Wednesday, March 21, 2007

C# Zip Utility using the vjslib.dll

At some time or another, everybody needs to work with zip files. Unfortunately C# has no native zip libraries. You can use third party components or even the free CSharpZip library. But what if (a) you don't want to pay for a third party component and (b) you'd prefer a simple, non-compiled solution the you can just add to single page?

The J# libraries are available and they do contain classes for the handling of zip files. These classes are contained within the vjslib.dll. All we need to do is create wrappers for the ZipOutputStream, ZipInputStream and ZipEntry. We can easily create these wrappers using system.reflection.

The answer is the single aspx file below. There is a zip class defined with three main methods, create, append and extract. These methods use the wrappers for the J# classes and allow you to manipulate the zip file.



<%@ Import Namespace="System.Diagnostics" %>
<%@ Import Namespace="System.Runtime.InteropServices" %>
<%@ Import Namespace="System.Reflection" %>
<%@ Import Namespace="System.Collections" %>
<%@ Import Namespace="System.IO" %>


<%@ Page language="C#" Debug="true" %>
<script runat="server">
/*
* ********* ********* ********* ********* *********
* REFERENCES
* http://www.codeproject.com/csharp/VmEasyZipUnZip.asp
* http://www.samspublishing.com/articles/article.asp?p=27219&seqNum=8&rl=1
* http://www.codeguru.com/forum/showthread.php?t=362530
* ********* ********* ********* ********* *********
*/
/*
* ********* ********* ********* ********* *********
* main class for handling zip files
* ********* ********* ********* ********* *********
*/
public class cZip
{
/// <summary>
/// Gets the name of the assembly from the physical path to vjslib.dll
/// </summary>
private string GetAssemblyName()
{
string path = "C:\\WINDOWS\\Microsoft.NET\\Framework\\v2.0.50727\\vjslib.dll";
Assembly a = Assembly.LoadFile(path);
return a.ToString();
}

/// <summary>
/// Extracts the contents of a zip file to the specified path, returns the list of files extracted
/// </summary>
/// <param name="virtualZip">virtual path to the zip file</param>
/// <param name="virtualPath">virtual path to extract the files to</param>
public string Extract(string virtualZip, string virtualPath)
{
StringBuilder sb = new StringBuilder();

// translate virtual paths to physical paths
string physicalZip = HttpContext.Current.Server.MapPath(virtualZip);
string physicalPath = HttpContext.Current.Server.MapPath(virtualPath);

// create objects from the java wrappers
// (wrapper source code is below)
string assemblyName = GetAssemblyName();
ZipInputStream zis = new ZipInputStream(assemblyName, physicalZip);

string title = zis.GetNextEntry();
while (title.Length != 0)
{
// append file to list
if (sb.ToString().Length > 0)
sb.Append(",");
sb.Append(virtualPath + "/" + title);

// create a BinaryWriter to write data
string file = physicalPath + "\\" + title;
System.IO.FileStream fs = System.IO.File.Open(file, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write);
System.IO.BinaryWriter br = new System.IO.BinaryWriter(fs);

sbyte[] sbuffer = new sbyte[1024];
int len = zis.Read(sbuffer);
while (len > 0)
{
byte[] buffer = ConvertToByte(sbuffer);
br.Write(buffer, 0, len);
len = zis.Read(sbuffer);
}
br.Close();
title = zis.GetNextEntry();
}
zis.Close();
return sb.ToString();
}

/// <summary>
/// Creates a zip file from a comma seperated list of virtual filenames
/// </summary>
/// <param name="virtualZip">virtual path to the zip file</param>
/// <param name="virtualFileList">comma seperated list of virtual filenames</param>
public void Create(string virtualZip, string virtualFileList)
{
// translate virtual paths to physical paths
string physicalZip = HttpContext.Current.Server.MapPath(virtualZip);

// create objects from the java wrappers
// (wrapper source code is below)
string assemblyName = GetAssemblyName();
ZipOutputStream zos = new ZipOutputStream(assemblyName, physicalZip);

string[] list = virtualFileList.Split(",".ToCharArray());
for (int i=0; i<list.Length; i++)
{
string physicalFile = HttpContext.Current.Server.MapPath(list[i]);
string title = physicalFile.Substring(physicalFile.LastIndexOf("\\") +1);

// create the Zip Entry object
ZipEntry ze = new ZipEntry(assemblyName, title);
zos.PutNextEntry(ze);

// create a BinaryReader to read data from the file that we want to add
System.IO.FileStream fs = System.IO.File.Open(physicalFile, System.IO.FileMode.Open, System.IO.FileAccess.Read);
System.IO.BinaryReader br = new System.IO.BinaryReader(fs);

// add the file to the zip, by reading the file through
// the standard C# Binary Reader and write it to the java
// ZipOutputStream
byte[] buffer = new byte[1024];
int len = br.Read(buffer, 0, 1024);

while (len>0)
{
sbyte[] sbuffer = ConvertToSByte(buffer);
zos.Write(sbuffer, 0, len);
len = br.Read(buffer, 0, 1024);
}
br.Close();
}
zos.Close();
}

/// <summary>
/// Adds one or more files to an existing zip.
/// </summary>
/// <param name="virtualZip">virtual path to the zip file</param>
/// <param name="virtualFileList">comma seperated list of virtual filenames</param>
public void Append(string virtualZip, string virtualFileList)
{
string physicalZip = HttpContext.Current.Server.MapPath(virtualZip);
string tempDir = "ZipTemp";
string list = string.Empty;
Boolean zipExists = false;

FileInfo fi = new FileInfo(physicalZip);
if (fi != null)
{
if (fi.Exists)
zipExists = true;
}

if (zipExists)
{
// to append files, we must first extract the existing files to a folder
// because every time a ZipOutputStream is created it overwrites an existing file
// so we extract to a list, append the new files, and recreate the zip
CreateFolder(tempDir);
list = Extract(virtualZip, "/" + tempDir);
if (list.Length != 0)
list += ",";
list += virtualFileList;
Create(virtualZip, list);
DeleteFolder(HttpContext.Current.Server.MapPath("/" + tempDir));
}
else
{
list = virtualFileList;
Create(virtualZip, list);
}
}

private sbyte[] ConvertToSByte(byte[] src)
{
sbyte[] dst = new sbyte[src.Length];
System.Buffer.BlockCopy(src, 0, dst, 0, src.Length);
return dst;
}
private byte[] ConvertToByte(sbyte[] src)
{
byte[] dst = new byte[src.Length];
System.Buffer.BlockCopy(src, 0, dst, 0, src.Length);
return dst;
}
private void CreateFolder(string name)
{
string physicalPath = HttpContext.Current.Server.MapPath("/");
DirectoryInfo folder = new DirectoryInfo(physicalPath);
folder.CreateSubdirectory(name);
}
private void DeleteFolder(string physicalPath)
{
DirectoryInfo folder = new DirectoryInfo(physicalPath);
foreach (DirectoryInfo subfolder in folder.GetDirectories())
DeleteFolder(subfolder.FullName);
foreach (FileInfo file in folder.GetFiles("*.*"))
{
file.Attributes = (FileAttributes.Normal);
file.Delete();
}
folder.Delete();
}
private string ToVirtualPath(string physicalPath)
{
string root = HttpContext.Current.Server.MapPath("/");
if (physicalPath.IndexOf(root) == -1)
return string.Empty;

string virtualPath = physicalPath.Replace(root, "/");
virtualPath = virtualPath.Replace("\\", "/");
return virtualPath;
}
public void ShowMethods(string className)
{
// create an instance of the object
string assemblyName = GetAssemblyName();
Assembly a = Assembly.Load(assemblyName);
Type t = a.GetType(className);

foreach(MethodInfo mi in t.GetMethods())
{
DbgWrite(mi.Name);
foreach (ParameterInfo pi in mi.GetParameters())
DbgWrite(pi.ParameterType.ToString());
}
foreach(PropertyInfo pi in t.GetProperties())
DbgWrite(pi.Name);
}
public void DbgWrite(string data)
{
HttpContext.Current.Response.Write("<div style='background-color:#cccccc'>");
HttpContext.Current.Response.Write(data);
HttpContext.Current.Response.Write("</div>");
}
}

/*
* ********* ********* ********* ********* *********
* wrapper for the java.util.zip.ZipOutputStream (late binds to object in vjslib.dll)
* NOTE: This wrapper includes the java.io.FileOutputStream which is required
* to contruct the ZipOutputStream
* ********* ********* ********* ********* *********
*/
public class ZipOutputStream : IDisposable
{
Assembly _assem;
Type _type;
object _inst;

Type _typeFileStream;
object _fileStream;

public ZipOutputStream(string assemblyName, string file)
{
_assem = Assembly.Load(assemblyName);

// create an instance of java.io.FileOutputStream
_typeFileStream = _assem.GetType("java.io.FileOutputStream");
object[] args = new object[] { file };
_fileStream = Activator.CreateInstance(_typeFileStream, args);

// create an instance of the java.util.zip.ZipOutputStream
_type = _assem.GetType("java.util.zip.ZipOutputStream");
args = new object[] { _fileStream };
_inst = Activator.CreateInstance(_type, args);
}
public void Dispose()
{
MethodInfo mi = _type.GetMethod("dispose");
if (mi != null)
mi.Invoke(_inst, null);
}
public void CloseEntry()
{
MethodInfo mi = _type.GetMethod("closeEntry");
mi.Invoke(_inst, null);
}
public void Close()
{
MethodInfo mi = _type.GetMethod("close");
mi.Invoke(_inst, null);

mi = _typeFileStream.GetMethod("close");
mi.Invoke(_fileStream, null);
}
public void PutNextEntry(ZipEntry ze)
{
MethodInfo mi = _type.GetMethod("putNextEntry");
object[] args = new object[] { ze.GetInstance() };
mi.Invoke(_inst, args);
}
public void Write(sbyte[] buffer, int start, int len)
{
object[] args = new object[3];
args[0] = buffer;
args[1] = 0;
args[2] = len;

Type[] types = new Type[3] { typeof(sbyte[]), typeof(int), typeof(int) }; // identify the correct Method by #arguments
BindingFlags b = BindingFlags.Public BindingFlags.Instance; // public or contructor method
MethodInfo mi = _type.GetMethod("write", b, null, types, null);
mi.Invoke(_inst, args);
}
}

/*
* ********* ********* ********* ********* *********
* wrapper for the java.util.zip.ZipInputStream (late binds to object in vjslib.dll)
* NOTE: This wrapper includes the java.io.FileInputStream which is required
* to contruct the ZipInputStream
* ********* ********* ********* ********* *********
*/
public class ZipInputStream : IDisposable
{
Assembly _assem;
Type _type;
object _inst;

Type _typeFileStream;
object _fileStream;

public ZipInputStream(string assemblyName, string file)
{
_assem = Assembly.Load(assemblyName);

// create an instance of java.io.FileInputStream
_typeFileStream = _assem.GetType("java.io.FileInputStream");
object[] args = new object[] { file };
_fileStream = Activator.CreateInstance(_typeFileStream, args);

// create an instance of the java.util.zip.ZipOutputStream
_type = _assem.GetType("java.util.zip.ZipInputStream");
args = new object[] { _fileStream };
_inst = Activator.CreateInstance(_type, args);
}
public void Dispose()
{
MethodInfo mi = _type.GetMethod("dispose");
if (mi != null)
mi.Invoke(_inst, null);
}
public void CloseEntry()
{
MethodInfo mi = _type.GetMethod("closeEntry");
mi.Invoke(_inst, null);
}
public void Close()
{
MethodInfo mi = _type.GetMethod("close");
mi.Invoke(_inst, null);

mi = _typeFileStream.GetMethod("close");
mi.Invoke(_fileStream, null);
}
public string GetNextEntry()
{
MethodInfo mi = _type.GetMethod("getNextEntry");
object ze = mi.Invoke(_inst, null);
if (ze != null)
{
Type typeZe = ze.GetType();
mi = typeZe.GetMethod("getName");
object result = mi.Invoke(ze, null);
return result.ToString();
}
return string.Empty;
}
public int Read(sbyte[] buffer)
{
object[] args = new object[1];
args[0] = buffer;

Type[] types = new Type[1] { typeof(sbyte[]) }; // identify the correct Method by #arguments
BindingFlags b = BindingFlags.Public BindingFlags.Instance; // public or contructor method
MethodInfo mi = _type.GetMethod("read", b, null, types, null);
object result = mi.Invoke(_inst, args);
return int.Parse(result.ToString());
}
}


/*
* ********* ********* ********* ********* *********
* wrapper for the java.util.zip.ZipEntry (late binds to object in vjslib.dll)
* ********* ********* ********* ********* *********
*/
public class ZipEntry : IDisposable
{
Assembly _assem;
Type _type;
object _inst;

public ZipEntry(string assemblyName, string data)
{
_assem = Assembly.Load(assemblyName);
_type = _assem.GetType("java.util.zip.ZipEntry");

object[] args = new object[] { data };
_inst = Activator.CreateInstance(_type, args);
}
//public ZipEntry(Assembly a, object zeInstance)
//{
// _assem = a;
// _type = _assem.GetType("java.util.zip.ZipEntry");
// _inst = zeInstance;
//}
public void Dispose()
{
MethodInfo mi = _type.GetMethod("dispose");
if (mi != null)
mi.Invoke(_inst, null);
}
public string GetName()
{
MethodInfo mi = _type.GetMethod("getName");
object result = mi.Invoke(_inst, null);
return result.ToString();
}
public object GetInstance()
{
return _inst;
}
}


/*
* ********* ********* ********* ********* *********
* PAGE LOAD
* ********* ********* ********* ********* *********
*/
private void Page_Load(object sender, System.EventArgs e)
{
cZip z = new cZip();
//z.ShowMethods("java.util.zip.ZipEntry");
z.Create("/zip.zip", "/zip.aspx,/win2000.gif,winxp.gif");
z.Append("/zip.zip", "/warning.gif,/help.gif");


if (!IsPostBack)
{
// not a re-post
}
else
{
// re-post
}
}
</script>


<html>
<head>
</head>

<body>
<form runat="server">

</form>
</body>
</html>


grow taller