CommandLineSelfExtractorStub.cs :  » Development » DotNetZip » Ionic » Zip » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Development » DotNetZip 
DotNetZip » Ionic » Zip » CommandLineSelfExtractorStub.cs
// CommandLineSelfExtractorStub.cs
// ------------------------------------------------------------------
//
// Copyright (c)  2008, 2009 Dino Chiesa.  
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License. 
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs): 
// Time-stamp: <2009-October-27 06:54:42>
//
// ------------------------------------------------------------------
//
// This is a the source module that implements the stub of a
// command-line self-extracting Zip archive - the code included in all
// command-line SFX files.  This code is included as a resource into the
// DotNetZip DLL, and then is compiled at runtime when a SFX is saved. 
//
// ------------------------------------------------------------------


namespace Ionic.Zip{
    // include the using statements inside the namespace decl, because
    // source code will be concatenated together before compilation. 
    using System;
    using System.Reflection;
    using System.Resources;
    using System.IO;
    using System.Collections.Generic;
    using System.Diagnostics;
    using Ionic.Zip;

    public class CommandLineSelfExtractor
    {
        const string DllResourceName = "Ionic.Zip.dll";

        string TargetDirectory = "@@EXTRACTLOCATION";
        string PostUnpackCmdLine = "@@POST_UNPACK_CMD_LINE";
        bool ReplacedEnvVarsForTargetDirectory;
        bool ReplacedEnvVarsForCmdLine;
        bool ListOnly;
        bool Verbose;
        bool ReallyVerbose;
        bool RemoveFilesAfterExe;
        bool SkipPostUnpackCommand;
        string Password = null;
        //Ionic.Zip.ExtractExistingFileAction Overwrite;   // cannot do - because of tricks with assembly resolution
        int Overwrite; 

        // Attention: it isn't possible, with the design  of this class as it is now, to have a
        // member variable of a type from the Ionic.Zip assembly.  The class design registers
        // an assembly resolver, but apparently NOT in time to allow the assembly to be used
        // in private instance variables. 
        
        private bool PostUnpackCmdLineIsSet()
        {
            // What is going on here?
            // The PostUnpackCmdLine is initialized to a particular value, then
            // we test to see if it begins with the first two chars of that value,
            // and ends with the last part of the value.  Why?

            // Here's the thing.  In order to insure the code is right, this module has
            // to compile as it is, as a standalone module.  But then, inside
            // DotNetZip, when generating an SFX, we do a text.Replace on the source
            // code, potentially replacing @@POST_UNPACK_CMD_LINE with an actual value.
            // The test here checks to see if it has been set. 

            bool result = !(PostUnpackCmdLine.StartsWith("@@") && 
                     PostUnpackCmdLine.EndsWith("POST_UNPACK_CMD_LINE"));

            if (result && ReplacedEnvVarsForCmdLine == false)
            {
                PostUnpackCmdLine= ReplaceEnvVars(PostUnpackCmdLine);
                ReplacedEnvVarsForCmdLine = true;
            }
            
            return result;
        }


        private bool TargetDirectoryIsSet()
        {
            bool result = !(TargetDirectory.StartsWith("@@") && 
                     TargetDirectory.EndsWith("EXTRACTLOCATION"));

            if (result && ReplacedEnvVarsForTargetDirectory == false)
            {
                TargetDirectory= ReplaceEnvVars(TargetDirectory);
                ReplacedEnvVarsForTargetDirectory = true;
            }
            return result;
        }



        private string ReplaceEnvVars(string s)
        {
            System.Collections.IDictionary envVars = Environment.GetEnvironmentVariables();
            foreach (System.Collections.DictionaryEntry de in envVars)
            {
                string t = "%" + de.Key + "%";
                s= s.Replace(t, de.Value as String);
            }
                
            return s;
        }

                
        private bool SetRemoveFilesFlag()
        {
            bool result = false;
            Boolean.TryParse("@@REMOVE_AFTER_EXECUTE", out result); 
            RemoveFilesAfterExe = result;
            return result;
        }


        private bool SetVerboseFlag()
        {
            bool result = false;
            Boolean.TryParse("@@QUIET", out result); 
            Verbose = !result;
            return Verbose;
        }

        private int SetOverwriteBehavior()
        {
            Int32 result = 0;
            Int32.TryParse("@@EXTRACT_EXISTING_FILE", out result); 
            Overwrite = (int) result;
            return result;
        }

        
        // ctor
        private CommandLineSelfExtractor()
        {
            SetRemoveFilesFlag();
            SetVerboseFlag();
            SetOverwriteBehavior();            
            PostUnpackCmdLineIsSet();
            TargetDirectoryIsSet();
        }

        
        // ctor
        public CommandLineSelfExtractor(string[] args) : this()
        {
            string specifiedDirectory = null;
            for (int i = 0; i < args.Length; i++)
            {
                switch (args[i])
                {
                    case "-d":
                        i++;
                        if (args.Length <= i)
                        {
                            Console.WriteLine("please supply a directory.\n");
                            GiveUsageAndExit();
                        }
                        if (specifiedDirectory != null) 
                        {
                            Console.WriteLine("You already provided a directory.\n");
                            GiveUsageAndExit();
                        }
                        specifiedDirectory = args[i];
                        break;
                    case "-p":
                        i++;
                        if (args.Length <= i)
                        {
                            Console.WriteLine("please supply a password.\n");
                            GiveUsageAndExit();
                        }
                        if (Password != null) 
                        {
                            Console.WriteLine("You already provided a password.\n");
                            GiveUsageAndExit();
                        }
                        Password = args[i];
                        break;
                    case "-o":
                        Overwrite = 1;
                        //WantOverwrite = ExtractExistingFileAction.OverwriteSilently;
                        break;
                    case "-n":
                        Overwrite= 2;
                        //WantOverwrite = ExtractExistingFileAction.DoNotOverwrite;
                        break;
                    case "-l":
                        ListOnly = true;
                        break;
                    case "-r+":
                        RemoveFilesAfterExe = true;
                        break;
                    case "-r-":
                        RemoveFilesAfterExe = false;
                        break;
                    case "-x":
                        SkipPostUnpackCommand = true;
                        break;
                    case "-?":
                        GiveUsageAndExit();
                        break;
                    case "-v-":
                        Verbose = false;
                        break;
                    case "-v+":
                        if (Verbose)
                            ReallyVerbose = true;
                        else
                            Verbose = true;
                        break;
                    default:
                        Console.WriteLine("unrecognized argument: '{0}'\n", args[i]);
                        GiveUsageAndExit();
                        break;
                }
            }


            if (!ListOnly)
            {
                if (specifiedDirectory!=null)
                    TargetDirectory = specifiedDirectory;
                else if (!TargetDirectoryIsSet())
                    TargetDirectory = ".";  // cwd
            }

            if (ListOnly && ((Overwrite!= 0) || (specifiedDirectory != null)))
            {
                Console.WriteLine("Inconsistent options.\n");
                GiveUsageAndExit();
            }
        }


        // workitem 8988
        private string[] SplitCommandLine(string cmdline)
        {
            // if the first char is NOT a double-quote, then just split the line
            if (cmdline[0]!='"')
                return cmdline.Split( new char[] {' '}, 2);

            // the first char is double-quote.  Need to verify that there's another one. 
            int ix = cmdline.IndexOf('"', 1);
            if (ix == -1) return null;  // no double-quote - FAIL

            // if the double-quote is the last char, then just return an array of ONE string
            if (ix+1 == cmdline.Length) return new string[] { cmdline.Substring(1,ix-1) };
            
            if (cmdline[ix+1]!= ' ') return null; // no space following the double-quote - FAIL

            // there's definitely another double quote, followed by a space
            string[] args = new string[2];
            args[0] = cmdline.Substring(1,ix-1);
            while (cmdline[ix+1]==' ') ix++;  // go to next non-space char
            args[1] = cmdline.Substring(ix+1);
            return args;
        }

        
        static CommandLineSelfExtractor()
        {
            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(Resolver);
        }


        static System.Reflection.Assembly Resolver(object sender, ResolveEventArgs args)
        {
            // super defensive
            Assembly a1 = Assembly.GetExecutingAssembly();
            if (a1==null)
                throw new Exception("GetExecutingAssembly returns null.");

            string[] tokens = args.Name.Split(',');
            
            String[] names = a1.GetManifestResourceNames();
            
            if (names==null)
                throw new Exception("GetManifestResourceNames returns null.");

            // workitem 7978
            Stream s = null;
            foreach (string n in names)
            {
                string root = n.Substring(0,n.Length-4);
                string ext = n.Substring(n.Length-3);
                if (root.Equals(tokens[0])  && ext.ToLower().Equals("dll"))
                {
                    s= a1.GetManifestResourceStream(n);
                    if (s!=null) break;
                }
            }
            
            if (s==null)
                throw new Exception(String.Format("GetManifestResourceStream returns null. Available resources: [{0}]",
                                                  String.Join("|", names)));

            byte[] block = new byte[s.Length];
            
            if (block==null)
                throw new Exception(String.Format("Cannot allocated buffer of length({0}).", s.Length));

            s.Read(block, 0, block.Length);
            Assembly a2 = Assembly.Load(block);
            if (a2==null)
                throw new Exception("Assembly.Load(block) returns null");
            
            return a2;
        }


        
        public int Run()
        {
            //System.Diagnostics.Debugger.Break();

            List<String> itemsExtracted= new List<String>();
            
            global::Ionic.Zip.ExtractExistingFileAction WantOverwrite =
                (Ionic.Zip.ExtractExistingFileAction) Overwrite;

            // There way this works:  the EXE is a ZIP file.  So
            // read from the location of the assembly, in other words the path to the exe. 
            Assembly a = Assembly.GetExecutingAssembly();

            int rc = 0;
            try
            {
                // workitem 7067
                using (global::Ionic.Zip.ZipFile zip = global::Ionic.Zip.ZipFile.Read(a.Location))
                {
                    if (!ListOnly)
                    {
                        if (Verbose)
                        {
                            System.Console.Write("Extracting to {0}", TargetDirectory);
                            System.Console.WriteLine(" (Existing file action: {0})", WantOverwrite.ToString());
                        }
                    }
                        
                    bool header = true;
                    foreach (global::Ionic.Zip.ZipEntry entry in zip)
                    {
                        if (ListOnly || ReallyVerbose)
                        {
                            if (header)
                            {
                                System.Console.WriteLine("Extracting Zip file: {0}", zip.Name);
                                if ((zip.Comment != null) && (zip.Comment != ""))
                                    System.Console.WriteLine("Comment: {0}", zip.Comment);

                                System.Console.WriteLine("\n{1,-22} {2,9}  {3,5}   {4,9}  {5,3} {6,8} {0}",
                                             "Filename", "Modified", "Size", "Ratio", "Packed", "pw?", "CRC");
                                System.Console.WriteLine(new System.String('-', 80));
                                header = false;
                            }

                            System.Console.WriteLine("{1,-22} {2,9} {3,5:F0}%   {4,9}  {5,3} {6:X8} {0}",
                                         entry.FileName,
                                         entry.LastModified.ToString("yyyy-MM-dd HH:mm:ss"),
                                         entry.UncompressedSize,
                                         entry.CompressionRatio,
                                         entry.CompressedSize,
                                         (entry.UsesEncryption) ? "Y" : "N",
                                         entry.Crc);

                        }

                        if (!ListOnly)
                        {
                            if (Verbose && !ReallyVerbose)
                                System.Console.WriteLine("  {0}", entry.FileName);
                                
                            if (entry.Encryption == global::Ionic.Zip.EncryptionAlgorithm.None)
                            {
                                try
                                {
                                    entry.Extract(TargetDirectory, WantOverwrite);
                                    itemsExtracted.Add(entry.FileName);
                                }
                                catch (Exception ex1)
                                {
                                    Console.WriteLine("  Error -- {0}", ex1.Message);
                                    rc++;
                                }
                            }
                            else
                            {
                                if (Password == null)
                                {
                                    Console.WriteLine("Cannot extract entry {0} without a password.", entry.FileName);
                                    rc++;
                                }
                                else
                                {
                                    try
                                    {
                                        entry.ExtractWithPassword(TargetDirectory, WantOverwrite, Password);
                                        itemsExtracted.Add(entry.FileName);
                                    }
                                    catch (Exception ex2)
                                    {
                                        Console.WriteLine("  Error -- {0}", ex2.Message);
                                        rc++;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception)
            {
                Console.WriteLine("The self-extracting zip file is corrupted.");
                return 4;
            }

            if (rc != 0) return rc;

            
            // potentially execute the embedded command
            if (PostUnpackCmdLineIsSet() && !SkipPostUnpackCommand)
            {
                if (ListOnly)
                {
                    Console.WriteLine("\nExecute on unpack: {0}", PostUnpackCmdLine);
                }
                else
                {
                    try
                    {
                        string[] args = SplitCommandLine(PostUnpackCmdLine);
                        
                        if (args!= null && args.Length > 0)
                        {
                            if (Verbose)
                                System.Console.WriteLine("Running command:  {0}", PostUnpackCmdLine);
                            
                            ProcessStartInfo startInfo = new ProcessStartInfo(args[0]);
                            startInfo.WorkingDirectory = TargetDirectory;
                            startInfo.CreateNoWindow = true;
                            if (args.Length > 1) startInfo.Arguments = args[1];

                            using (Process p = Process.Start(startInfo))
                            {
                                if (p!=null)
                                {
                                    p.WaitForExit();
                                    rc = p.ExitCode;
                                    // workitem 8925
                                    if (p.ExitCode == 0)
                                    {
                                        if (RemoveFilesAfterExe)
                                        {
                                            foreach (string s in itemsExtracted)
                                            {
                                                string fullPath = Path.Combine(TargetDirectory,s);
                                                try 
                                                {
                                                    if (File.Exists(fullPath))
                                                        File.Delete(fullPath);
                                                    else if (Directory.Exists(fullPath))
                                                        Directory.Delete(fullPath, true);
                                                }
                                                catch
                                                {
                                                }
                                            }
                                        }
                                    }                                    
                                }
                            }

                            
                        }
                    }
                    catch (Exception exc1)
                    {
                        System.Console.WriteLine("{0}", exc1);
                        rc = 5;
                    }
                    
                }
            }

            return rc;
        }


        
        private void GiveUsageAndExit()
        {
            Assembly a = Assembly.GetExecutingAssembly();
            string s = Path.GetFileName(a.Location);
            Console.WriteLine("DotNetZip Command-Line Self Extractor, see http://DotNetZip.codeplex.com/");
            Console.WriteLine("usage:\n  {0} [-p <password>] [-d <directory>]", s);

            string more = "    Extracts entries from the archive. If any files to be extracted already\n" +
                          "    exist, the program will stop.\n\n    Additional Options:\n" +
                          "{0}" +
                          "{1}" +
                          "{2}" +
                          "{3}";
            
            string overwriteString = 
                          String.Format("      -o    - overwrite any existing files upon extraction{0}.\n" +
                                        "      -n    - do not overwrite any existing files upon extraction{1}.\n",
                                        (Overwrite == 1) ? " (default)" : "",
                                        (Overwrite == 2) ? " (default)" : "");


            string removeString = PostUnpackCmdLineIsSet()
                ? String.Format("      -r+   - remove files after the optional post-unpack exe completes{0}.\n" +
                                "      -r-   - don't remove files after the optional post-unpack exe completes{1}.\n",
                                RemoveFilesAfterExe ? " (default)" : "",
                                RemoveFilesAfterExe ?  "" : " (default)")
                : "";


            string verbString = String.Format("      -v-   - turn OFF verbose messages{0}.\n"+
                                              "      -v+   - turn ON verbose messages{1}.\n",
                                              Verbose ?  "" : " (default)",
                                              Verbose ? " (default)" : "");
                
            string cmdString = PostUnpackCmdLineIsSet() 
                ? String.Format("      -x    - don't run the post-unpack exe.\n              [cmd is: {0}]\n",
                              PostUnpackCmdLine)
                : "" ;

        
            Console.WriteLine(more, overwriteString, removeString, cmdString, verbString);

            
            if (TargetDirectoryIsSet()) 
                Console.WriteLine("    default extract dir: [{0}]\n", TargetDirectory);


            Console.WriteLine("  {0} -l", s);
            Console.WriteLine("    Lists entries in the archive.");
            FreeConsole();
            Environment.Exit(1);
        }


        [STAThread]
        public static int Main(string[] args)
        {
            int left = Console.CursorLeft;
            int top = Console.CursorTop;
            bool wantPause = (left==0 && top==0);
            int rc = 0;
            try
            {
                CommandLineSelfExtractor me = new CommandLineSelfExtractor(args);
                
                // Hide my own console window if there is no parent console
                // (which means, it was launched rom explorer).
                if (!me.Verbose)
                {
                    IntPtr myHandle = Process.GetCurrentProcess().MainWindowHandle;
                    ShowWindow(myHandle, SW_HIDE);
                }
                
                rc = me.Run();
                
                // If there was an error, and this is a new console, and
                // we're still displaying the console, then do a
                // ReadLine.  This gives the user a chance to read the
                // window error messages before dismissing.
                if (rc != 0 && wantPause && me.Verbose)
                {
                    //Console.WriteLine("rc({0})  wantPause({1}) verbose({2})", rc, wantPause, me.Verbose);
                    Console.Write("<ENTER> to continue...");
                    Console.ReadLine();
                }
                
            }
            catch (System.Exception exc1)
            {
                Console.WriteLine("Exception while extracting: {0}", exc1.ToString());
                rc = 255;
            }

            FreeConsole();
            return rc;
        }

        private static readonly int SW_HIDE= 0;
        
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private static extern Boolean ShowWindow(IntPtr hWnd, Int32 nCmdShow);

        [System.Runtime.InteropServices.DllImport("kernel32.dll")]
        private static extern bool AttachConsole(int pid);
        
        [System.Runtime.InteropServices.DllImport("kernel32.dll")]
        private static extern bool AllocConsole();

        [System.Runtime.InteropServices.DllImport("kernel32.dll")]
        private static extern bool FreeConsole();

    }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.