[mapguide-commits] r6585 - in trunk/Installer: . Libraries/MapGuide
Web Extensions Libraries/MapGuide Web Extensions/Lang Support
Support/Paraffin Support/Paraffin/Properties
svn_mapguide at osgeo.org
svn_mapguide at osgeo.org
Sun Apr 22 08:47:10 EDT 2012
Author: jng
Date: 2012-04-22 05:47:10 -0700 (Sun, 22 Apr 2012)
New Revision: 6585
Added:
trunk/Installer/Features.xml
trunk/Installer/Paraffin.exe
trunk/Installer/Paraffin.pdb
trunk/Installer/Support/Paraffin/
trunk/Installer/Support/Paraffin/ArgParser.cs
trunk/Installer/Support/Paraffin/Constants.Designer.cs
trunk/Installer/Support/Paraffin/Constants.resx
trunk/Installer/Support/Paraffin/Features.xml
trunk/Installer/Support/Paraffin/GlobalSuppressions.cs
trunk/Installer/Support/Paraffin/Main.cs
trunk/Installer/Support/Paraffin/Paraffin.csproj
trunk/Installer/Support/Paraffin/Paraffin.sln
trunk/Installer/Support/Paraffin/ParaffinArgParser.cs
trunk/Installer/Support/Paraffin/Properties/
trunk/Installer/Support/Paraffin/Properties/AssemblyInfo.cs
trunk/Installer/Support/Paraffin/Wintellect.SNK
trunk/Installer/Support/Paraffin/WintellectDictionary.xml
Modified:
trunk/Installer/Libraries/MapGuide Web Extensions/Lang/MapGuideWebExtensions_en-US.wxl
trunk/Installer/Libraries/MapGuide Web Extensions/MapGuideWebExtensions.wxs
Log:
#1805: Make SVN metadata an optional install component. To do this we had to hack our own custom version of Paraffin to allow specifying a list of directories to look for. Wix components under these directories will be relocated to a ComponentGroup named <filename>_SVNMETADATA. A new top-level wix feature then includes all of these ComponentGroups. This submission includes the modified Paraffin source and executables
NOTE: Installing with the SVN metadata enabled will also include the .svn dirs for in-active components (because we're not tying svn metadata to their respective features, but to a single global feature). This is a small inconvenient price to pay.
Added: trunk/Installer/Features.xml
===================================================================
--- trunk/Installer/Features.xml (rev 0)
+++ trunk/Installer/Features.xml 2012-04-22 12:47:10 UTC (rev 6585)
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<FeatureMap>
+ <DirectorySearch Name=".svn" Suffix="_SVNMETADATA" />
+</FeatureMap>
\ No newline at end of file
Modified: trunk/Installer/Libraries/MapGuide Web Extensions/Lang/MapGuideWebExtensions_en-US.wxl
===================================================================
--- trunk/Installer/Libraries/MapGuide Web Extensions/Lang/MapGuideWebExtensions_en-US.wxl 2012-04-22 06:20:09 UTC (rev 6584)
+++ trunk/Installer/Libraries/MapGuide Web Extensions/Lang/MapGuideWebExtensions_en-US.wxl 2012-04-22 12:47:10 UTC (rev 6585)
@@ -46,6 +46,8 @@
<String Id="WebStdIconsFeature_Description">Icons for the AJAX viewer</String>
<String Id="WebTempFeature">Temp Directory</String>
<String Id="WebTempFeature_Description">You may choose a location where MapGuide will store temporary files.</String>
+ <String Id="SvnMetadataFeature">SVN Metadata</String>
+ <String Id="SvnMetadataFeature_Description">Includes SVN metadata for web application files allowing the user to pull down fixes and updates using a Subversion client</String>
<String Id="Shortcut_DevGuide">MapGuide Developer's Guide</String>
<String Id="Shortcut_WebAPI">Web API Documentation</String>
Modified: trunk/Installer/Libraries/MapGuide Web Extensions/MapGuideWebExtensions.wxs
===================================================================
--- trunk/Installer/Libraries/MapGuide Web Extensions/MapGuideWebExtensions.wxs 2012-04-22 06:20:09 UTC (rev 6584)
+++ trunk/Installer/Libraries/MapGuide Web Extensions/MapGuideWebExtensions.wxs 2012-04-22 12:47:10 UTC (rev 6585)
@@ -228,7 +228,25 @@
<ComponentGroupRef Id="group_MAPVIEWERSTDICONFILES" />
</Feature>
<FeatureRef Id="IISSetupFeature" />
+ <Feature Id="SvnMetadataFeature" Title="!(loc.SvnMetadataFeature)" Level="1" Description="!(loc.SvnMetadataFeature_Description)" AllowAdvertise="no" TypicalDefault="install" InstallDefault="local">
+ <ComponentGroupRef Id="incDotNetDevGuideFiles_SVNMETADATA" />
+ <ComponentGroupRef Id="incDotNetViewerSampleFiles_SVNMETADATA" />
+ <ComponentGroupRef Id="incFusionFiles_SVNMETADATA" />
+ <ComponentGroupRef Id="incHelpFiles_SVNMETADATA" />
+ <ComponentGroupRef Id="incJavaDevGuideFiles_SVNMETADATA" />
+ <ComponentGroupRef Id="incJavaViewerSampleFiles_SVNMETADATA" />
+ <ComponentGroupRef Id="incMapAgentFiles_SVNMETADATA" />
+ <ComponentGroupRef Id="incMapViewerAspxFiles_SVNMETADATA" />
+ <ComponentGroupRef Id="incMapViewerFiles_SVNMETADATA" />
+ <ComponentGroupRef Id="incMapViewerJspFiles_SVNMETADATA" />
+ <ComponentGroupRef Id="incMapViewerLocalizedFiles_SVNMETADATA" />
+ <ComponentGroupRef Id="incMapViewerMapAdminFiles_SVNMETADATA" />
+ <ComponentGroupRef Id="incMapViewerPhpFiles_SVNMETADATA" />
+ <ComponentGroupRef Id="incMapViewerSchemareportFiles_SVNMETADATA" />
+ <ComponentGroupRef Id="incMapViewerStdiconFiles_SVNMETADATA" />
+ <ComponentGroupRef Id="incPhpDevGuideFiles_SVNMETADATA" />
+ <ComponentGroupRef Id="incPhpViewerSampleFiles_SVNMETADATA" />
+ </Feature>
</Feature>
-
</Fragment>
</Wix>
Added: trunk/Installer/Paraffin.exe
===================================================================
(Binary files differ)
Property changes on: trunk/Installer/Paraffin.exe
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: trunk/Installer/Paraffin.pdb
===================================================================
(Binary files differ)
Property changes on: trunk/Installer/Paraffin.pdb
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Property changes on: trunk/Installer/Support/Paraffin
___________________________________________________________________
Added: bugtraq:number
+ true
Added: trunk/Installer/Support/Paraffin/ArgParser.cs
===================================================================
--- trunk/Installer/Support/Paraffin/ArgParser.cs (rev 0)
+++ trunk/Installer/Support/Paraffin/ArgParser.cs 2012-04-22 12:47:10 UTC (rev 6585)
@@ -0,0 +1,468 @@
+/*------------------------------------------------------------------------------
+ * Debugging Microsoft .NET 2.0 Applications
+ * Copyright © 1997-2006 John Robbins -- All rights reserved.
+ -----------------------------------------------------------------------------*/
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+using System.Diagnostics.CodeAnalysis;
+
+namespace Wintellect.Paraffin
+{
+ /// <summary>
+ /// A command line argument parsing class.
+ /// </summary>
+ /// <remarks>
+ /// This class is based on the WordCount version from the Framework SDK
+ /// samples. Any errors are mine.
+ /// <para>
+ /// There are two arrays of flags you'll pass to the constructors. The
+ /// flagSymbols are supposed to be standalone switches that toggle an option
+ /// on. The dataSymbols are for switches that take data values. For
+ /// example, if your application needs a switch, -c, to set the count,
+ /// you'd put "c" in the dataSymbols. Note that you can pass null/Nothing
+ /// for dataSymbols if you don't need them.
+ /// </para>
+ /// </remarks>
+ internal abstract class ArgParser
+ {
+ // For example: "/", "-"
+ private String [] switchChars;
+ // Switch character(s) that are simple flags
+ private String [] flagSymbols;
+ // Switch characters(s) that take parameters. For example: -f <file>.
+ // This can be null if not needed.
+ private String [] dataSymbols;
+ // Are switches case-sensitive?
+ private Boolean caseSensitiveSwitches;
+
+
+ /// <summary>
+ /// The status values for various internal methods.
+ /// </summary>
+ protected enum SwitchStatus
+ {
+ /// <summary>
+ /// Success.
+ /// </summary>
+ NoError ,
+ /// <summary>
+ /// There was a problem.
+ /// </summary>
+ Error ,
+ /// <summary>
+ /// Show the usage help.
+ /// </summary>
+ ShowUsage
+ } ;
+
+ ///// <summary>
+ ///// Constructs the class with nothing but flag switches and defaults to
+ ///// "/" and "-" as valid switch characters.
+ ///// </summary>
+ ///// <param name="flagSymbols">
+ ///// The array of simple flags to toggle options on or off.
+ ///// </param>
+ //protected ArgParser ( String [] flagSymbols )
+ // : this ( flagSymbols ,
+ // null ,
+ // false ,
+ // new string [] { "/" , "-" } )
+ //{
+ //}
+
+ ///// <summary>
+ ///// Constructs the class with nothing but flag switches and defaults to
+ ///// "/" and "-" as valid switch characters.
+ ///// </summary>
+ ///// <param name="flagSymbols">
+ ///// The array of simple flags to toggle options on or off.
+ ///// </param>
+ ///// <param name="caseSensitiveSwitches">
+ ///// True if case sensitive switches are supposed to be used.
+ ///// </param>
+ //protected ArgParser ( String [] flagSymbols ,
+ // Boolean caseSensitiveSwitches )
+ // : this ( flagSymbols ,
+ // null ,
+ // caseSensitiveSwitches ,
+ // new string [] { "/" , "-" } )
+ //{
+ //}
+
+ ///// <summary>
+ ///// Constructs the class to use case-insensitive switches and
+ ///// defaults to "/" and "-" as valid switch characters.
+ ///// </summary>
+ ///// <param name="flagSymbols">
+ ///// The array of simple flags to toggle options on or off.
+ ///// </param>
+ ///// <param name="dataSymbols">
+ ///// The array of options that need data either in the next parameter or
+ ///// after the switch itself. This value can be null/Nothing.
+ ///// </param>
+ //protected ArgParser ( String [] flagSymbols , String [] dataSymbols )
+ // : this ( flagSymbols ,
+ // dataSymbols ,
+ // false ,
+ // new string [] { "/" , "-" } )
+ //{
+ //}
+
+ ///// <summary>
+ ///// Constructs the class and defaults to "/" and "-" as the only
+ ///// valid switch characters
+ ///// </summary>
+ ///// <param name="flagSymbols">
+ ///// The array of simple flags to toggle options on or off.
+ ///// </param>
+ ///// <param name="dataSymbols">
+ ///// The array of options that need data either in the next parameter or
+ ///// after the switch itself. This value can be null/Nothing.
+ ///// </param>
+ ///// <param name="caseSensitiveSwitches">
+ ///// True if case sensitive switches are supposed to be used.
+ ///// </param>
+ protected ArgParser ( String [] flagSymbols ,
+ String [] dataSymbols ,
+ Boolean caseSensitiveSwitches )
+ : this ( flagSymbols ,
+ dataSymbols ,
+ caseSensitiveSwitches ,
+ new string [] { "/" , "-" } )
+ {
+ }
+
+
+ /// <summary>
+ /// Constructor where the caller sets all options to the class.
+ /// </summary>
+ /// <param name="flagSymbols">
+ /// The array of simple flags to toggle options on or off.
+ /// </param>
+ /// <param name="dataSymbols">
+ /// The array of options that need data either in the next parameter or
+ /// after the switch itself. This value can be null/Nothing.
+ /// </param>
+ /// <param name="caseSensitiveSwitches">
+ /// True if case sensitive switches are supposed to be used.
+ /// </param>
+ /// <param name="switchChars">
+ /// The array of switch characters to use.
+ /// </param>
+ /// <exception cref="ArgumentException">
+ /// Thrown if <paramref name="flagSymbols"/> or
+ /// <paramref name="switchChars"/> are invalid.
+ /// </exception>
+ protected ArgParser ( String [] flagSymbols ,
+ String [] dataSymbols ,
+ Boolean caseSensitiveSwitches ,
+ String [] switchChars )
+ {
+ Debug.Assert ( null != flagSymbols , "null != flagSymbols" );
+ // Avoid assertion side effects in debug builds.
+#if DEBUG
+ if ( null != flagSymbols )
+ {
+ Debug.Assert ( flagSymbols.Length > 0 ,
+ "flagSymbols.Length > 0" );
+ }
+#endif
+ if ( ( null == flagSymbols ) || ( 0 == flagSymbols.Length ) )
+ {
+ throw new ArgumentException ( Constants.ArrayMustBeValid ,
+ "flagSymbols" );
+ }
+ Debug.Assert ( null != switchChars , "null != switchChars" );
+ // Avoid assertion side effects in debug builds.
+#if DEBUG
+ if ( null != switchChars )
+ {
+ Debug.Assert ( switchChars.Length > 0 ,
+ "switchChars.Length > 0" );
+ }
+#endif
+ if ( ( null == switchChars ) || ( 0 == switchChars.Length ) )
+ {
+ throw new ArgumentException ( Constants.ArrayMustBeValid ,
+ "switchChars" );
+ }
+
+ this.flagSymbols = flagSymbols;
+ this.dataSymbols = dataSymbols;
+ this.caseSensitiveSwitches = caseSensitiveSwitches;
+ this.switchChars = switchChars;
+ }
+
+ /// <summary>
+ /// Reports correct command line usage.
+ /// </summary>
+ /// <param name="errorInfo">
+ /// The string with the invalid command line option.
+ /// </param>
+ public abstract void OnUsage ( String errorInfo );
+
+
+ // Every derived class must implement an OnSwitch method or a switch is
+ // considered an error.
+ /// <summary>
+ /// Called when a switch is parsed out.
+ /// </summary>
+ /// <param name="switchSymbol">
+ /// The switch value parsed out.
+ /// </param>
+ /// <param name="switchValue">
+ /// The value of the switch. For flag switches this is null/Nothing.
+ /// </param>
+ /// <returns>
+ /// One of the <see cref="SwitchStatus"/> values.
+ /// </returns>
+ protected virtual SwitchStatus OnSwitch ( String switchSymbol ,
+ String switchValue )
+ {
+ return ( SwitchStatus.Error );
+ }
+
+ /// <summary>
+ /// Called when a non-switch value is parsed out.
+ /// </summary>
+ /// <param name="value">
+ /// The value parsed out.
+ /// </param>
+ /// <returns>
+ /// One of the <see cref="SwitchStatus"/> values.
+ /// </returns>
+ protected virtual SwitchStatus OnNonSwitch ( String value )
+ {
+ return ( SwitchStatus.Error );
+ }
+
+ /// <summary>
+ /// Called when parsing is finished so final sanity checking can be
+ /// performed.
+ /// </summary>
+ /// <returns>
+ /// One of the <see cref="SwitchStatus"/> values.
+ /// </returns>
+ protected virtual SwitchStatus OnDoneParse ( )
+ {
+ // By default, we'll assume that all parsing was an error.
+ return ( SwitchStatus.Error );
+ }
+
+ ///// <summary>
+ ///// Parses the application's command-line arguments.
+ ///// </summary>
+ ///// <returns>
+ ///// True if the parsing succeeded.
+ ///// </returns>
+ //public Boolean Parse ( )
+ //{
+ // // Visual Basic will use this method since its entry-point function
+ // // doesn't get the command-line arguments passed to it.
+ // return ( Parse ( Environment.GetCommandLineArgs ( ) ) );
+ //}
+
+ // Looks to see if the switch is in the array.
+ private int IsSwitchInArray ( String [] switchArray ,
+ String value )
+ {
+ String valueCompare = value;
+ if ( true == caseSensitiveSwitches )
+ {
+ valueCompare = value.ToUpperInvariant ( );
+ }
+ int retValue = -1;
+ for ( int n = 0 ; n < switchArray.Length ; n++ )
+ {
+ String currSwitch = switchArray [ n ];
+ if ( true == caseSensitiveSwitches )
+ {
+ currSwitch = currSwitch.ToUpperInvariant ( );
+ }
+ if ( 0 == String.CompareOrdinal ( valueCompare ,
+ currSwitch ) )
+ {
+ retValue = n;
+ break;
+ }
+ }
+ return ( retValue );
+ }
+
+ /// <summary>
+ /// Looks to see if this string starts with a switch character.
+ /// </summary>
+ /// <param name="value">
+ /// The string to check.
+ /// </param>
+ /// <returns>
+ /// True if the string starts with a switch character.
+ /// </returns>
+ private Boolean StartsWithSwitchChar ( String value )
+ {
+ Boolean isSwitch = false;
+ for ( int n = 0 ; !isSwitch && ( n < switchChars.Length ) ; n++ )
+ {
+ if ( 0 == String.CompareOrdinal ( value ,
+ 0 ,
+ switchChars [ n ] ,
+ 0 ,
+ 1 ) )
+ {
+ isSwitch = true;
+ break;
+ }
+ }
+ return ( isSwitch );
+ }
+
+ /// <summary>
+ /// Parses an arbitrary set of arguments.
+ /// </summary>
+ /// <param name="args">
+ /// The string array to parse through.
+ /// </param>
+ /// <returns>
+ /// True if parsing was correct.
+ /// </returns>
+ /// <exception cref="ArgumentException">
+ /// Thrown if <paramref name="args"/> is null or empty.
+ /// </exception>
+ [SuppressMessage ( "Microsoft.Globalization" ,
+ "CA1308:NormalizeStringsToUppercase" ,
+ Justification = "I NEED TO FIX THIS!" )]
+ public Boolean Parse ( String [] args )
+ {
+ Debug.Assert ( null != args , "null != args" );
+ // Avoid side effects in debug builds.
+#if DEBUG
+ if ( null != args )
+ {
+ Debug.Assert ( args.Length > 0 , "args.Length > 0" );
+ }
+#endif
+ if ( ( null == args ) || ( args.Length == 0 ) )
+ {
+ throw new ArgumentException ( Constants.InvalidParameter );
+ }
+ // Assume parsing is successful.
+ SwitchStatus ss = SwitchStatus.NoError;
+
+ int errorArg = -1;
+ int currArg;
+ for ( currArg = 0 ;
+ ( ss == SwitchStatus.NoError ) && ( currArg < args.Length ) ;
+ currArg++ )
+ {
+ errorArg = currArg;
+ // Determine if this argument starts with a valid switch
+ // character
+ Boolean isSwitch = StartsWithSwitchChar ( args [ currArg ] );
+ if ( true == isSwitch )
+ {
+ // Indicates the symbol is a data symbol.
+ Boolean useDataSymbols = false;
+ // Get the argument itself.
+ String processedArg = args [ currArg ].Substring ( 1 );
+ // The index into the symbol array.
+ int n;
+ // First check the flags array.
+ n = IsSwitchInArray ( flagSymbols , processedArg );
+ // If it's not in the flags array, try the data array if that
+ // array is not null.
+ if ( ( -1 == n ) && ( null != dataSymbols ) )
+ {
+ n = IsSwitchInArray ( dataSymbols , processedArg );
+ useDataSymbols = true;
+ }
+ if ( -1 != n )
+ {
+ String theSwitch = null;
+ String dataValue = null;
+ // If it's a flag switch.
+ if ( false == useDataSymbols )
+ {
+ // This is a legal switch, notified the derived
+ // class of this switch and its value.
+ theSwitch = flagSymbols [ n ];
+ if ( caseSensitiveSwitches )
+ {
+ theSwitch = flagSymbols [ n ].
+ ToLowerInvariant ( );
+ }
+ }
+ else
+ {
+ theSwitch = dataSymbols [ n ];
+ // Look at the next parameter if it's there.
+ if ( currArg + 1 < args.Length )
+ {
+ currArg++;
+ dataValue = args [ currArg ];
+ // Take a look at dataValue to see if it starts
+ // with a switch character. If it does, that
+ // means this data argument is empty.
+ if ( true == StartsWithSwitchChar (
+ dataValue ) )
+ {
+ ss = SwitchStatus.Error;
+ break;
+ }
+ }
+ else
+ {
+ ss = SwitchStatus.Error;
+ break;
+ }
+ }
+ ss = OnSwitch ( theSwitch , dataValue );
+ }
+ else
+ {
+ ss = SwitchStatus.Error;
+ break;
+ }
+ }
+ else
+ {
+ // This is not a switch, notified the derived class of this
+ // "non-switch value"
+ ss = OnNonSwitch ( args [ currArg ] );
+ }
+ }
+
+ // Finished parsing arguments
+ if ( ss == SwitchStatus.NoError )
+ {
+ // No error occurred while parsing, let derived class perform a
+ // sanity check and return an appropriate status
+ ss = OnDoneParse ( );
+ }
+
+ if ( ss == SwitchStatus.ShowUsage )
+ {
+ // Status indicates that usage should be shown, show it
+ OnUsage ( null );
+ }
+
+ if ( ss == SwitchStatus.Error )
+ {
+ String errorValue = null;
+ if ( ( errorArg != -1 ) && ( errorArg != args.Length ) )
+ {
+ errorValue = args [ errorArg ];
+ }
+ // Status indicates that an error occurred, show it and the
+ // proper usage
+ OnUsage ( errorValue );
+ }
+
+ // Return whether all parsing was successful.
+ return ( ss == SwitchStatus.NoError );
+ }
+ }
+}
\ No newline at end of file
Added: trunk/Installer/Support/Paraffin/Constants.Designer.cs
===================================================================
--- trunk/Installer/Support/Paraffin/Constants.Designer.cs (rev 0)
+++ trunk/Installer/Support/Paraffin/Constants.Designer.cs 2012-04-22 12:47:10 UTC (rev 6585)
@@ -0,0 +1,309 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.3053
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Wintellect.Paraffin {
+ using System;
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Constants {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Constants() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Wintellect.Paraffin.Constants", typeof(Constants).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Only one -alias switch at a time is supported..
+ /// </summary>
+ internal static string AliasMultipleSwitches {
+ get {
+ return ResourceManager.GetString("AliasMultipleSwitches", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The array must not be null or of zero length..
+ /// </summary>
+ internal static string ArrayMustBeValid {
+ get {
+ return ResourceManager.GetString("ArrayMustBeValid", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Autogenerated by Paraffin - Wintellect - John Robbins - john at wintellect.com.
+ /// </summary>
+ internal static string CommentProducer {
+ get {
+ return ResourceManager.GetString("CommentProducer", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Manual changes to this file may cause incorrect behavior..
+ /// </summary>
+ internal static string CommentWarning {
+ get {
+ return ResourceManager.GetString("CommentWarning", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The -directory switch must always be specified..
+ /// </summary>
+ internal static string DirectoryCannotBeEmpty {
+ get {
+ return ResourceManager.GetString("DirectoryCannotBeEmpty", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The -directory specified path does not exist..
+ /// </summary>
+ internal static string DirectoryDoesNotExist {
+ get {
+ return ResourceManager.GetString("DirectoryDoesNotExist", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Only one -directory switch at a time is supported..
+ /// </summary>
+ internal static string DirectoryMultipleSwitches {
+ get {
+ return ResourceManager.GetString("DirectoryMultipleSwitches", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Only one -dirref switch at a time is supported..
+ /// </summary>
+ internal static string DirectoryRefMultipleSwitches {
+ get {
+ return ResourceManager.GetString("DirectoryRefMultipleSwitches", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Error on the '{0}' switch..
+ /// </summary>
+ internal static string ErrorSwitch {
+ get {
+ return ResourceManager.GetString("ErrorSwitch", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Extension values cannot be empty..
+ /// </summary>
+ internal static string ExtensionCannotBeEmpty {
+ get {
+ return ResourceManager.GetString("ExtensionCannotBeEmpty", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Only one increment switch at a time is supported..
+ /// </summary>
+ internal static string IncrementMultipleSwitches {
+ get {
+ return ResourceManager.GetString("IncrementMultipleSwitches", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The increment value does not appear to be an integer..
+ /// </summary>
+ internal static string IncrementNoParse {
+ get {
+ return ResourceManager.GetString("IncrementNoParse", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The increment value must be greater than zero..
+ /// </summary>
+ internal static string IncrementNotZero {
+ get {
+ return ResourceManager.GetString("IncrementNotZero", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to A call into Windows failed unexpectedly..
+ /// </summary>
+ internal static string InteropCallFailed {
+ get {
+ return ResourceManager.GetString("InteropCallFailed", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to There appears to be multiple nodes in input .WXS file with the same file name in the same directory: {0}..
+ /// </summary>
+ internal static string InvalidFileNameCountFmt {
+ get {
+ return ResourceManager.GetString("InvalidFileNameCountFmt", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to An invalid parameter was passed to the method..
+ /// </summary>
+ internal static string InvalidParameter {
+ get {
+ return ResourceManager.GetString("InvalidParameter", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Update and creation command line options are mutually excusive..
+ /// </summary>
+ internal static string MutuallyExclusiveOptions {
+ get {
+ return ResourceManager.GetString("MutuallyExclusiveOptions", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Only one output or processing file can be specified..
+ /// </summary>
+ internal static string OutputAlreadySpecified {
+ get {
+ return ResourceManager.GetString("OutputAlreadySpecified", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to You must specify the .WXS file to write to or process..
+ /// </summary>
+ internal static string OutputCannotBeEmpty {
+ get {
+ return ResourceManager.GetString("OutputCannotBeEmpty", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The -unique value cannot be empty..
+ /// </summary>
+ internal static string UniqueCannotBeEmpty {
+ get {
+ return ResourceManager.GetString("UniqueCannotBeEmpty", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Only one -unique switch at a time is supported..
+ /// </summary>
+ internal static string UniqueMultipleSwitches {
+ get {
+ return ResourceManager.GetString("UniqueMultipleSwitches", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The -unique string value cannot be longer than 65 characters..
+ /// </summary>
+ internal static string UniqueTooLong {
+ get {
+ return ResourceManager.GetString("UniqueTooLong", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Unknown command line option..
+ /// </summary>
+ internal static string UnknownCommandLineOption {
+ get {
+ return ResourceManager.GetString("UnknownCommandLineOption", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The file to process does no appear to have been created with Paraffin. The comment node is missing..
+ /// </summary>
+ internal static string UnknownFileType {
+ get {
+ return ResourceManager.GetString("UnknownFileType", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The file to update does not exist..
+ /// </summary>
+ internal static string UpdateFileMustExist {
+ get {
+ return ResourceManager.GetString("UpdateFileMustExist", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Paraffin {0}
+ ///(c) 2007-2008, John Robbins - john at wintellect.com
+ ///A better Tallow for generating Windows Installer XML (WiX) 3.0 fragments.
+ ///
+ ///Usage:
+ /// Paraffin (-dir <dir> -custom <value> <file>
+ /// [-alias <alias> -ext <ext>* | -dirref <DirectoryRef> |
+ /// -direXclude <exdir>* | -inc # |
+ /// -guids |-multiple | -norecurse | -Win64] ) |
+ /// (-update <file> [-ext <ext>*])
+ ///
+ ///Required parameters to create a new fragment:
+ /// -dir <dir> - The direc [rest of string was truncated]";.
+ /// </summary>
+ internal static string UsageString {
+ get {
+ return ResourceManager.GetString("UsageString", resourceCulture);
+ }
+ }
+ }
+}
Added: trunk/Installer/Support/Paraffin/Constants.resx
===================================================================
--- trunk/Installer/Support/Paraffin/Constants.resx (rev 0)
+++ trunk/Installer/Support/Paraffin/Constants.resx 2012-04-22 12:47:10 UTC (rev 6585)
@@ -0,0 +1,256 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <data name="AliasMultipleSwitches" xml:space="preserve">
+ <value>Only one -alias switch at a time is supported.</value>
+ </data>
+ <data name="ArrayMustBeValid" xml:space="preserve">
+ <value>The array must not be null or of zero length.</value>
+ </data>
+ <data name="CommentProducer" xml:space="preserve">
+ <value>Autogenerated by Paraffin - Wintellect - John Robbins - john at wintellect.com</value>
+ </data>
+ <data name="CommentWarning" xml:space="preserve">
+ <value>Manual changes to this file may cause incorrect behavior.</value>
+ </data>
+ <data name="DirectoryCannotBeEmpty" xml:space="preserve">
+ <value>The -directory switch must always be specified.</value>
+ </data>
+ <data name="DirectoryDoesNotExist" xml:space="preserve">
+ <value>The -directory specified path does not exist.</value>
+ </data>
+ <data name="DirectoryMultipleSwitches" xml:space="preserve">
+ <value>Only one -directory switch at a time is supported.</value>
+ </data>
+ <data name="DirectoryRefMultipleSwitches" xml:space="preserve">
+ <value>Only one -dirref switch at a time is supported.</value>
+ </data>
+ <data name="ErrorSwitch" xml:space="preserve">
+ <value>Error on the '{0}' switch.</value>
+ </data>
+ <data name="ExtensionCannotBeEmpty" xml:space="preserve">
+ <value>Extension values cannot be empty.</value>
+ </data>
+ <data name="IncrementMultipleSwitches" xml:space="preserve">
+ <value>Only one increment switch at a time is supported.</value>
+ </data>
+ <data name="IncrementNoParse" xml:space="preserve">
+ <value>The increment value does not appear to be an integer.</value>
+ </data>
+ <data name="IncrementNotZero" xml:space="preserve">
+ <value>The increment value must be greater than zero.</value>
+ </data>
+ <data name="InteropCallFailed" xml:space="preserve">
+ <value>A call into Windows failed unexpectedly.</value>
+ </data>
+ <data name="InvalidFileNameCountFmt" xml:space="preserve">
+ <value>There appears to be multiple nodes in input .WXS file with the same file name in the same directory: {0}.</value>
+ </data>
+ <data name="InvalidParameter" xml:space="preserve">
+ <value>An invalid parameter was passed to the method.</value>
+ </data>
+ <data name="MutuallyExclusiveOptions" xml:space="preserve">
+ <value>Update and creation command line options are mutually excusive.</value>
+ </data>
+ <data name="OutputAlreadySpecified" xml:space="preserve">
+ <value>Only one output or processing file can be specified.</value>
+ </data>
+ <data name="OutputCannotBeEmpty" xml:space="preserve">
+ <value>You must specify the .WXS file to write to or process.</value>
+ </data>
+ <data name="UniqueCannotBeEmpty" xml:space="preserve">
+ <value>The -unique value cannot be empty.</value>
+ </data>
+ <data name="UniqueMultipleSwitches" xml:space="preserve">
+ <value>Only one -unique switch at a time is supported.</value>
+ </data>
+ <data name="UniqueTooLong" xml:space="preserve">
+ <value>The -unique string value cannot be longer than 65 characters.</value>
+ </data>
+ <data name="UnknownCommandLineOption" xml:space="preserve">
+ <value>Unknown command line option.</value>
+ </data>
+ <data name="UnknownFileType" xml:space="preserve">
+ <value>The file to process does no appear to have been created with Paraffin. The comment node is missing.</value>
+ </data>
+ <data name="UpdateFileMustExist" xml:space="preserve">
+ <value>The file to update does not exist.</value>
+ </data>
+ <data name="UsageString" xml:space="preserve">
+ <value>Paraffin {0}
+(c) 2007-2008, John Robbins - john at wintellect.com
+A better Tallow for generating Windows Installer XML (WiX) 3.0 fragments.
+
+Usage:
+ Paraffin (-dir <dir> -custom <value> <file>
+ [-alias <alias> -ext <ext>* | -dirref <DirectoryRef> |
+ -direXclude <exdir>* | -inc # |
+ -guids |-multiple | -norecurse | -Win64] ) |
+ (-update <file> [-ext <ext>*])
+
+Required parameters to create a new fragment:
+ -dir <dir> - The directory to recurse and build the fragment
+ from. (short: -d)
+ -custom <value> - The unique value to apply to all generated
+ components, and files. Note all invalid id
+ characters converted to underscores. (short: -c)
+ <file> - The .WXS output file.
+
+Optional parameters when creating a new fragment:
+ -alias <alias> - The alias to replace the base directory in the
+ File element's src attribute. The default is to
+ put the full hard coded path. (short: -a)
+ -ext <ext> - File extensions to exclude. Specify as many -ext
+ options as necessary. (short: -e)
+ -direXclude <exdir> - Directories to exclude. There is no wildcard
+ matching, only string contains matching. Specify
+ as many -direXclude options as necessary.
+ (short: -x)
+ -dirref <DirectoryRef> - Override the default <DirectoryRef> Id
+ attribute. Default: INSTALLDIR (short: -dr)
+ -inc # - The number to add to each directory and component
+ elements to allow space for additional items
+ later. (short: -i)
+ -guids - Generate GUID values for all components.
+ (short: -g)
+ -multiple - Multiple files per component. Defaults to one
+ file per component. (short: -m)
+ -norecurse - Do not recurse directories. Defaults to recursing
+ all directories under <dir>. (short: -nr)
+ -Win64 - If specified, adds Win64="yes" to all components.
+
+Required parameters to update a previously created file:
+ -update - Indicates you want to update an existing .WXS file
+ that was created by Paraffin.
+ <file> - The .WXS file to process. The updated output is
+ written to <file>.PARAFFIN.
+
+Optional parameters when updating a previously created file:
+ -ext <ext > - File extensions to exclude. Specify as many -ext
+ options as necessary. Additional ignore extensions
+ are added to those already specified when the file
+ was initially created. (short: -e)
+ -direXclude <exdir> - Directories to exclude. There is no wildcard
+ matching, only string contains matching. Specify
+ as many -direXclude options as necessary.
+ Additional exclude directories are added to those
+ already specified when the file was initially
+ created. (short: -x)</value>
+ </data>
+</root>
\ No newline at end of file
Added: trunk/Installer/Support/Paraffin/Features.xml
===================================================================
--- trunk/Installer/Support/Paraffin/Features.xml (rev 0)
+++ trunk/Installer/Support/Paraffin/Features.xml 2012-04-22 12:47:10 UTC (rev 6585)
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<FeatureMap>
+ <DirectorySearch Name=".svn" Suffix="_SVNMETADATA" />
+</FeatureMap>
\ No newline at end of file
Added: trunk/Installer/Support/Paraffin/GlobalSuppressions.cs
===================================================================
--- trunk/Installer/Support/Paraffin/GlobalSuppressions.cs (rev 0)
+++ trunk/Installer/Support/Paraffin/GlobalSuppressions.cs 2012-04-22 12:47:10 UTC (rev 6585)
@@ -0,0 +1,9 @@
+// This file is used by Code Analysis to maintain SuppressMessage
+// attributes that are applied to this project. Project-level
+// suppressions either have no target or are given a specific target
+// and scoped to a namespace, type, member, etc.
+//
+// To add a suppression to this file, right-click the message in the
+// Error List, point to "Suppress Message(s)", and click "In Project
+// Suppression File". You do not need to add suppressions to this
+// file manually.
Added: trunk/Installer/Support/Paraffin/Main.cs
===================================================================
--- trunk/Installer/Support/Paraffin/Main.cs (rev 0)
+++ trunk/Installer/Support/Paraffin/Main.cs 2012-04-22 12:47:10 UTC (rev 6585)
@@ -0,0 +1,1386 @@
+//------------------------------------------------------------------------------
+// <copyright company="Wintellect">
+// Copyright (c) John Robbins/Wintellect -- All rights reserved.
+// </copyright>
+// <Project>
+// Wintellect Debugging .NET Code
+// </Project>
+//------------------------------------------------------------------------------
+/*------------------------------------------------------------------------------
+ * See the following blog entries for more information about PARAFFIN:
+ *
+ * http://www.wintellect.com/cs/blogs/jrobbins/archive/2007/10/18/wix-hints-for-new-users-part-1-of-3.aspx
+ * http://www.wintellect.com/cs/blogs/jrobbins/archive/2007/10/19/wix-the-pain-of-wix-part-2-of-3.aspx
+ * http://www.wintellect.com/cs/blogs/jrobbins/archive/2007/10/21/wix-a-better-tallow-paraffin.aspx
+ *
+ * 1.00 - Initial release
+ * 1.01 - Fixed a bug where directory and component names could have a dash in
+ * them, which is not supported by WiX.
+ * 1.02 - Special thanks to Darren Stone for all his input about PARAFFIN.
+ * - Added -Win64 switch, which adds Win64="yes" to all components.
+ * - Updated the Id naming to keep all values in the range [0-9a-zA-Z_] to
+ * avoid any naming problems. WiX is not consistent on exactly what can
+ * characters can be in the Id attribute.
+ * - When updating, I was previously only relying on the Directory and
+ * File elements Name attribute to find those elements. I mistakenly
+ * thought the short file/directory name was guaranteed to be unique.
+ * I fixed this bug by updating the Directory element searching to look
+ * for either the matching Name attribute or LongName attribute depending
+ * if the long name is different than the short name. For File elements,
+ * I look at both the Name and the Source attributes for the exact match.
+ * - Fixed a bug where I wasn't properly matching directory names when
+ * generating the Id attribute.
+ * - Fixed the innocuous bug where I was appending a double slash on an
+ * alias if the input directory did not end in a trailing slash.
+ * 1.03 - Fixed a bug where I was assuming that the short name for a file was
+ * constant. It's really a random value. Now I only look at the Source
+ * attribute when updating a File node as there's no other way to ensure
+ * that a file is the same. This means I might have a rare conflict with
+ * the short name for a file. The big reason for upgrading to WiX 3.0 is
+ * that you no longer need to mess with these darn short names!
+ * 1.04 - Thanks to Matthew Goos, added the -dirref option to allow a custom
+ * name for the DirectoryRef node when creating a file.
+ * - Now the -ext and direXclude command line options can also be specified
+ * for updates in order to add additional extensions or directories to
+ * ignore when updating a file.
+ * 3.00 - Sorry for the big version jump but Paraffin now targets WiX 3.0 so I
+ * thought I'd make them the same. Now that WiX 3.0 has hit beta, it's
+ * time to support it. Note that this version no longer will create files
+ * for use with WiX 2.0. However, it will import and convert previously
+ * created Paraffin files to WiX 3.0.
+ * Yay! No more short filenames!
+ * - When adding files, I now check if they are .DLL, .EXE, or .OCX and if
+ * so, add CheckSum='yes' attribute to the File element.
+ * - All command line switches are now case insensitive. I'd forgotten to
+ * set that in a prior version.
+ -----------------------------------------------------------------------------*/
+namespace Wintellect.Paraffin
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using System.IO;
+ using System.Xml.Linq;
+ using System.Runtime.InteropServices;
+ using System.Globalization;
+ using System.Diagnostics;
+ using System.Collections;
+ using System.Text.RegularExpressions;
+
+ /// <summary>
+ /// The main program.
+ /// </summary>
+ internal class Program
+ {
+ #region Comment Options Elements
+ // All the elements for the data stored in the comment.
+ private const String CMDLINEOPTIONSELEM = "CommandLineOptions";
+ private const String PRODUCEDBYELEM = "Producer";
+ private const String WARNINGELEM = "WARNING";
+ private const String DATECREATE = "CreatedOn";
+ private const String DIRECTORYELEM = "Directory";
+ private const String CUSTOMELEM = "Custom";
+ private const String ALIASELEM = "DirAlias";
+ private const String INCREMENTELEM = "Increment";
+ private const String GUIDSELEM = "Guids";
+ private const String MULTIPLEELEM = "Multiple";
+ private const String NORECURSELEM = "Norecurse";
+ private const String WIN64ELEM = "Win64";
+ private const String EXTEXCLUDEELEM = "ExtensionExcludes";
+ private const String EXTELEM = "Ext";
+ private const String DIREEXCLUDEELEM = "DirExcludes";
+ private const String DIREXT = "Dir";
+ private const String NEXTDIRECTORYNUMELEM = "NextDirectoryNumber";
+ private const String NEXTCOMPONENTNUMBER = "NextComponentNumber";
+ #endregion
+
+ // The WiX 3.0 namespace.
+ private static XNamespace nsWiX3 =
+ "http://schemas.microsoft.com/wix/2006/wi";
+ private static XNamespace nsWiX2 =
+ "http://schemas.microsoft.com/wix/2003/01/wi";
+
+ // The argument values used across all the methods.
+ private static ParaffinArgParser argValues;
+
+ // The current directory number.
+ private static Int32 directoryNumber;
+
+ // The starting directory name. I use this to build up unique
+ // Directory Id values.
+ private static String baseDirectoryName;
+
+ // The full starting directory. If the user wants aliases, I'll replace
+ // this with the alias.
+ private static String fullStartDirectory;
+
+ // The current component number
+ private static Int32 componentNumber;
+
+ // The error message.
+ private static String errorMessage;
+
+ // The input file namespace.
+ private static XNamespace inputNameSpace = nsWiX3;
+
+ // The PE file extensions.
+ private static String [] peFileExtension = { ".DLL" , ".EXE" , ".OCX" };
+
+ internal static Int32 Main ( string [] args )
+ {
+ LoadProcessFeatureMap();
+
+ directoryNumber = 0;
+ componentNumber = 0;
+ errorMessage = String.Empty;
+
+ // Think positive that everything will run completely.
+ Int32 returnValue = 0;
+ argValues = new ParaffinArgParser ( );
+ if ( args.Length > 0 )
+ {
+ Boolean parsed = argValues.Parse ( args );
+ if ( true == parsed )
+ {
+ if ( true == argValues.Update )
+ {
+ returnValue = UpdateExistingFile ( );
+ }
+ else
+ {
+ returnValue = CreateNewFile ( );
+ }
+ }
+ }
+ else
+ {
+ argValues.OnUsage ( String.Empty );
+ returnValue = 1;
+ }
+
+ if ( false == String.IsNullOrEmpty ( errorMessage ) )
+ {
+ Console.WriteLine ( errorMessage );
+ }
+
+ return ( returnValue );
+ }
+
+ /// <summary>
+ /// Creates a brand new .WXS file for the specified directory and
+ /// options. Any previous file of this name is overwritten.
+ /// </summary>
+ /// <returns>
+ /// Zero if the file was all properly written.
+ /// </returns>
+ private static int CreateNewFile ( )
+ {
+ // Create the XML document.
+ XDocument doc = new XDocument ( );
+
+ // Add the WiX and Fragment nodes.
+ XElement root = new XElement ( nsWiX3 + "Wix" );
+ doc.Add ( root );
+ XElement fragment = new XElement ( nsWiX3 + "Fragment" );
+ root.Add ( fragment );
+
+ // Add the DirectoryRef node.
+ XElement directoryRef;
+ if ( true == String.IsNullOrEmpty ( argValues.DirectoryRef ) )
+ {
+ directoryRef = new XElement ( nsWiX3 + "DirectoryRef" ,
+ new XAttribute ( "Id" ,
+ "INSTALLDIR" ) );
+ }
+ else
+ {
+ directoryRef = new XElement ( nsWiX3 + "DirectoryRef" ,
+ new XAttribute ( "Id" ,
+ argValues.DirectoryRef ) );
+ }
+
+ fragment.Add ( directoryRef );
+
+ // Get the starting directories initialized.
+ InitializeDirectoryValues ( );
+
+ // Now start the grind.
+ RecurseDirectoriesForNewFile ( directoryRef , fullStartDirectory );
+
+ // Add the Component group node.
+ AddComponentGroup ( fragment );
+
+ // Add the comment with all the command line options.
+ AddCommandLineOptionsComment ( root );
+
+ ProcessFeatureMap(doc, Path.GetFileNameWithoutExtension(argValues.FileName) );
+
+ // We're done, save it!
+ doc.Save ( argValues.FileName );
+ return ( 0 );
+ }
+
+ private static Dictionary<string, string> _featureMap = new Dictionary<string, string>();
+
+ private static void LoadProcessFeatureMap()
+ {
+ if (File.Exists("Features.xml"))
+ {
+ var doc = XDocument.Load("Features.xml");
+ var mappings = from item in doc.Descendants("DirectorySearch")
+ select new
+ {
+ Name = item.Attribute("Name").Value,
+ Suffix = item.Attribute("Suffix").Value
+ };
+ foreach (var m in mappings)
+ _featureMap[m.Name] = m.Suffix;
+ }
+ }
+
+ /// <summary>
+ /// Performs a search through the given XDocument for Directory fragments
+ /// whose name matches the specified items in the FeatureMap, for each matching
+ /// directory, all of its child elements will be assigned to the specified feature
+ /// </summary>
+ /// <param name="doc"></param>
+ private static void ProcessFeatureMap(XDocument doc, string name)
+ {
+ Dictionary<string, HashSet<string>> componentMaps = new Dictionary<string, HashSet<string>>();
+
+ foreach (var dirName in _featureMap.Keys)
+ {
+ var suffix = _featureMap[dirName];
+ if (!componentMaps.ContainsKey(suffix))
+ componentMaps[suffix] = new HashSet<string>();
+ Console.WriteLine("Checking if any Directory elements match: " + dirName);
+ var matches = doc.Descendants("{" + nsWiX3 + "}Directory").Where(x => x.Attribute("Name").Value == dirName);
+ foreach (var dir in matches)
+ {
+ Console.WriteLine("\tProcessing Directory (Id=" + dir.Attribute("Id") + ")");
+ foreach (var comp in dir.Descendants("{" + nsWiX3 + "}Component"))
+ {
+ //Console.WriteLine("\t\tSet Component Feature (Id=" + comp.Attribute("Id") + ") to use feature (" + suffix + ")");
+ componentMaps[suffix].Add(comp.Attribute("Id").Value);
+ }
+ }
+ }
+
+ //Remove these collected ids from the existing component group
+ var currentGroup = doc.Descendants("{" + nsWiX3 + "}ComponentGroup").First();
+ var remove = new List<XElement>();
+
+ int moved = 0;
+ //Now write out the component group
+ foreach(var suffix in _featureMap.Values)
+ {
+ if (componentMaps[suffix].Count > 0)
+ {
+ var groupId = name + suffix;
+
+ var grp = new XElement("{" + nsWiX3 + "}ComponentGroup");
+ grp.SetAttributeValue("Id", groupId);
+
+ foreach (var cid in componentMaps[suffix])
+ {
+ var matches = currentGroup.Descendants("{" + nsWiX3 + "}ComponentRef").Where(x => x.Attribute("Id").Value == cid);
+ remove.AddRange(matches);
+
+ var el = new XElement("{" + nsWiX3 + "}ComponentRef");
+ el.SetAttributeValue("Id", cid);
+
+ grp.Add(el);
+ moved++;
+ }
+
+ //Prepend component group to the fragment
+ doc.Descendants("{" + nsWiX3 + "}Fragment").First().AddFirst(grp);
+ }
+ }
+
+ //Remove moved componentrefs from original group
+ foreach (var el in remove)
+ {
+ el.Remove();
+ }
+ Console.WriteLine("Moved {0} elements to new ComponentGroup. Removed {1} elements from original ComponentGroup", moved, remove.Count);
+ }
+
+ /// <summary>
+ /// Takes an existing .WXS file and generates an updated version, which
+ /// is saved to a .PARAFFIN extension.
+ /// </summary>
+ /// <returns>
+ /// 0 - The .PARAFFIN file was created.
+ /// 2 - The input file does not have the special comment in the
+ /// appropriate location.
+ /// </returns>
+ private static int UpdateExistingFile ( )
+ {
+ int returnValue = 0;
+
+ // Load the XML document. Any loading problems go right
+ // to an exception for the user.
+ XDocument inputDoc = XDocument.Load ( argValues.FileName );
+
+ XAttribute ns = inputDoc.Root.Attribute ( "xmlns" );
+ if ( 0 == String.Compare ( nsWiX2.ToString ( ) ,
+ ns.Value ,
+ StringComparison.OrdinalIgnoreCase ) )
+ {
+ inputNameSpace = nsWiX2;
+ }
+
+ // The output filename.
+ String outputFile = Path.ChangeExtension ( argValues.FileName ,
+ ".PARAFFIN" );
+
+ // The first node has to be comment I put there when
+ // the file was created.
+ XComment options = inputDoc.Root.FirstNode as XComment;
+ if ( null != options )
+ {
+ // It's a comment node, so set all the arguments from that
+ // section.
+ InitializeArgumentsFromFile ( options.Value );
+
+ // Create the new output file.
+ XDocument outputDoc = new XDocument ( );
+
+ // Add the WiX and Fragment nodes.
+ XElement outputRoot = new XElement ( nsWiX3 + "Wix" );
+ outputDoc.Add ( outputRoot );
+ XElement outputFragment = new XElement ( nsWiX3 + "Fragment" );
+ outputRoot.Add ( outputFragment );
+
+ // Find the directory ref of the input file.
+ XElement inputDirRef = inputDoc.Descendants (
+ inputNameSpace +
+ "DirectoryRef" ).First ( );
+ String idValue =
+ inputDirRef.Attributes ( "Id" ).First ( ).Value;
+
+ // Build a DirectoryRef for the output file.
+ XElement outputDirRef = new XElement ( nsWiX3 + "DirectoryRef" ,
+ new XAttribute ( "Id" , idValue ) );
+
+ // Add the directory ref to the output file.
+ outputFragment.Add ( outputDirRef );
+
+ // Get the starting directory values ready to go.
+ InitializeDirectoryValues ( );
+
+ // Recurse through the input file and the directories
+ // themselves.
+ RecurseDirectoriesForExistingFile ( inputDirRef ,
+ outputDirRef ,
+ fullStartDirectory );
+
+ // Add the Component group node.
+ AddComponentGroup ( outputFragment );
+
+ // Add the comment with all the command line options.
+ AddCommandLineOptionsComment ( outputRoot );
+
+ ProcessFeatureMap(outputDoc, Path.GetFileNameWithoutExtension(outputFile));
+
+ // All OK, Jumpmaster!
+ outputDoc.Save ( outputFile );
+ }
+ else
+ {
+ // This does not look like a file this tool previously
+ // generated.
+ errorMessage = Constants.UnknownFileType;
+ returnValue = 2;
+ }
+
+ return ( returnValue );
+ }
+
+ /// <summary>
+ /// Does the work of recursing both the file system directories and the
+ /// original .WXS file to produce an updated XML document.
+ /// </summary>
+ /// <param name="currInputElement">
+ /// The current element in the input .WXS file.
+ /// </param>
+ /// <param name="currOutputElement">
+ /// The current element in the output .PARAFFIN file.
+ /// </param>
+ /// <param name="directory">
+ /// The directory to process. This has to be the full directory value.
+ /// </param>
+ /// <remarks>
+ /// As you can guess, this is called recursively.
+ /// </remarks>
+ private static void
+ RecurseDirectoriesForExistingFile ( XElement currInputElement ,
+ XElement currOutputElement ,
+ String directory )
+ {
+ // If the currInputElement is null, I'm processing a brand new
+ // directory that isn't in the original file. Thus, I can treat
+ // adding this directory just like it's a new file and add this
+ // directory, plus all under it.
+ if ( null == currInputElement )
+ {
+ RecurseDirectoriesForNewFile ( currOutputElement , directory );
+ }
+ else
+ {
+ // The directory element I'm going to be building up.
+ XElement outputDirElement;
+
+ // Get the directory info in order to get just the name.
+ DirectoryInfo info = new DirectoryInfo ( directory );
+ String name = info.Name;
+
+ String matchAttrib = "Name";
+ // If this is a WiX 2.0 input file, I need to match on LongName
+ // instead if the name is more than 8 characters.
+ if ( ( inputNameSpace == nsWiX2 ) && ( name.Length > 8 ) )
+ {
+ matchAttrib = "LongName";
+ }
+
+ // Does this directory already exist in the input file?
+ var qFindDirectory = from elem in currInputElement.Elements ( )
+ where
+ ( (string)elem.Attribute ( matchAttrib ) == name )
+ select elem;
+
+ XElement inputDirElement = null;
+ int fileCount = qFindDirectory.Count ( );
+ Debug.Assert ( fileCount <= 1 , "fileCount <= 1" );
+ if ( fileCount > 1 )
+ {
+ // We've got a serious problem. :( You can't have multiple
+ // directories with the same name.
+ String err = String.Format ( CultureInfo.CurrentCulture ,
+ Constants.InvalidFileNameCountFmt ,
+ name );
+ throw new InvalidOperationException ( err );
+ }
+ else if ( 0 == fileCount )
+ {
+ // This is a new directory.
+ outputDirElement = CreateDirectoryElement ( directory );
+ }
+ else
+ {
+ // We've got one element so grab it.
+ inputDirElement = qFindDirectory.First ( );
+
+ if ( inputNameSpace == nsWiX2 )
+ {
+ // In case the input file was created with the
+ // version of Paraffin that supported WiX 2.0, I
+ // want to strip off the LongName attribute
+ // as it is no longer needed.
+ inputDirElement.SetAttributeValue ( "LongName" , null );
+ // Since WiX3 uses the Name attribute, I willl change
+ // the existing Name attribute to the long name so
+ // it gets copied below. This is the long name now.
+ inputDirElement.SetAttributeValue ( "Name" , name );
+ }
+
+ // This directory was in the previous file so copy it's
+ // attributes over to the new file.
+ outputDirElement = new XElement ( nsWiX3 + "Directory" );
+ foreach ( var attrib in inputDirElement.Attributes ( ) )
+ {
+ outputDirElement.SetAttributeValue ( attrib.Name ,
+ attrib.Value );
+ }
+
+ }
+
+ // Add this element to the output element.
+ currOutputElement.Add ( outputDirElement );
+
+ // Process all the files in this directory as compared to the
+ // input file.
+ UpdateFilesInDirectoryNode ( directory ,
+ inputDirElement ,
+ outputDirElement );
+
+ // Recurse directories if the original file had that set.
+ if ( false == argValues.NoDirectoryRecursion )
+ {
+ String [] dirs = Directory.GetDirectories ( directory );
+ foreach ( var item in dirs )
+ {
+ // Is this a directory the user wanted to skip?
+ Boolean skipDirectory = IsDirectoryExcluded ( item );
+ if ( false == skipDirectory )
+ {
+ RecurseDirectoriesForExistingFile (
+ inputDirElement ,
+ outputDirElement ,
+ item );
+ }
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Looks at the input .WXS for the files in this directory and compare
+ /// it to the files on disk. If the file is the same or is a new file,
+ /// add the files to the output. If it's no longer present on disk, but
+ /// is in the input .WXS, skip adding the file to the output.
+ /// </summary>
+ /// <param name="directory">The disk directory to scan.</param>
+ /// <param name="inputDir">The Directory element from the .WXS file that
+ /// maps to <see cref="directory"/>.</param>
+ /// <param name="outputDir">The Directory element for the output
+ /// .PARAFFIN file.</param>
+ /// <exception cref="InvalidOperationException">
+ /// Thrown if there's multiple files with the same name in the <paramref
+ /// name="outputDir"/> child elements.
+ /// </exception>
+ private static void UpdateFilesInDirectoryNode ( String directory ,
+ XElement inputDir ,
+ XElement outputDir )
+ {
+ // If the inputDir element is null, just treat this as if I was
+ // creating a new file.
+ if ( null == inputDir )
+ {
+ AddNewFilesToDirectoryNode ( directory , outputDir );
+ }
+ else
+ {
+ // The .WXS file had files for this directory so I need to
+ // match them all up with the existing files.
+
+ // Start by getting the files in this directory.
+ String [] files = Directory.GetFiles ( directory );
+
+ // Skip all those that have extension the user does not want.
+ var filesQuery = from file in files
+ where false == argValues.ExtensionList.
+ ContainsKey ( Path.GetExtension ( file )
+ .ToUpperInvariant ( ) )
+ select file;
+
+ // If there's no files in this directory, there's nothing else
+ // to do.
+ if ( 0 != filesQuery.Count ( ) )
+ {
+ // I'll add to the output .WXS file current Directory node
+ // by default.
+ XElement addToElement = outputDir;
+
+ // Are we doing multiple files per component?
+ if ( true == argValues.MultipleFilesPerComponent )
+ {
+ // Copy over the one component node. If you just add
+ // the node directly, that copies over all the child
+ // nodes as well so I need duplicate just the component
+ // node itself.
+ XElement intputCompElem =
+ inputDir.Element (
+ inputNameSpace + "Component" );
+ XElement outputCompElem =
+ new XElement ( nsWiX3 + "Component" );
+ foreach ( var attrib in intputCompElem.Attributes ( ) )
+ {
+ outputCompElem.SetAttributeValue ( attrib.Name ,
+ attrib.Value );
+ }
+
+ // Add the Component node on.
+ outputDir.Add ( outputCompElem );
+
+ // Point to the component where I'll be adding all the
+ // file nodes.
+ addToElement = outputCompElem;
+ }
+
+ // First get the child component(s) from this Directory.
+ var comps = inputDir.Elements (
+ inputNameSpace + "Component" );
+
+ // Now get all the files from just these Component
+ // elements.
+ var inputFiles = comps.Descendants (
+ inputNameSpace + "File" );
+
+ // Loop through all the files on disk.
+ foreach ( var file in filesQuery )
+ {
+ // Holds the element I'm going to add to the current
+ // output XML document.
+ XElement newOutputElem;
+
+ // Get the aliased value for this file.
+ String aliasedName = BuildAliasedFilename ( file );
+
+ // See if I can find that file in the input .WXS file
+ // by checking the aliased Source names.
+ var inputFileQuery = from fileNode in inputFiles
+ where
+ ( ( (string)fileNode.Attribute ( "Source" ) )
+ == aliasedName )
+ select fileNode;
+ int fileCount = inputFileQuery.Count ( );
+ Debug.Assert ( fileCount <= 1 , "fileCount <= 1" );
+ if ( 0 == fileCount )
+ {
+ XElement comp = null;
+ if ( false == argValues.MultipleFilesPerComponent )
+ {
+ // Put this file element in it's own Component.
+ // The component always has to be created first.
+ // so that the component and file are using the
+ // same unique number.
+ comp = CreateComponentElement ( );
+ }
+
+ // This is a new file that wasn't in the input .WXS
+ // file so just add it. First create a new File
+ // element.
+ newOutputElem = CreateFileElement ( file );
+
+ // Did I create a component for this file?
+ if ( null != comp )
+ {
+ // Add the file to this component.
+ comp.Add ( newOutputElem );
+
+ // Point at the component to add.
+ newOutputElem = comp;
+ }
+ }
+ else if ( 1 == fileCount )
+ {
+ newOutputElem = inputFileQuery.First ( );
+
+ // In case the input file was created with the
+ // version of Paraffin that supported WiX 2.0, I
+ // want to strip off the Name and LongName
+ // attributes as they are no longer needed.
+ newOutputElem.SetAttributeValue ( "Name" , null );
+ newOutputElem.SetAttributeValue ( "LongName" ,
+ null );
+
+
+ // Is it one file per component?
+ if ( false == argValues.MultipleFilesPerComponent )
+ {
+ // If this is a WiX 3.0 .WXS file I can simply
+ // cheat and make the newOutputElem actually
+ // point to the Component element. That way I
+ // just add the Component and the child File
+ // element in one swoop.
+ if ( inputNameSpace == nsWiX3 )
+ {
+ newOutputElem = newOutputElem.Parent;
+ }
+ else
+ {
+ // This is a fragment from WiX 2.0 being
+ // updated to 3.0. Because of the namespace
+ // being different, I need to copy the
+ // attributes manually.
+ XElement comp = new XElement (
+ nsWiX3 + "Component" );
+ foreach ( var attrib in
+ newOutputElem.Parent.Attributes ( ) )
+ {
+ comp.SetAttributeValue ( attrib.Name ,
+ attrib.Value );
+ }
+
+ // Create the WiX 3 version of this WiX 2
+ // file node.
+ XElement newFile =
+ CreateWiX3FileFromWix2File (
+ newOutputElem );
+ // Add the file to the component.
+ comp.Add ( newFile );
+ // Set the output element to the component.
+ newOutputElem = comp;
+ }
+ }
+ else if ( inputNameSpace == nsWiX2 )
+ {
+ // It's multiple files per component and this is
+ // a WiX 2.0 input file. Copy the attributes
+ // over manually to keep the namespaces
+ // straight. Now newOutput points to the WiX 3.0
+ // element.
+ newOutputElem = CreateWiX3FileFromWix2File (
+ newOutputElem );
+ }
+ }
+ else
+ {
+ // There's multiple files with the same name in this
+ // particular node. That's bad. :(
+ String err = String.Format (
+ CultureInfo.CurrentCulture ,
+ Constants.InvalidFileNameCountFmt ,
+ file );
+ throw new InvalidOperationException ( err );
+ }
+
+ // Add the file element to the parent node.
+ addToElement.Add ( newOutputElem );
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Called when processing a new file or a directory that's wasn't seen
+ /// in the existing .WXS when updating.
+ /// </summary>
+ /// <param name="currElement">
+ /// The current element in the output XML document.
+ /// </param>
+ /// <param name="directory">
+ /// The disk directory to recurse.
+ /// </param>
+ private static void RecurseDirectoriesForNewFile ( XElement currElement ,
+ String directory )
+ {
+ // It's new so create a Directory element.
+ XElement directoryNode = CreateDirectoryElement ( directory );
+
+ // Add the current directory to the passed in element
+ currElement.Add ( directoryNode );
+
+ // Add the files to this directory node.
+ AddNewFilesToDirectoryNode ( directory , directoryNode );
+
+ // Recurse the directories if I'm supposed to do so.
+ if ( false == argValues.NoDirectoryRecursion )
+ {
+ String [] dirs = Directory.GetDirectories ( directory );
+ foreach ( var item in dirs )
+ {
+ Boolean skipDirectory = IsDirectoryExcluded ( item );
+ if ( false == skipDirectory )
+ {
+ RecurseDirectoriesForNewFile ( directoryNode , item );
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// For new directories when creating new files or when adding new
+ /// directories when processing an existing .WXS, adds the files
+ /// to the <see cref="directoryElem"/> element.
+ /// </summary>
+ /// <param name="directory">
+ /// The directory to get the files from.
+ /// </param>
+ /// <param name="directoryElem">
+ /// The Director element to add the new Component/File elements to.
+ /// </param>
+ private static void AddNewFilesToDirectoryNode ( String directory ,
+ XElement directoryElem )
+ {
+ // Get the files in this directory.
+ String [] files = Directory.GetFiles ( directory );
+
+ // Only do the work if there are some files in the directory.
+ if ( files.Length > 0 )
+ {
+ // Skip all those that have extensions the user does not want.
+ var filesQuery = from file in files
+ where false == argValues.ExtensionList.
+ ContainsKey ( Path.GetExtension ( file )
+ .ToUpperInvariant ( ) )
+ select file;
+
+ // Create the first Component element. Only add this node to the
+ // directory node if the user wants multiple files per component
+ // node.
+ XElement currentComponent = CreateComponentElement ( );
+ if ( true == argValues.MultipleFilesPerComponent )
+ {
+ directoryElem.Add ( currentComponent );
+ }
+
+ // For each file on disk.
+ foreach ( var file in filesQuery )
+ {
+ // Create the File element and add it to the current
+ // Component element.
+ XElement fileElement = CreateFileElement ( file );
+ currentComponent.Add ( fileElement );
+ if ( false == argValues.MultipleFilesPerComponent )
+ {
+ directoryElem.Add ( currentComponent );
+ currentComponent = CreateComponentElement ( );
+ }
+ }
+
+ // I'm done with this directory so bump up the component and
+ // directory count if the user asked for that to happen.
+ componentNumber += ( argValues.IncrementValue - 2 );
+ }
+ }
+
+ /// <summary>
+ /// Initializes the <see cref="ParaffinArgParser"/> with all the
+ /// settings from the first comment block. Used when reading in a .WXS
+ /// to compare to the files on the disk.
+ /// </summary>
+ /// <param name="inputXml">
+ /// The XML string to process.
+ /// </param>
+ private static void InitializeArgumentsFromFile ( string inputXml )
+ {
+ XElement options = XElement.Parse ( inputXml );
+
+ // Save off the settings from the command line.
+ ParaffinArgParser originalArgs = argValues;
+
+ // Start the arguments from the comment section.
+ argValues = new ParaffinArgParser ( );
+
+ // Get all the easy values out.
+ argValues.CustomValue =
+ options.Descendants ( CUSTOMELEM ).First ( ).Value;
+
+ argValues.Alias =
+ options.Descendants ( ALIASELEM ).First ( ).Value;
+
+ argValues.StartDirectory =
+ options.Descendants ( DIRECTORYELEM ).First ( ).Value;
+
+ argValues.IncrementValue = Convert.ToInt32 (
+ options.Descendants ( INCREMENTELEM ).First ( ).Value ,
+ CultureInfo.InvariantCulture );
+
+ argValues.GenerateGuids = Convert.ToBoolean (
+ options.Descendants ( GUIDSELEM ).First ( ).Value ,
+ CultureInfo.InvariantCulture );
+
+ argValues.MultipleFilesPerComponent = Convert.ToBoolean (
+ options.Descendants ( MULTIPLEELEM ).First ( ).Value ,
+ CultureInfo.InvariantCulture );
+
+ argValues.NoDirectoryRecursion = Convert.ToBoolean (
+ options.Descendants ( NORECURSELEM ).First ( ).Value ,
+ CultureInfo.InvariantCulture );
+
+ directoryNumber = Convert.ToInt32 (
+ options.Descendants ( NEXTDIRECTORYNUMELEM ).First ( ).Value ,
+ CultureInfo.InvariantCulture );
+
+ componentNumber = Convert.ToInt32 (
+ options.Descendants ( NEXTCOMPONENTNUMBER ).First ( ).Value ,
+ CultureInfo.InvariantCulture );
+
+ var extNode = options.Descendants ( EXTEXCLUDEELEM );
+ foreach ( var item in extNode.Descendants ( ) )
+ {
+ argValues.ExtensionList.Add ( item.Value , true );
+ }
+
+ var dirEx = options.Descendants ( DIREEXCLUDEELEM );
+ foreach ( var item in dirEx.Descendants ( ) )
+ {
+ argValues.DirectoryExcludeList.Add ( item.Value );
+ }
+
+ // After releasing 1.0, I've added a few command line options.
+ // Since I don't want to break existing PARAFFIN generated files,
+ // I'll not require the following options to be in existing files.
+ // If they are cool, but no sense crashing out if they aren't.
+ var win64Elems = options.Descendants ( WIN64ELEM );
+ if ( win64Elems.Count ( ) == 1 )
+ {
+ // Grab the value.
+ argValues.Win64 = Convert.ToBoolean (
+ win64Elems.First ( ).Value ,
+ CultureInfo.InvariantCulture );
+ }
+ else
+ {
+ // Assume false.
+ argValues.Win64 = false;
+ }
+
+ // Now that everything is read out of the original options block,
+ // add in any additional -ext and -dirExclude options specified on
+ // the command line.
+ foreach ( var cmdLineExt in originalArgs.ExtensionList.Keys )
+ {
+ if ( false ==
+ argValues.ExtensionList.ContainsKey ( cmdLineExt ) )
+ {
+ argValues.ExtensionList.Add ( cmdLineExt , true );
+ }
+ }
+ foreach ( var dirExclude in originalArgs.DirectoryExcludeList )
+ {
+ if ( false ==
+ argValues.DirectoryExcludeList.Contains ( dirExclude ) )
+ {
+ argValues.DirectoryExcludeList.Add ( dirExclude );
+ }
+ }
+ }
+
+ /// <summary>
+ /// Adds the command line options as the first comment element under
+ /// the WiX element.
+ /// </summary>
+ /// <param name="wixElement">
+ /// The WiX element to add to.
+ /// </param>
+ private static void AddCommandLineOptionsComment ( XElement wixElement )
+ {
+ // Create the XML data for the easy stuff.
+ XElement initOptions =
+ new XElement ( CMDLINEOPTIONSELEM ,
+ new XElement ( PRODUCEDBYELEM ,
+ Constants.CommentProducer ) ,
+ new XElement ( WARNINGELEM , Constants.CommentWarning ) ,
+ new XElement ( DATECREATE ,
+ DateTime.Now.ToString ( "g" ,
+ CultureInfo.CurrentCulture ) ) ,
+ new XElement ( DIRECTORYELEM ,
+ argValues.StartDirectory ) ,
+ new XElement ( CUSTOMELEM , argValues.CustomValue ) ,
+ new XElement ( ALIASELEM , argValues.Alias ) ,
+ new XElement ( INCREMENTELEM ,
+ argValues.IncrementValue ) ,
+ new XElement ( GUIDSELEM , argValues.GenerateGuids ) ,
+ new XElement ( WIN64ELEM , argValues.Win64 ) ,
+ new XElement ( MULTIPLEELEM ,
+ argValues.MultipleFilesPerComponent ) ,
+ new XElement ( NORECURSELEM ,
+ argValues.NoDirectoryRecursion ) );
+
+ // Add the file extension exclusions.
+ XElement extList = new XElement ( EXTEXCLUDEELEM );
+ foreach ( var item in argValues.ExtensionList )
+ {
+ extList.Add ( new XElement ( EXTELEM , item.Key ) );
+ }
+
+ initOptions.Add ( extList );
+
+ // Add the directory exclusions.
+ XElement dirExList = new XElement ( DIREEXCLUDEELEM );
+ foreach ( var item in argValues.DirectoryExcludeList )
+ {
+ dirExList.Add ( new XElement ( DIREXT , item.ToString ( ) ) );
+ }
+
+ initOptions.Add ( dirExList );
+
+ // Add the next directory number and component number so we don't
+ // overwrite an existing value.
+ XElement dirNum = new XElement ( NEXTDIRECTORYNUMELEM ,
+ directoryNumber );
+ initOptions.Add ( dirNum );
+ XElement compNum = new XElement ( NEXTCOMPONENTNUMBER ,
+ componentNumber );
+ initOptions.Add ( compNum );
+
+ // Add the XML comment.
+ XComment comment = new XComment ( initOptions.ToString ( ) );
+ wixElement.AddFirst ( comment );
+ }
+
+ /// <summary>
+ /// Adds the ComponentGroup as the first child to the Fragment element.
+ /// </summary>
+ /// <param name="fragment">
+ /// The Fragment element.
+ /// </param>
+ private static void AddComponentGroup ( XElement fragment )
+ {
+ // Grab all the Component elements and sort them by the ID
+ // attribute.
+ var compNodes = from node in fragment.
+ Descendants ( nsWiX3 + "Component" )
+ select node;
+
+ // Sort them in logical order because I'm a little bit obsessive.
+ compNodes = compNodes.OrderBy (
+ n => (string)n.Attribute ( "Id" ).Value ,
+ new LogicalStringComparer ( ) );
+
+ StringBuilder sb = new StringBuilder ( 70 );
+ sb.AppendFormat ( "group_{0}" , argValues.CustomValue );
+
+ // Ensure that all invalid characters are stripped from the ID.
+ String id = RemoveInvalidIdCharacters ( sb.ToString ( ) );
+
+ XElement groupNode = new XElement ( nsWiX3 + "ComponentGroup" ,
+ new XAttribute ( "Id" , id ) );
+ foreach ( var component in compNodes )
+ {
+ XElement refNode = new XElement ( nsWiX3 + "ComponentRef" ,
+ new XAttribute ( "Id" ,
+ component.Attribute ( "Id" ).Value ) );
+ groupNode.Add ( refNode );
+ }
+
+ // Add the group node as the first child of the outputFragment only
+ // if there are some components. It's perfectly reasonable to have
+ // a fragment made up of nothing but directories.
+ if ( 0 != compNodes.Count ( ) )
+ {
+ fragment.AddFirst ( groupNode );
+ }
+ }
+
+ /// <summary>
+ /// Gets the directory values initialized so the code can handle aliases
+ /// and the individual directories.
+ /// </summary>
+ private static void InitializeDirectoryValues ( )
+ {
+ fullStartDirectory = Path.GetFullPath ( argValues.StartDirectory );
+ DirectoryInfo info = new DirectoryInfo ( fullStartDirectory );
+ baseDirectoryName = info.Name;
+ }
+
+ /// <summary>
+ /// MSI only accepts IDs that are 72 characters long so I need to ensure
+ /// that the strings I use are within that limit.
+ /// </summary>
+ /// <param name="start">
+ /// The initial part of the string.
+ /// </param>
+ /// <param name="main">
+ /// The main part of the string.
+ /// </param>
+ /// <param name="uniqueId">
+ /// The unique value to append to this string.
+ /// </param>
+ /// <returns>
+ /// A unique string that is only 70 characters long and has all invalid
+ /// characters stripped.
+ /// </returns>
+ private static String CreateSeventyCharIdString ( String start ,
+ String main ,
+ int uniqueId )
+ {
+ const String FormatStr = "{0}_{1}_{2}";
+ const Int32 MaxLen = 70;
+
+ String uniqueStr = String.Format ( CultureInfo.InvariantCulture ,
+ "{0}" ,
+ uniqueId );
+ StringBuilder sb = new StringBuilder ( 100 );
+ sb.AppendFormat ( FormatStr , start , main , uniqueStr );
+ if ( sb.Length > MaxLen )
+ {
+ sb.Length = 0;
+ int idLen = uniqueStr.Length;
+ int startLen = start.Length;
+ int len = Math.Min ( main.Length ,
+ MaxLen - ( idLen + startLen ) );
+ String sub = main.Substring ( 0 , len );
+ sb.AppendFormat ( FormatStr ,
+ start ,
+ sub ,
+ uniqueStr );
+ }
+
+ // Turns out id strings in WiX cannot have dashes in them so
+ // convert them to underscores.
+ String retVal = RemoveInvalidIdCharacters ( sb.ToString ( ) );
+ return ( retVal );
+ }
+
+ /// <summary>
+ /// Looks through the list of directory exclusions and returns true
+ /// if this directory is supposed to be excluded.
+ /// </summary>
+ /// <param name="directory">
+ /// The directory to check if it's got any excluded value in it.
+ /// </param>
+ /// <returns>
+ /// True - Supposed to exclude and skip.
+ /// False - Process this directory.
+ /// </returns>
+ private static Boolean IsDirectoryExcluded ( String directory )
+ {
+ Boolean skipDirectory = false;
+
+ // If the user wanted to skip some directories, check to see
+ // if this happens to be one.
+ for ( int i = 0 ; i < argValues.DirectoryExcludeList.Count ; i++ )
+ {
+ if ( true == directory.Contains (
+ argValues.DirectoryExcludeList [ i ] ) )
+ {
+ skipDirectory = true;
+ break;
+ }
+ }
+
+ return ( skipDirectory );
+ }
+
+ /// <summary>
+ /// Returns a unique name for the Directory Id attribute.
+ /// </summary>
+ /// <param name="directory">
+ /// The full directory to process.
+ /// </param>
+ /// <returns>
+ /// A string that encapsulates the directory name with a unique value
+ /// appended.
+ /// </returns>
+ private static String GenerateUniqueDirectoryIdName ( String directory )
+ {
+ // To make the Id a bit easier to read, I'm going to use a naming
+ // scheme of "dir_<Path>_<Num>". That will put some uniqueness on
+ // the names so they don't conflict across large installs.
+
+ // Suffix the directory with \ to ensure I find the exact match
+ // when looking the base directory.
+ if ( false == directory.EndsWith ( "\\" ,
+ StringComparison.OrdinalIgnoreCase ) )
+ {
+ directory += "\\";
+ }
+
+ // Figure out where the base directory name is in this string and
+ // create a unique name for the Id attribute.
+ String exactBaseDirectory =
+ String.Format ( CultureInfo.InvariantCulture ,
+ "\\{0}\\" ,
+ baseDirectoryName );
+ Int32 startBaseDir = directory.IndexOf ( exactBaseDirectory ,
+ StringComparison.OrdinalIgnoreCase );
+
+ // Get the real value and skip the preceding \\ used to find the
+ // exact base.
+ String dirIdString = directory.Substring ( startBaseDir + 1 );
+ if ( '\\' == dirIdString [ dirIdString.Length - 1 ] )
+ {
+ dirIdString = dirIdString.Substring ( 0 ,
+ dirIdString.Length - 1 );
+ }
+
+ dirIdString = dirIdString.Replace ( '\\' , '.' );
+ dirIdString = CreateSeventyCharIdString ( "dir" ,
+ dirIdString ,
+ directoryNumber );
+
+ // Since I've used this directoryNumber, time to bump it up.
+ directoryNumber += argValues.IncrementValue;
+
+ return ( dirIdString );
+ }
+
+ /// <summary>
+ /// Creates a new Directory element.
+ /// </summary>
+ /// <param name="directory">
+ /// The file directory for this element.
+ /// </param>
+ /// <returns>
+ /// A constructed <see cref="XElement"/>.
+ /// </returns>
+ private static XElement CreateDirectoryElement ( String directory )
+ {
+ // Each directory element needs a unique value.
+ String uniqueDirID = GenerateUniqueDirectoryIdName ( directory );
+
+ // Get the long and short names for this directory.
+ DirectoryInfo info = new DirectoryInfo ( directory );
+
+ // I've got enough to create the Directory node.
+ XElement directoryNode = new XElement ( nsWiX3 + "Directory" ,
+ new XAttribute ( "Id" , uniqueDirID ) ,
+ new XAttribute ( "Name" , info.Name ) );
+ return ( directoryNode );
+ }
+
+ /// <summary>
+ /// Creates a File element for the file in <paramref name="fileName"/>.
+ /// </summary>
+ /// <param name="fileName">
+ /// The full filename to process.
+ /// </param>
+ /// <returns>
+ /// A valid <see cref="XElement"/> for the File element.
+ /// </returns>
+ private static XElement CreateFileElement ( String fileName )
+ {
+ // Create a unique filename. In a one file per component run, this
+ // will mean that the file and it's parent component will have the
+ // same number.
+ String fileId = CreateSeventyCharIdString ( "file" ,
+ argValues.CustomValue ,
+ componentNumber - 1 );
+
+ // If the user wanted to group all the files into a component, I
+ // need to bump up the componentNumber to keep everything straight.
+ if ( true == argValues.MultipleFilesPerComponent )
+ {
+ componentNumber++;
+ }
+
+ XElement file = new XElement ( nsWiX3 + "File" ,
+ new XAttribute ( "Id" , fileId ) );
+ if ( true == IsPEFile ( fileName ) )
+ {
+ file.Add ( new XAttribute ( "Checksum" , "yes" ) );
+ }
+ fileName = BuildAliasedFilename ( fileName );
+ file.Add ( new XAttribute ( "Source" , fileName ) );
+ return ( file );
+ }
+
+ /// <summary>
+ /// Creates a WiX 3 File Element from a WiX 2 File Element.
+ /// </summary>
+ /// <param name="input">
+ /// The WiX 2.0 file element.
+ /// </param>
+ /// <returns>
+ /// The WiX 3.0 file element.
+ /// </returns>
+ private static XElement CreateWiX3FileFromWix2File ( XElement input )
+ {
+
+ XElement newFile = new XElement ( nsWiX3 + "File" );
+ foreach ( var attrib in input.Attributes ( ) )
+ {
+ newFile.SetAttributeValue ( attrib.Name , attrib.Value );
+ }
+
+ // If it's a PE binary file, add on the Checksum attribute.
+ if ( true == IsPEFile ( newFile.Attribute ( "Source" ).Value ) )
+ {
+ newFile.SetAttributeValue ( "Checksum" ,
+ "yes" );
+ }
+ return ( newFile );
+ }
+
+ /// <summary>
+ /// Creates a standard Component element.
+ /// </summary>
+ /// <returns>
+ /// A newly created and unique Component elements.
+ /// </returns>
+ private static XElement CreateComponentElement ( )
+ {
+ // Make sure the Id field is less than or equal to 70 characters.
+ String componentId = CreateSeventyCharIdString ( "comp" ,
+ argValues.CustomValue ,
+ componentNumber );
+
+ // Increment since I just used that number.
+ componentNumber++;
+
+ String guidString = "PUT-GUID-HERE";
+ if ( true == argValues.GenerateGuids )
+ {
+ Guid g = Guid.NewGuid ( );
+ guidString = g.ToString ( ).ToUpperInvariant ( );
+ }
+
+ XElement comp = new XElement ( nsWiX3 + "Component" ,
+ new XAttribute ( "Id" , componentId ) ,
+ new XAttribute ( "DiskId" , "1" ) ,
+ new XAttribute ( "KeyPath" , "yes" ) ,
+ new XAttribute ( "Guid" , guidString ) );
+
+ // Does the user want the Win64 attribute?
+ if ( true == argValues.Win64 )
+ {
+ comp.SetAttributeValue ( "Win64" , "yes" );
+ }
+
+ return ( comp );
+ }
+
+ private static String BuildAliasedFilename ( String fileName )
+ {
+ // Does the user want an alias for the base directory name?
+ if ( false == String.IsNullOrEmpty ( argValues.Alias ) )
+ {
+ fileName = fileName.Replace ( fullStartDirectory ,
+ argValues.Alias );
+ }
+
+ return ( fileName );
+ }
+
+ private static Boolean IsPEFile ( String fileName )
+ {
+ String ext = Path.GetExtension ( fileName );
+ ext = ext.ToUpper ( CultureInfo.CurrentCulture );
+
+ for ( int i = 0 ; i < peFileExtension.Length ; i++ )
+ {
+ if ( 0 == String.Compare ( ext ,
+ peFileExtension[i] ,
+ true ,
+ CultureInfo.CurrentCulture ) )
+ {
+ return ( true );
+ }
+ }
+ return ( false );
+ }
+
+ private static String RemoveInvalidIdCharacters ( String input )
+ {
+ // WiX 2.0 does not document the actual valid characters in an Id
+ // attribute. This is especially true in Directory elements. What
+ // I'll do here is replace everything that's not in the range
+ // [0-9a-zA-Z_] with underscores. While that might make some of the
+ // Ids harder to read, I'm assured CANDLE.EXE will compile the
+ // fragment.
+ return ( Regex.Replace ( input , "[^0-9a-zA-Z_]" , "_" ) );
+ }
+
+ private static class NativeMethods
+ {
+ private const int MaxPath = 255;
+
+ [DllImport ( "shlwapi.dll" ,
+ CharSet = CharSet.Unicode ,
+ ExactSpelling = true )]
+ internal static extern int StrCmpLogicalW ( String x , String y );
+
+ }
+
+ /// <summary>
+ /// Used to sort values in strings in logical order.
+ /// </summary>
+ private class LogicalStringComparer : IComparer<String>
+ {
+ /// <summary>
+ /// Calls the native logical string compare method.
+ /// </summary>
+ /// <param name="x">
+ /// The first string to compare.
+ /// </param>
+ /// <param name="y">
+ /// The second string to compare.
+ /// </param>
+ /// <returns>
+ /// Zero if the strings are identical, 1 if
+ /// <paramref name="x"/> is greater, -1 if
+ /// <paramref name="y"/> is greater.
+ /// </returns>
+ public int Compare ( string x , string y )
+ {
+ return ( NativeMethods.StrCmpLogicalW ( x , y ) );
+ }
+ }
+ }
+}
Added: trunk/Installer/Support/Paraffin/Paraffin.csproj
===================================================================
--- trunk/Installer/Support/Paraffin/Paraffin.csproj (rev 0)
+++ trunk/Installer/Support/Paraffin/Paraffin.csproj 2012-04-22 12:47:10 UTC (rev 6585)
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{69CEBB42-4C4B-4546-9DEE-A5183E989214}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Wintellect.Paraffin</RootNamespace>
+ <AssemblyName>Paraffin</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <SignAssembly>true</SignAssembly>
+ <AssemblyOriginatorKeyFile>Wintellect.SNK</AssemblyOriginatorKeyFile>
+ <PublishUrl>publish\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Disk</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <IsWebBootstrapper>false</IsWebBootstrapper>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
+ <CodeAnalysisRules>+!Microsoft.Design#CA1012;+!Microsoft.Design#CA2210;+!Microsoft.Design#CA1040;+!Microsoft.Design#CA1005;+!Microsoft.Design#CA1020;+!Microsoft.Design#CA1021;+!Microsoft.Design#CA1010;+!Microsoft.Design#CA1011;+!Microsoft.Design#CA1009;+!Microsoft.Design#CA1050;+!Microsoft.Design#CA1026;+!Microsoft.Design#CA1019;+!Microsoft.Design#CA1031;+!Microsoft.Design#CA1047;+!Microsoft.Design#CA1000;+!Microsoft.Design#CA1048;+!Microsoft.Design#CA1051;+!Microsoft.Design#CA1002;+!Microsoft.Design#CA1061;+!Microsoft.Design#CA1006;+!Microsoft.Design#CA1046;+!Microsoft.Design#CA1045;+!Microsoft.Design#CA1065;+!Microsoft.Design#CA1038;+!Microsoft.Design#CA1008;+!Microsoft.Design#CA1028;+!Microsoft.Design#CA1064;+!Microsoft.Design#CA1004;+!Microsoft.Design#CA1035;+!Microsoft.Design#CA1063;+!Microsoft.Design#CA1032;+!Microsoft.Design#CA1023;+!Microsoft.Design#CA1033;+!Microsoft.Design#CA1039;+!Microsoft.Design#CA1016;+!Microsoft.Design#CA1014;+!Microsoft.Design#CA1017;+!Mi
crosoft.Design#CA1018;+!Microsoft.Design#CA1027;+!Microsoft.Design#CA1059;+!Microsoft.Design#CA1060;+!Microsoft.Design#CA1034;+!Microsoft.Design#CA1013;+!Microsoft.Design#CA1036;+!Microsoft.Design#CA1044;+!Microsoft.Design#CA1041;+!Microsoft.Design#CA1025;+!Microsoft.Design#CA1052;+!Microsoft.Design#CA1053;+!Microsoft.Design#CA1057;+!Microsoft.Design#CA1058;+!Microsoft.Design#CA1001;+!Microsoft.Design#CA1049;+!Microsoft.Design#CA1054;+!Microsoft.Design#CA1056;+!Microsoft.Design#CA1055;+!Microsoft.Design#CA1030;+!Microsoft.Design#CA1003;+!Microsoft.Design#CA1007;+!Microsoft.Design#CA1043;+!Microsoft.Design#CA1024;+!Microsoft.Globalization#CA1301;+!Microsoft.Globalization#CA1302;+!Microsoft.Globalization#CA1308;+!Microsoft.Globalization#CA1306;+!Microsoft.Globalization#CA1304;+!Microsoft.Globalization#CA1305;+!Microsoft.Globalization#CA2101;+!Microsoft.Globalization#CA1300;+!Microsoft.Globalization#CA1307;+!Microsoft.Globalization#CA1309;+!Microsoft.Interoperability#CA1403;+!M
icrosoft.Interoperability#CA1406;+!Microsoft.Interoperability#CA1413;+!Microsoft.Interoperability#CA1402;+!Microsoft.Interoperability#CA1407;+!Microsoft.Interoperability#CA1404;+!Microsoft.Interoperability#CA1410;+!Microsoft.Interoperability#CA1411;+!Microsoft.Interoperability#CA1405;+!Microsoft.Interoperability#CA1409;+!Microsoft.Interoperability#CA1415;+!Microsoft.Interoperability#CA1408;+!Microsoft.Interoperability#CA1414;+!Microsoft.Interoperability#CA1412;+!Microsoft.Interoperability#CA1400;+!Microsoft.Interoperability#CA1401;+!Microsoft.Maintainability#CA1506;+!Microsoft.Maintainability#CA1502;+!Microsoft.Maintainability#CA1501;+!Microsoft.Maintainability#CA1505;+!Microsoft.Maintainability#CA1504;+!Microsoft.Maintainability#CA1500;+!Microsoft.Mobility#CA1600;+!Microsoft.Mobility#CA1601;+!Microsoft.Naming#CA1702;+!Microsoft.Naming#CA1700;+!Microsoft.Naming#CA1712;+!Microsoft.Naming#CA1713;+!Microsoft.Naming#CA1714;+!Microsoft.Naming#CA1709;+!Microsoft.Naming#CA1704;+!Mi
crosoft.Naming#CA1708;+!Microsoft.Naming#CA1715;+!Microsoft.Naming#CA1710;+!Microsoft.Naming#CA1720;+!Microsoft.Naming#CA1707;+!Microsoft.Naming#CA1722;+!Microsoft.Naming#CA1711;+!Microsoft.Naming#CA1716;+!Microsoft.Naming#CA1717;+!Microsoft.Naming#CA1725;+!Microsoft.Naming#CA1719;+!Microsoft.Naming#CA1721;+!Microsoft.Naming#CA1701;+!Microsoft.Naming#CA1703;+!Microsoft.Naming#CA1724;+!Microsoft.Naming#CA1726;+!Microsoft.Performance#CA1809;+!Microsoft.Performance#CA1811;+!Microsoft.Performance#CA1812;+!Microsoft.Performance#CA1813;+!Microsoft.Performance#CA1823;+!Microsoft.Performance#CA1800;+!Microsoft.Performance#CA1805;+!Microsoft.Performance#CA1810;+!Microsoft.Performance#CA1824;+!Microsoft.Performance#CA1822;+!Microsoft.Performance#CA1815;+!Microsoft.Performance#CA1814;+!Microsoft.Performance#CA1819;+!Microsoft.Performance#CA1821;+!Microsoft.Performance#CA1804;+!Microsoft.Performance#CA1820;+!Microsoft.Performance#CA1802;+!Microsoft.Portability#CA1903;+!Microsoft.Portabi
lity#CA1901;+!Microsoft.Portability#CA1900;+!Microsoft.Reliability#CA2001;+!Microsoft.Reliability#CA2002;+!Microsoft.Reliability#CA2003;+!Microsoft.Reliability#CA2004;+!Microsoft.Reliability#CA2006;+!Microsoft.Security#CA2116;+!Microsoft.Security#CA2117;+!Microsoft.Security#CA2105;+!Microsoft.Security#CA2115;+!Microsoft.Security#CA2102;+!Microsoft.Security#CA2104;+!Microsoft.Security#CA2122;+!Microsoft.Security#CA2114;+!Microsoft.Security#CA2123;+!Microsoft.Security#CA2111;+!Microsoft.Security#CA2108;+!Microsoft.Security#CA2107;+!Microsoft.Security#CA2103;+!Microsoft.Security#CA2118;+!Microsoft.Security#CA2109;+!Microsoft.Security#CA2119;+!Microsoft.Security#CA2106;+!Microsoft.Security#CA2112;+!Microsoft.Security#CA2120;+!Microsoft.Security#CA2121;+!Microsoft.Security#CA2126;+!Microsoft.Security#CA2124;+!Microsoft.Security#CA2127;+!Microsoft.Security#CA2128;+!Microsoft.Security#CA2129;+!Microsoft.Usage#CA2243;+!Microsoft.Usage#CA2236;+!Microsoft.Usage#CA1816;+!Microsoft.Usag
e#CA2227;+!Microsoft.Usage#CA2213;+!Microsoft.Usage#CA2216;+!Microsoft.Usage#CA2214;+!Microsoft.Usage#CA2222;+!Microsoft.Usage#CA1806;+!Microsoft.Usage#CA2217;+!Microsoft.Usage#CA2212;+!Microsoft.Usage#CA2219;+!Microsoft.Usage#CA2201;+!Microsoft.Usage#CA2228;+!Microsoft.Usage#CA2221;+!Microsoft.Usage#CA2220;+!Microsoft.Usage#CA2240;+!Microsoft.Usage#CA2229;+!Microsoft.Usage#CA2238;+!Microsoft.Usage#CA2207;+!Microsoft.Usage#CA2208;+!Microsoft.Usage#CA2235;+!Microsoft.Usage#CA2237;+!Microsoft.Usage#CA2232;+!Microsoft.Usage#CA2223;+!Microsoft.Usage#CA2211;+!Microsoft.Usage#CA2233;+!Microsoft.Usage#CA2225;+!Microsoft.Usage#CA2226;+!Microsoft.Usage#CA2231;+!Microsoft.Usage#CA2224;+!Microsoft.Usage#CA2218;+!Microsoft.Usage#CA2234;+!Microsoft.Usage#CA2239;+!Microsoft.Usage#CA2200;+!Microsoft.Usage#CA1801;+!Microsoft.Usage#CA2242;+!Microsoft.Usage#CA2205;+!Microsoft.Usage#CA2230;+!Wintellect.DesignRules#Wintellect2002;+!Wintellect.DesignRules#Wintellect2001;+!Wintellect.DesignRules#
Wintellect2003;+!Wintellect.DesignRules#Wintellect2004;+!Wintellect.DesignRules#Wintellect2000;+!Wintellect.DesignRules#Wintellect2006;+!Wintellect.DesignRules#Wintellect2005;+!Wintellect.DesignRules#Wintellect2007;+!Wintellect.PerformanceRules#Wintellect1000;+!Wintellect.UsageRules#Wintellect3000;+!Wintellect.UsageRules#Wintellect3003;+!Wintellect.UsageRules#Wintellect3002;+!Wintellect.UsageRules#Wintellect3005;+!Wintellect.UsageRules#Wintellect3004;+!Wintellect.UsageRules#Wintellect3001</CodeAnalysisRules>
+ <DocumentationFile>
+ </DocumentationFile>
+ <RunCodeAnalysis>true</RunCodeAnalysis>
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeAnalysisRules>+!Microsoft.Design#CA1012;+!Microsoft.Design#CA2210;+!Microsoft.Design#CA1040;+!Microsoft.Design#CA1005;+!Microsoft.Design#CA1020;+!Microsoft.Design#CA1021;+!Microsoft.Design#CA1010;+!Microsoft.Design#CA1011;+!Microsoft.Design#CA1009;+!Microsoft.Design#CA1050;+!Microsoft.Design#CA1026;+!Microsoft.Design#CA1019;+!Microsoft.Design#CA1031;+!Microsoft.Design#CA1047;+!Microsoft.Design#CA1000;+!Microsoft.Design#CA1048;+!Microsoft.Design#CA1051;+!Microsoft.Design#CA1002;+!Microsoft.Design#CA1061;+!Microsoft.Design#CA1006;+!Microsoft.Design#CA1046;+!Microsoft.Design#CA1045;+!Microsoft.Design#CA1065;+!Microsoft.Design#CA1038;+!Microsoft.Design#CA1008;+!Microsoft.Design#CA1028;+!Microsoft.Design#CA1064;+!Microsoft.Design#CA1004;+!Microsoft.Design#CA1035;+!Microsoft.Design#CA1063;+!Microsoft.Design#CA1032;+!Microsoft.Design#CA1023;+!Microsoft.Design#CA1033;+!Microsoft.Design#CA1039;+!Microsoft.Design#CA1016;+!Microsoft.Design#CA1014;+!Microsoft.Design#CA1017;+!Mi
crosoft.Design#CA1018;+!Microsoft.Design#CA1027;+!Microsoft.Design#CA1059;+!Microsoft.Design#CA1060;+!Microsoft.Design#CA1034;+!Microsoft.Design#CA1013;+!Microsoft.Design#CA1036;+!Microsoft.Design#CA1044;+!Microsoft.Design#CA1041;+!Microsoft.Design#CA1025;+!Microsoft.Design#CA1052;+!Microsoft.Design#CA1053;+!Microsoft.Design#CA1057;+!Microsoft.Design#CA1058;+!Microsoft.Design#CA1001;+!Microsoft.Design#CA1049;+!Microsoft.Design#CA1054;+!Microsoft.Design#CA1056;+!Microsoft.Design#CA1055;+!Microsoft.Design#CA1030;+!Microsoft.Design#CA1003;+!Microsoft.Design#CA1007;+!Microsoft.Design#CA1043;+!Microsoft.Design#CA1024;+!Microsoft.Globalization#CA1301;+!Microsoft.Globalization#CA1302;+!Microsoft.Globalization#CA1308;+!Microsoft.Globalization#CA1306;+!Microsoft.Globalization#CA1304;+!Microsoft.Globalization#CA1305;+!Microsoft.Globalization#CA2101;+!Microsoft.Globalization#CA1300;+!Microsoft.Globalization#CA1307;+!Microsoft.Globalization#CA1309;+!Microsoft.Interoperability#CA1403;+!M
icrosoft.Interoperability#CA1406;+!Microsoft.Interoperability#CA1413;+!Microsoft.Interoperability#CA1402;+!Microsoft.Interoperability#CA1407;+!Microsoft.Interoperability#CA1404;+!Microsoft.Interoperability#CA1410;+!Microsoft.Interoperability#CA1411;+!Microsoft.Interoperability#CA1405;+!Microsoft.Interoperability#CA1409;+!Microsoft.Interoperability#CA1415;+!Microsoft.Interoperability#CA1408;+!Microsoft.Interoperability#CA1414;+!Microsoft.Interoperability#CA1412;+!Microsoft.Interoperability#CA1400;+!Microsoft.Interoperability#CA1401;+!Microsoft.Maintainability#CA1506;+!Microsoft.Maintainability#CA1502;+!Microsoft.Maintainability#CA1501;+!Microsoft.Maintainability#CA1505;+!Microsoft.Maintainability#CA1504;+!Microsoft.Maintainability#CA1500;+!Microsoft.Mobility#CA1600;+!Microsoft.Mobility#CA1601;+!Microsoft.Naming#CA1702;+!Microsoft.Naming#CA1700;+!Microsoft.Naming#CA1712;+!Microsoft.Naming#CA1713;+!Microsoft.Naming#CA1714;+!Microsoft.Naming#CA1709;+!Microsoft.Naming#CA1704;+!Mi
crosoft.Naming#CA1708;+!Microsoft.Naming#CA1715;+!Microsoft.Naming#CA1710;+!Microsoft.Naming#CA1720;+!Microsoft.Naming#CA1707;+!Microsoft.Naming#CA1722;+!Microsoft.Naming#CA1711;+!Microsoft.Naming#CA1716;+!Microsoft.Naming#CA1717;+!Microsoft.Naming#CA1725;+!Microsoft.Naming#CA1719;+!Microsoft.Naming#CA1721;+!Microsoft.Naming#CA1701;+!Microsoft.Naming#CA1703;+!Microsoft.Naming#CA1724;+!Microsoft.Naming#CA1726;+!Microsoft.Performance#CA1809;+!Microsoft.Performance#CA1811;+!Microsoft.Performance#CA1812;+!Microsoft.Performance#CA1813;+!Microsoft.Performance#CA1823;+!Microsoft.Performance#CA1800;+!Microsoft.Performance#CA1805;+!Microsoft.Performance#CA1810;+!Microsoft.Performance#CA1824;+!Microsoft.Performance#CA1822;+!Microsoft.Performance#CA1815;+!Microsoft.Performance#CA1814;+!Microsoft.Performance#CA1819;+!Microsoft.Performance#CA1821;+!Microsoft.Performance#CA1804;+!Microsoft.Performance#CA1820;+!Microsoft.Performance#CA1802;+!Microsoft.Portability#CA1903;+!Microsoft.Portabi
lity#CA1901;+!Microsoft.Portability#CA1900;+!Microsoft.Reliability#CA2001;+!Microsoft.Reliability#CA2002;+!Microsoft.Reliability#CA2003;+!Microsoft.Reliability#CA2004;+!Microsoft.Reliability#CA2006;+!Microsoft.Security#CA2116;+!Microsoft.Security#CA2117;+!Microsoft.Security#CA2105;+!Microsoft.Security#CA2115;+!Microsoft.Security#CA2102;+!Microsoft.Security#CA2104;+!Microsoft.Security#CA2122;+!Microsoft.Security#CA2114;+!Microsoft.Security#CA2123;+!Microsoft.Security#CA2111;+!Microsoft.Security#CA2108;+!Microsoft.Security#CA2107;+!Microsoft.Security#CA2103;+!Microsoft.Security#CA2118;+!Microsoft.Security#CA2109;+!Microsoft.Security#CA2119;+!Microsoft.Security#CA2106;+!Microsoft.Security#CA2112;+!Microsoft.Security#CA2120;+!Microsoft.Security#CA2121;+!Microsoft.Security#CA2126;+!Microsoft.Security#CA2124;+!Microsoft.Security#CA2127;+!Microsoft.Security#CA2128;+!Microsoft.Security#CA2129;+!Microsoft.Usage#CA2243;+!Microsoft.Usage#CA2236;+!Microsoft.Usage#CA1816;+!Microsoft.Usag
e#CA2227;+!Microsoft.Usage#CA2213;+!Microsoft.Usage#CA2216;+!Microsoft.Usage#CA2214;+!Microsoft.Usage#CA2222;+!Microsoft.Usage#CA1806;+!Microsoft.Usage#CA2217;+!Microsoft.Usage#CA2212;+!Microsoft.Usage#CA2219;+!Microsoft.Usage#CA2201;+!Microsoft.Usage#CA2228;+!Microsoft.Usage#CA2221;+!Microsoft.Usage#CA2220;+!Microsoft.Usage#CA2240;+!Microsoft.Usage#CA2229;+!Microsoft.Usage#CA2238;+!Microsoft.Usage#CA2207;+!Microsoft.Usage#CA2208;+!Microsoft.Usage#CA2235;+!Microsoft.Usage#CA2237;+!Microsoft.Usage#CA2232;+!Microsoft.Usage#CA2223;+!Microsoft.Usage#CA2211;+!Microsoft.Usage#CA2233;+!Microsoft.Usage#CA2225;+!Microsoft.Usage#CA2226;+!Microsoft.Usage#CA2231;+!Microsoft.Usage#CA2224;+!Microsoft.Usage#CA2218;+!Microsoft.Usage#CA2234;+!Microsoft.Usage#CA2239;+!Microsoft.Usage#CA2200;+!Microsoft.Usage#CA1801;+!Microsoft.Usage#CA2242;+!Microsoft.Usage#CA2205;+!Microsoft.Usage#CA2230;+!Wintellect.DesignRules#Wintellect2002;+!Wintellect.DesignRules#Wintellect2001;+!Wintellect.DesignRules#
Wintellect2003;+!Wintellect.DesignRules#Wintellect2004;+!Wintellect.DesignRules#Wintellect2000;+!Wintellect.DesignRules#Wintellect2006;+!Wintellect.DesignRules#Wintellect2005;+!Wintellect.DesignRules#Wintellect2007;+!Wintellect.PerformanceRules#Wintellect1000;+!Wintellect.UsageRules#Wintellect3000;+!Wintellect.UsageRules#Wintellect3003;+!Wintellect.UsageRules#Wintellect3002;+!Wintellect.UsageRules#Wintellect3005;+!Wintellect.UsageRules#Wintellect3004;+!Wintellect.UsageRules#Wintellect3001</CodeAnalysisRules>
+ <DocumentationFile>
+ </DocumentationFile>
+ <RunCodeAnalysis>true</RunCodeAnalysis>
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="ArgParser.cs" />
+ <Compile Include="Constants.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>Constants.resx</DependentUpon>
+ </Compile>
+ <Compile Include="GlobalSuppressions.cs" />
+ <Compile Include="Main.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="ParaffinArgParser.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="Constants.resx">
+ <SubType>Designer</SubType>
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Constants.Designer.cs</LastGenOutput>
+ </EmbeddedResource>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Wintellect.SNK" />
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 2.0 %28x86%29</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+ <Visible>False</Visible>
+ <ProductName>Windows Installer 3.1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <ItemGroup>
+ <CodeAnalysisDictionary Include="WintellectDictionary.xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="Features.xml">
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ </Content>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
\ No newline at end of file
Added: trunk/Installer/Support/Paraffin/Paraffin.sln
===================================================================
--- trunk/Installer/Support/Paraffin/Paraffin.sln (rev 0)
+++ trunk/Installer/Support/Paraffin/Paraffin.sln 2012-04-22 12:47:10 UTC (rev 6585)
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Paraffin", "Paraffin.csproj", "{69CEBB42-4C4B-4546-9DEE-A5183E989214}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {69CEBB42-4C4B-4546-9DEE-A5183E989214}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {69CEBB42-4C4B-4546-9DEE-A5183E989214}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {69CEBB42-4C4B-4546-9DEE-A5183E989214}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {69CEBB42-4C4B-4546-9DEE-A5183E989214}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
Added: trunk/Installer/Support/Paraffin/ParaffinArgParser.cs
===================================================================
--- trunk/Installer/Support/Paraffin/ParaffinArgParser.cs (rev 0)
+++ trunk/Installer/Support/Paraffin/ParaffinArgParser.cs 2012-04-22 12:47:10 UTC (rev 6585)
@@ -0,0 +1,439 @@
+/*------------------------------------------------------------------------------
+ * Copyright © 2007 John Robbins -- All rights reserved.
+ -----------------------------------------------------------------------------*/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Diagnostics;
+using System.IO;
+using System.Diagnostics.CodeAnalysis;
+
+namespace Wintellect.Paraffin
+{
+ internal class ParaffinArgParser : ArgParser
+ {
+ #region Required Creation Parameters
+ /// <summary>
+ /// The directory to process.
+ /// </summary>
+ public String StartDirectory { get; set; }
+
+ /// <summary>
+ /// The custom value to put on all components/files/dirs.
+ /// </summary>
+ public String CustomValue { get; set; }
+
+ #endregion
+
+ #region Optional Creation Parameters
+ /// <summary>
+ /// Override the DirectoryRef Id if you want the fragment files
+ /// to go somewhere esle besides the INSTALLDIR.
+ /// </summary>
+ public String DirectoryRef { get; set; }
+
+ /// <summary>
+ /// The value to replace the starting directory in the File element
+ /// src attribute.
+ /// </summary>
+ public String Alias { get; set; }
+
+ /// <summary>
+ /// If true, all the files in a directory will be included into a
+ /// single component.
+ /// </summary>
+ public Boolean MultipleFilesPerComponent { get; set; }
+
+ /// <summary>
+ /// The list of extensions to skip.
+ /// </summary>
+ public Dictionary<String , Boolean> ExtensionList { get; set; }
+
+ /// <summary>
+ /// If true, GUIDs will be generated for all components.
+ /// </summary>
+ public Boolean GenerateGuids { get; set; }
+
+ /// <summary>
+ /// The amount to add to each component number to leave room for
+ /// additional component files between directories.
+ /// </summary>
+ public Int32 IncrementValue { get; set; }
+
+ /// <summary>
+ /// If true, does not recurse the directories.
+ /// </summary>
+ public Boolean NoDirectoryRecursion { get; set; }
+
+ /// <summary>
+ /// The list of directories to exclude from the processing.
+ /// </summary>
+ public List<String> DirectoryExcludeList { get; set; }
+
+ /// <summary>
+ /// If true, adds the Win64 attribute to components.
+ /// </summary>
+ public Boolean Win64 { get; set; }
+ #endregion
+
+ /// <summary>
+ /// True if the user wants to update a previously created file.
+ /// </summary>
+ public Boolean Update { get; set; }
+
+ /// <summary>
+ /// The output filename.
+ /// </summary>
+ public String FileName { get; set; }
+
+ // The private string to hold more detailed error information.
+ private String errorMessage;
+ // Indicates the error was found in OnDoneParse.
+ private Boolean errorInOnDoneParse;
+ // Indicates we've already seen the -inc switch.
+ private Boolean seenIncrementSwitch;
+
+ #region Command Line Option Constants
+ private const string k_HELP_QUESTION = "?";
+ private const string k_HELP_SHORT = "h";
+ private const string k_HELP = "help";
+ private const string k_GUIDS = "guids";
+ private const string k_GUIDS_SHORT = "g";
+ private const string k_ALIAS = "alias";
+ private const string k_ALIAS_SHORT = "a";
+ private const string k_MULTIPLE = "multiple";
+ private const string k_MULTIPLE_SHORT = "m";
+ private const string k_NORECURSE = "norecurse";
+ private const string k_NORECURSE_SHORT = "nr";
+ private const string k_DIR = "dir";
+ private const string k_DIR_SHORT = "d";
+ private const string k_CUSTOM = "custom";
+ private const string k_CUSTOM_SHORT = "c";
+ private const string k_EXT = "ext";
+ private const string k_EXT_SHORT = "e";
+ private const string k_DIREXCLUDE = "direXclude";
+ private const string k_DIREXCLUDE_SHORT = "x";
+ private const string k_INC = "inc";
+ private const string k_INC_SHORT = "i";
+ private const string k_UPDATE = "update";
+ private const string k_UPDATE_SHORT = "u";
+ private const string k_WIN64 = "win64";
+ private const string k_DIRREF = "dirref";
+ private const string k_DIRREF_SHORT = "dr";
+ #endregion
+
+ public ParaffinArgParser ( )
+ : base ( new String [] { k_HELP_QUESTION , k_HELP_SHORT , k_HELP ,
+ k_GUIDS_SHORT , k_GUIDS ,
+ k_MULTIPLE_SHORT , k_MULTIPLE ,
+ k_NORECURSE_SHORT , k_NORECURSE ,
+ k_UPDATE_SHORT , k_UPDATE ,
+ k_WIN64 } ,
+ new String [] { k_DIR_SHORT , k_DIR ,
+ k_CUSTOM_SHORT , k_CUSTOM ,
+ k_ALIAS_SHORT , k_ALIAS ,
+ k_EXT_SHORT , k_EXT ,
+ k_INC_SHORT , k_INC ,
+ k_DIREXCLUDE_SHORT , k_DIREXCLUDE ,
+ k_DIRREF , k_DIRREF_SHORT } ,
+ true )
+ {
+ // Set all the appropriate defaults.
+ FileName = String.Empty;
+ StartDirectory = String.Empty;
+ CustomValue = String.Empty;
+ Alias = String.Empty;
+ DirectoryRef = String.Empty;
+ MultipleFilesPerComponent = false;
+ ExtensionList = new Dictionary<String , Boolean> ( );
+ GenerateGuids = false;
+ IncrementValue = 1;
+ DirectoryExcludeList = new List<String> ( );
+
+ errorMessage = String.Empty;
+ }
+
+ [SuppressMessage ( "Microsoft.Maintainability" ,
+ "CA1502:AvoidExcessiveComplexity" ,
+ Justification =
+ "A switch statement using strings always generates complexity." )]
+ protected override SwitchStatus OnSwitch ( string switchSymbol ,
+ string switchValue )
+ {
+ SwitchStatus ss = SwitchStatus.NoError;
+ switch ( switchSymbol )
+ {
+ case k_HELP_QUESTION:
+ case k_HELP_SHORT:
+ case k_HELP:
+ ss = SwitchStatus.ShowUsage;
+ break;
+
+ case k_GUIDS_SHORT:
+ case k_GUIDS:
+ GenerateGuids = true;
+ break;
+
+ case k_MULTIPLE_SHORT:
+ case k_MULTIPLE:
+ MultipleFilesPerComponent = true;
+ break;
+
+ case k_NORECURSE_SHORT:
+ case k_NORECURSE:
+ NoDirectoryRecursion = true;
+ break;
+
+ case k_UPDATE_SHORT:
+ case k_UPDATE:
+ Update = true;
+ break;
+
+ case k_WIN64:
+ Win64 = true;
+ break;
+
+ case k_ALIAS_SHORT:
+ case k_ALIAS:
+ if ( false == String.IsNullOrEmpty ( Alias ) )
+ {
+ errorMessage = Constants.AliasMultipleSwitches;
+ ss = SwitchStatus.Error;
+ }
+ else
+ {
+ // If the alias does not end with a \, add one to help
+ // the user out.
+ if ( false == switchValue.EndsWith ( "\\" ,
+ StringComparison.OrdinalIgnoreCase ) )
+ {
+ switchValue += "\\";
+ }
+ Alias = switchValue;
+ }
+ break;
+
+
+ case k_DIRREF_SHORT:
+ case k_DIRREF:
+ if ( false == String.IsNullOrEmpty ( DirectoryRef ) )
+ {
+ errorMessage = Constants.DirectoryRefMultipleSwitches;
+ ss = SwitchStatus.Error;
+ }
+ else
+ {
+ DirectoryRef = switchValue;
+ }
+ break;
+
+ case k_DIR_SHORT:
+ case k_DIR:
+ if ( false == String.IsNullOrEmpty ( StartDirectory ) )
+ {
+ errorMessage = Constants.DirectoryMultipleSwitches;
+ ss = SwitchStatus.Error;
+ }
+ else if ( true == String.IsNullOrEmpty ( switchValue ) )
+ {
+ errorMessage = Constants.DirectoryCannotBeEmpty;
+ ss = SwitchStatus.Error;
+ }
+ else
+ {
+ // If the directory does not end with a \, add one.
+ if ( false == switchValue.EndsWith ( "\\" ,
+ StringComparison.OrdinalIgnoreCase ) )
+ {
+ switchValue += "\\";
+ }
+ StartDirectory = switchValue;
+ }
+ break;
+
+ case k_CUSTOM_SHORT:
+ case k_CUSTOM:
+ if ( false == String.IsNullOrEmpty ( CustomValue ) )
+ {
+ errorMessage = Constants.UniqueMultipleSwitches;
+ ss = SwitchStatus.Error;
+ }
+ else if ( true == String.IsNullOrEmpty ( switchValue ) )
+ {
+ errorMessage = Constants.UniqueCannotBeEmpty;
+ ss = SwitchStatus.Error;
+ }
+ else if ( switchValue.Length >= 65 )
+ {
+ errorMessage = Constants.UniqueTooLong;
+ ss = SwitchStatus.Error;
+ }
+ else
+ {
+ CustomValue = switchValue;
+ }
+ break;
+
+ case k_EXT_SHORT:
+ case k_EXT:
+ if ( true == String.IsNullOrEmpty ( switchValue ) )
+ {
+ errorMessage = Constants.ExtensionCannotBeEmpty;
+ ss = SwitchStatus.Error;
+ }
+ else
+ {
+ // Does it start with a period? If not, add one to help
+ // the user out.
+ if ( '.' != switchValue [ 0 ] )
+ {
+ switchValue = "." + switchValue;
+ }
+ // You can have as many -ext switches as you want.
+ ExtensionList.Add ( switchValue.ToUpperInvariant ( ) ,
+ true );
+ }
+ break;
+
+ case k_INC_SHORT:
+ case k_INC:
+ if ( true == seenIncrementSwitch )
+ {
+ errorMessage = Constants.IncrementMultipleSwitches;
+ ss = SwitchStatus.Error;
+ }
+ else
+ {
+ Int32 level = 0;
+ if ( false == Int32.TryParse ( switchValue ,
+ out level ) )
+ {
+ errorMessage = Constants.IncrementNoParse;
+ ss = SwitchStatus.Error;
+ }
+ else if ( level <= 0 )
+ {
+ errorMessage = Constants.IncrementNotZero;
+ ss = SwitchStatus.Error;
+ }
+ else
+ {
+ IncrementValue = level;
+ seenIncrementSwitch = true;
+ }
+ }
+ break;
+
+ case k_DIREXCLUDE_SHORT:
+ case k_DIREXCLUDE:
+ DirectoryExcludeList.Add ( switchValue );
+ break;
+
+ default:
+ {
+ errorMessage = Constants.UnknownCommandLineOption;
+ ss = SwitchStatus.Error;
+ }
+ break;
+ }
+ return ( ss );
+ }
+
+ protected override SwitchStatus OnNonSwitch ( string value )
+ {
+ SwitchStatus ss = SwitchStatus.NoError;
+ if ( false == String.IsNullOrEmpty ( FileName ) )
+ {
+ errorMessage = Constants.OutputAlreadySpecified;
+ ss = SwitchStatus.Error;
+ }
+ else if ( true == String.IsNullOrEmpty ( value ) )
+ {
+ errorMessage = Constants.OutputCannotBeEmpty;
+ ss = SwitchStatus.Error;
+ }
+ else
+ {
+ FileName = value;
+ }
+
+ // There are no non switches allowed.
+ errorMessage = Constants.UnknownCommandLineOption;
+ return ( ss );
+ }
+
+ protected override SwitchStatus OnDoneParse ( )
+ {
+ SwitchStatus ss = SwitchStatus.NoError;
+ // The output file can never be null.
+ if ( true == string.IsNullOrEmpty ( FileName ) )
+ {
+ errorMessage = Constants.OutputCannotBeEmpty;
+ ss = SwitchStatus.Error;
+ errorInOnDoneParse = true;
+ }
+ else if ( false == Update )
+ {
+ // Check that I at least have a directory and prefix. Everything
+ // else is optional when updating files.
+ if ( true == String.IsNullOrEmpty ( StartDirectory ) )
+ {
+ errorMessage = Constants.DirectoryCannotBeEmpty;
+ ss = SwitchStatus.Error;
+ errorInOnDoneParse = true;
+ }
+ else if ( false == Directory.Exists ( StartDirectory ) )
+ {
+ errorMessage = Constants.DirectoryDoesNotExist;
+ ss = SwitchStatus.Error;
+ errorInOnDoneParse = true;
+ }
+ else if ( true == String.IsNullOrEmpty ( CustomValue ) )
+ {
+ errorMessage = Constants.UniqueCannotBeEmpty;
+ ss = SwitchStatus.Error;
+ errorInOnDoneParse = true;
+ }
+ }
+ else
+ {
+ // The user is asking to update.
+ // Check that they didn't also specify creation options.
+ if ( ( false == String.IsNullOrEmpty ( StartDirectory ) ||
+ ( false == String.IsNullOrEmpty ( CustomValue ) ) ) )
+ {
+ errorMessage = Constants.MutuallyExclusiveOptions;
+ ss = SwitchStatus.Error;
+ errorInOnDoneParse = true;
+ }
+ // Check to at least see if the file exists.
+ if ( false == File.Exists ( FileName ) )
+ {
+ errorMessage = Constants.UpdateFileMustExist;
+ ss = SwitchStatus.Error;
+ errorInOnDoneParse = true;
+ }
+ }
+ return ( ss );
+ }
+
+ public override void OnUsage ( string errorInfo )
+ {
+ ProcessModule exe = Process.GetCurrentProcess ( ).Modules [ 0 ];
+ Console.WriteLine ( Constants.UsageString ,
+ exe.FileVersionInfo.FileVersion );
+ if ( ( false == errorInOnDoneParse ) &&
+ ( false == String.IsNullOrEmpty ( errorInfo ) ) )
+ {
+ Console.WriteLine ( );
+ Console.WriteLine ( Constants.ErrorSwitch , errorInfo );
+ }
+ if ( false == String.IsNullOrEmpty ( errorMessage ) )
+ {
+ Console.WriteLine ( );
+ Console.WriteLine ( errorMessage );
+ }
+ }
+ }
+}
Property changes on: trunk/Installer/Support/Paraffin/Properties
___________________________________________________________________
Added: bugtraq:number
+ true
Added: trunk/Installer/Support/Paraffin/Properties/AssemblyInfo.cs
===================================================================
--- trunk/Installer/Support/Paraffin/Properties/AssemblyInfo.cs (rev 0)
+++ trunk/Installer/Support/Paraffin/Properties/AssemblyInfo.cs 2012-04-22 12:47:10 UTC (rev 6585)
@@ -0,0 +1,41 @@
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Resources;
+
+[assembly: CLSCompliant ( true )]
+[assembly: NeutralResourcesLanguage ( "en-US" )]
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle ( "Paraffin" )]
+[assembly: AssemblyDescription ( "A better TALLOW for creating WiX fragments" )]
+[assembly: AssemblyConfiguration ( "" )]
+[assembly: AssemblyCompany ( "Wintellect" )]
+[assembly: AssemblyProduct ( "Paraffin" )]
+[assembly: AssemblyCopyright ( "Copyright © John Robbins 2007-2008" )]
+[assembly: AssemblyTrademark ( "" )]
+[assembly: AssemblyCulture ( "" )]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible ( false )]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid ( "c3298ef9-1922-4e6b-9da6-6c4f644aa5a5" )]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion ( "3.0.0.0" )]
+[assembly: AssemblyFileVersion ( "3.0.0.0" )]
Added: trunk/Installer/Support/Paraffin/Wintellect.SNK
===================================================================
(Binary files differ)
Property changes on: trunk/Installer/Support/Paraffin/Wintellect.SNK
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: trunk/Installer/Support/Paraffin/WintellectDictionary.xml
===================================================================
--- trunk/Installer/Support/Paraffin/WintellectDictionary.xml (rev 0)
+++ trunk/Installer/Support/Paraffin/WintellectDictionary.xml 2012-04-22 12:47:10 UTC (rev 6585)
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<Dictionary>
+ <Words>
+ <Unrecognized>
+ </Unrecognized>
+ <Recognized>
+ <Word>Wintellect</Word>
+ <Word>Validators</Word>
+ <Word>Automator</Word>
+ <Word>mscorwks</Word>
+ <Word>plugin</Word>
+ <Word>minidump</Word>
+ <Word>loadby</Word>
+ <Word>dmp</Word>
+ <Word>pid</Word>
+ <Word>comspec</Word>
+ <Word>Hhc</Word>
+ <Word>Sln</Word>
+ <Word>Ini</Word>
+ <Word>Perf</Word>
+ <Word>Turnon</Word>
+ <Word>Vss</Word>
+ <Word>Wix</Word>
+ <Word>stdafx</Word>
+ <Word>Impl</Word>
+ <Word>Visualizers</Word>
+ <Word>Visualizer</Word>
+ <Word>guids</Word>
+ <Word>GUIDs</Word>
+ <Word>blogs</Word>
+ <Word>jrobbins</Word>
+ <Word>sourceforge</Word>
+ <Word>norecurse</Word>
+ <Word>recursing</Word>
+ <Word>Xclude</Word>
+ <Word>exdir</Word>
+ <Word>Bugslayer</Word>
+ <Word>Autogenerated</Word>
+ <Word>src</Word>
+ <Word>dirref</Word>
+ </Recognized>
+ <Deprecated>
+ </Deprecated>
+ <Compound>
+ </Compound>
+ <DiscreteExceptions>
+ </DiscreteExceptions>
+ </Words>
+ <Acronyms>
+ <CasingExceptions>
+ </CasingExceptions>
+ </Acronyms>
+</Dictionary>
More information about the mapguide-commits
mailing list