Self Extracting Zip support

Jun 4, 2008 at 1:47 AM
I filed a work item for this but thought I'd drop a note in here as well: I'd like to volunteer to add self-extracting zip support to the library. If this is something you're interested in, please let me know so we can collaborate.

Thanks,
Erik
Coordinator
Jun 4, 2008 at 8:25 PM

Cool, I Was just thinking that self-extracting zips would be a nice feature to add.

ok, you have the source code.  Have you got something worked up already? Got a design or a plan or a prototype?

 

Jun 5, 2008 at 2:25 AM
Not really - I was hoping to collaborate on one. I have a few ideas, and I've been looking through the source, and I think I get where you're going with it - but I'd rather not second-guess you - it is your project after all. ;)

If you like we can talk on AIM (esforbes) or Yahoo (dzcepheus) - feel free to contact me any time and we'll talk. =)
Coordinator
Jun 6, 2008 at 9:43 PM
here's the thing.  a self-extracting zip file is really just an EXE with some boilerplate extract logic (maybe a SelfExtractor class), bundled with the actual zip file embedded as a resource in the exe.

How would this work?
One way to do it:  run the exe and the Main() method in the SelfExtractor runs.  It slurps in the zip archive from the resource manager, like any embedded resource - resourceManager.GetObject("EmbeddedZipStream");.  This resource can emerge as a byte[], and there is a ZipFile constructor that accepts a byte[].  Now it has an instance of ZipFile.  The SelfExtractor pops up a window saying "I am a self extracting zip, do you want to extract the files?" and allows the user to OK/Cancel, and also specify the target extract directory.

Then if OK, the logic just calls ZipFile.ExtractAll() or whatever on the zip stream. 
There are some special cases for passwords I guess. And you might want a command-line-only mode, too.

To get this to work you could: 
  1. build the extraction logic (SelfExtractor class).  Manually embed a zip archive as a resource into the assembly.  Test out the model I described above.  This would validate the model.
  2. build the logic in ZipFile to save to a self-extracting-exe.  Probably a new method called SaveToSfx().  Within that method, you would use Reflection.Emit() to generate the code that you validated in step 1, and you'd have to save the generated assembly.  You will have to find the magic incantation that will allow you to programmatically embed a resource into the generated assembly.
  3. Finally, embed the Ionic.Utils.Zip.dll itself as a resource in the Self-extracting-zip, and then there would have to be some magic assembly-loading logic that loads that Zip assembly from the resource, and then is able to call into it.  I don't know if this would work, but one idea is here: http://blog.magenic.com/blogs/brante/archive/2008/04/14/Embedded-Assembly-Linker.aspx 

The resulting generated assembly would run on any platform that has the .NET Framework 2.0 on it. 
The extracting machine would not need to have the Ionic.Utils.Zip.dll assembly installed on it, because that assembly would be distributed (embedded) in the self-extracting-zip itself.

what do you think ?

 

Coordinator
Jun 7, 2008 at 1:00 AM
ok, I built a prototype utility that creates self-extracting zip files from existing zip files. It follows the design I outlined above, with embedded library and zip archive.
It is categorized as an example in the source tree.  
See changeset 19730 for the source. 

You can also download the utility itself, from the v1.5 preview release.
http://www.codeplex.com/Release/ProjectReleases.aspx?ProjectName=DotNetZip&ReleaseId=12712


Eventually I will update the library to include this capability.  Check it out.
It does basic stuff, but there are rough edges:
  • It doesn't handle zips with passwords well.
  • It is not tested extensively

But it illustrates the idea.

Jun 7, 2008 at 3:07 AM
Well damn. =P You pre-empted me. =)

How would you like me to submit changes?
Coordinator
Jun 7, 2008 at 4:53 PM
Sorry about the pre-emption.
I wrote up what CreateSelfExtractor.cs does in the file comments.  Basically, CreateSelfExtractor.exe is an assembly that has source code embedded into it.  The source code is the logic for the self-extractor.  There are two flavors, the Windows GUI extractor, and the command-line extractor.  At runtime CreateSelfExtractor.exe compiles that source code into a new assembly (the self extracting zip it is creating)  and then embeds within that new assembly, the zip archive itself.  The result is an exe with extract logic in it, as well as a zip file. 

Now I will fold the logic currently in the CreateSelfExtractor.cs file into a SaveAsSfx() method on the ZipFile class.  Actually there might be more than one method because sometimes ya might wanna save it to a stream. so... SaveAsSfx(string filename) and SaveAsSfx(stream outstream).   I'll have to do some project surgery too, to embed the source-code-as-resources into the DLL. 


Jun 7, 2008 at 8:02 PM
No problem. =) It happens - at least I contributed by prompting the work, even if I didn't do it myself. ;)
Coordinator
Jun 7, 2008 at 8:59 PM
Edited Jun 8, 2008 at 1:58 AM
Ok, I put it in the library.  It should be usable now. 
Get the v1.5 preview. 

With this change, the size of the DLL went from ~50k to ~210k.
Yikes!

It is the resources for the WinForms graphical stuff.  No way to compress them further, I tried.
Jun 8, 2008 at 12:27 AM
Compression, nice. =P Grabbing the update now from svn.
Sep 11, 2008 at 5:13 AM
Hi!

I have just tried to build the DotNetZip 1.5.1.1 release using the Framework 2.0 SDK, and it won't build due to a compilation error. The errors reported are:

ZipFile.SaveSelfExtractor.cs(88,37): error CS1513: } expected
ZipFile.SaveSelfExtractor.cs(89,24): error CS1519: Invalid token '=' in class, struct, or interface member declaration
ZipFile.SaveSelfExtractor.cs(89,65): error CS1519: Invalid token ',' in class, struct, or interface member declaration
ZipFile.SaveSelfExtractor.cs(90,37): error CS1519: Invalid token '=' in class, struct, or interface member declaration
ZipFile.SaveSelfExtractor.cs(90,55): error CS1519: Invalid token '{' in class, struct, or interface member declaration
ZipFile.SaveSelfExtractor.cs(91,84): error CS0116: A namespace does not directly contain members such as fields or methods
ZipFile.SaveSelfExtractor.cs(92,44): error CS1518: Expected class, delegate, enum, interface, or struct
ZipFile.SaveSelfExtractor.cs(95,42): error CS1518: Expected class, delegate, enum, interface, or struct
ZipFile.SaveSelfExtractor.cs(101,14): error CS0116: A namespace does not directly contain members such as fields or methods
ZipFile.SaveSelfExtractor.cs(102,17): error CS1518: Expected class, delegate, enum, interface, or struct
ZipFile.SaveSelfExtractor.cs(106,42): error CS1518: Expected class, delegate, enum, interface, or struct
ZipFile.SaveSelfExtractor.cs(107,13): error CS1022: Type or namespace definition, or end-of-file expected

I'm not an experienced C# developer, so I am not sure what the problem is or how to fix it.

Any help would be greatly appreciated!

Thanks,
David


Coordinator
Sep 11, 2008 at 5:32 PM

David, you should use the .NET Framework 3.5 SDK.  The 2.0 SDK is from 2005.  You should update anyway, even if you don't care about building DotNetZip.  The 3.5 SDK, like the 2.0 SDK, is a free download. 

Get the 3.5 SDK here:  http://www.microsoft.com/downloads/details.aspx?FamilyID=e6e1c3df-a74f-4207-8586-711ebe331cdc&DisplayLang=en

In fact, I don't know how you would be building it with the .NET 2.0 SDK; when I try this with Msbuild from the .NET 2.0 SDK, I get this error:

c:\Desktop\zip\DotNetZip>msbuild
Microsoft (R) Build Engine Version 2.0.50727.3053
[Microsoft .NET Framework, Version 2.0.50727.3053]
Copyright (C) Microsoft Corporation 2005. All rights reserved.
.\DotNetZip.sln(2): Solution file error MSB5014: File format version is not recognized. MSBuild can only read solution files between versions 7.0 and 9.0, inclusive.

The DotNetZip.sln file is a v10 solution file. So... msbuild from the .net 2.0 SDK isn't going to work.

by the way, the first error in your compile points to a line in the source code that uses an array initializer, a syntax that was first introduced with the C# 3.0 compiler. That would be line 88 in ZipFile.SaveSelfExtractor.cs . That is why your v2.0 compiler is choking on the compile.

Sep 11, 2008 at 11:52 PM
Hi there,

I'm sorry to hear that Framework 2.0 is not supported any more, as we are stuck with that at the current time. Or do you mean that I can build with SDK 3.5 and run on Framework 2.0? Your Readme.txt file states:


Pre-requisites
---------------------------------

to run:
.NET Framework 2.0 or later

to build:
.NET Framework 2.0 SDK or later
or
Visual Studio 2008 or later


As for being able to build at all, I just followed the instructions in the Readme.txt file as, of course, everyone ;-) does. (cd to library directory and run msbuild).

No doubt we will upgrade to 3.5 sooner or later. In the mean time, can I build with 3.5 and deploy to 2.0? Or is that too much trouble and should I just find an older version of DotNetZip?

Thanks,
David




Coordinator
Sep 12, 2008 at 2:49 PM
you can build with .NET SDK 3.5 and run on .NET 2.0.
Yes.

The 3.5 stuff used by the library is compiler (like the array initializer I mentioned) and msbuild stuff.
I do not use any post-2.0 assemblies.  I don't use WPF, WCF, or LINQ, for example. Which means at runtime, .NET 2.0 is all you need.

I obviously need to update the readme.

Still I am curious that you got the msbuild.exe from 2.0 to actually compile that solution file.
When I try it, msbuild chokes before I get to the compilation part.

You could try excluding the Self-Extracting stuff (just the one module).  Edit the .csproj file to eliminate that module, then try to build again. I think that all of my C# 3.0 compiler stuff is limited to the Self-Extractor module.
I may be wrong about that.

Sep 15, 2008 at 12:16 AM
Many thanks, Cheeso. I was able to build the library with 3.5.

Interestingly, when I went to install Framework 3.5, it offered a repair/uninstall option. I suspect that a previous installation of Visual C# Express 2008 was not completely gone. That could explain how I got further than you thought I should have been able to get!

Cheers,
David