using System;
using System.IO;
using System.Text;
using System.Reflection;
using System.Collections;
using System.Runtime.InteropServices;
using System.Threading;
namespace Demo
{
class CabLibDemo
{
[DllImport("kernel32.dll", EntryPoint="GetWindowsDirectoryA", CharSet=CharSet.Ansi)]
private static extern int GetWindowsDirectory(StringBuilder s_Text, int MaxCount);
[DllImport("kernel32.dll", EntryPoint="GetCurrentDirectoryA", CharSet=CharSet.Ansi)]
private static extern int GetCurrentDirectory(int MaxCount, StringBuilder s_Text);
[DllImport("kernel32.dll", EntryPoint="SetConsoleTextAttribute")]
private static extern bool SetConsoleTextAttribute(IntPtr h_ConsoleOutput, Int16 u16_Attributes);
[DllImport("kernel32.dll", EntryPoint="GetStdHandle")]
private static extern IntPtr GetStdHandle(int u32_Device);
const int GREY = 0x7;
const int WHITE = 0xF;
const int GREEN = 0xA;
const int CYAN = 0xB;
const int RED = 0xC;
const int YELLOW = 0xE;
[STAThread]
static void Main(string[] args)
{
// ######################### SETTINGS MULTITHREAD DEMO ########################
// This demo extracts or compresses 2 huge folders multithreaded at the same time.
// Before setting "true" adapt the paths in the function MultiThread()!
bool b_MultiThreadCompress = false;
bool b_MultiThreadExtract = false;
// ############################ SETTINGS NORMAL DEMO ##########################
// Change this to split the archive into multiple files (200000 --> CAB split size = 200kB)
// ATTENTION: In this case Parameter 1 of CompressFile() MUST contain "%d" or "%02u",...
int s32_SplitSize = 0x7FFFFFFF;
// Store filetimes as UTC in CAB files
bool b_UtcTime = true;
// Encode ANSI or Unicode filenames in CAB file using UTF8. Read the documentation!
bool b_EncodeUtf = true;
// NONE: store files without compression
// MSZIP, LZX: compression algorithms
CabLib.Compress.eCompress e_Compress = CabLib.Compress.eCompress.LZX;
// true -> Don't write any file to disk, all files are passed in OnAfterCopyFile()
bool b_ExtractToMemory = false;
// You can specify your own key for CAB encryption here (the longer the more secure, up to 5000 characters)
String s_EncryptionKey = ""; // to handle CAB files without encryption
// String s_EncryptionKey = "AH%KJ/76?K�H�\\��dghf7(ZTbjsf82iz<sx87qc5ba&m;-@^l#jeL9/)$D2@rTbZ<�9�}2&";
// ########################## Initialization ############################
if (b_MultiThreadCompress)
{
StartThread("Compress1");
StartThread("Compress2");
return;
}
if (b_MultiThreadExtract)
{
StartThread("Extract1");
StartThread("Extract2");
return;
}
StringBuilder s_WinDir = new StringBuilder(500);
GetWindowsDirectory(s_WinDir, 500);
String s_Explorer = s_WinDir + "\\Explorer.exe";
String s_Notepad = s_WinDir + "\\Notepad.exe";
StringBuilder s_WorkDir = new StringBuilder(500);
GetCurrentDirectory(500, s_WorkDir);
String s_CompressDir = s_WorkDir + "\\_Compressed";
String s_ExtractDir = s_WorkDir + "\\_ExtractFile";
String s_ResourceDir = s_WorkDir + "\\_ExtractResource";
String s_StreamDir = s_WorkDir + "\\_ExtractStream";
String s_UrlDir = s_WorkDir + "\\_ExtractUrl";
String s_CompressFile = s_CompressDir + "\\Packed_%02d.cab";
CabLib.Compress i_Compress = new CabLib.Compress();
CabLib.Extract i_Extract = new CabLib.Extract();
i_Compress.SetEncryptionKey(s_EncryptionKey);
i_Extract. SetDecryptionKey(s_EncryptionKey);
// Call this if you want to change the default compression algorithm (LZX)
i_Compress.SwitchCompression(e_Compress);
// Attach compress event handler
i_Compress.evFilePlaced += new CabLib.Compress.delFilePlaced (OnFilePlaced);
i_Compress.evUpdateStatus += new CabLib.Compress.delUpdateStatus (OnUpdateStatus);
// Attach extract event handler
i_Extract.evBeforeCopyFile += new CabLib.Extract.delBeforeCopyFile(OnBeforeCopyFile);
i_Extract.evAfterCopyFile += new CabLib.Extract.delAfterCopyFile (OnAfterCopyFile);
i_Extract.evProgressInfo += new CabLib.Extract.delProgressInfo (OnProgressInfo);
i_Extract.evCabinetInfo += new CabLib.Extract.delCabinetInfo (OnCabinetInfo);
i_Extract.evNextCabinet += new CabLib.Extract.delNextCabinet (OnNextCabinet);
// ########################## Print CabLib version ############################
Assembly i_Lib = typeof(CabLib.Extract).Assembly;
object[] o_Title = i_Lib.GetCustomAttributes(typeof(AssemblyTitleAttribute), false);
AssemblyTitleAttribute i_Title = (AssemblyTitleAttribute)o_Title[0];
Version i_Vers = i_Lib.GetName().Version;
Print(CYAN, i_Title.Title + " version " + i_Vers.Major + "." + i_Vers.Minor + "\n");
// ############################# Compress demo ################################
// This will pack Explorer.exe and Notepad.exe into a CAB file with subfolders
Print(WHITE, "----------------------------------------------------------------");
Print(YELLOW, " CAB FILE COMPRESSION (" + e_Compress.ToString() + ")\n");
try
{
ArrayList i_Files = new ArrayList();
i_Files.Add(new string[] { s_Explorer, @"FileManager\Explorer.exe" });
i_Files.Add(new string[] { s_Notepad, @"TextManager\Notepad.exe" });
i_Compress.CompressFileList(i_Files, s_CompressFile, b_UtcTime, b_EncodeUtf, s32_SplitSize);
Print(GREEN, "\nSUCCESS: Compressed Explorer.exe and Notepad.exe into cabinet in\n" + s_CompressDir);
}
catch (Exception Ex)
{
Print(RED, Ex.Message);
goto _RESOURCE;
}
// ########################## Extract File demo ############################
// This will decrypt the CAB file if it was encrypted above
Print(WHITE, "----------------------------------------------------------------");
Print(YELLOW, "\n CAB FILE EXTRACTION\n");
// "Packed_%02d.cab" --> "Packed_01.cab"
s_CompressFile = CabLib.Compress.Sprintf(s_CompressFile, new object[]{1});
try
{
// Print header information
CabLib.Extract.kHeaderInfo k_Info;
// ATTENTION:
// The following code only demonstrates how to use IsFileCabinet()
// But it is not necessary to call IsFileCabinet() before every extraction!
if (i_Extract.IsFileCabinet(s_CompressFile, out k_Info))
{
Print(WHITE, "CAB filesize: " + k_Info.u32_FileSize + " Bytes");
Print(WHITE, "Folder count in CAB: " + k_Info.u16_Folders);
Print(WHITE, "File count in CAB: " + k_Info.u16_Files);
Print(WHITE, "Set ID: " + k_Info.u16_SetID);
Print(WHITE, "CAB Index: " + k_Info.u16_CabIndex);
Print(WHITE, "Has additional header data: " + k_Info.b_HasReserve);
Print(WHITE, "Has predecessor in splitted Cabinet: " + k_Info.b_HasPrevious);
Print(WHITE, "Has successor in splitted Cabinet: " + k_Info.b_HasNext + "\n");
}
else
{
Print(RED, "The file is not a valid Cabinet: " + s_CompressFile);
}
}
catch (Exception Ex)
{
Print(RED, Ex.Message);
}
try
{
if (b_ExtractToMemory)
s_ExtractDir = "MEMORY";
// Now extract into subdirectory "_ExtractFile" and the corresponding subdirectories in the CAB file
i_Extract.ExtractFile(s_CompressFile, s_ExtractDir);
Print(GREEN, "\nSUCCESS: Extracted all files from the above compressed cabinet to\n" + s_ExtractDir);
}
catch (Exception Ex)
{
Print(RED, Ex.Message);
}
// ########################## Extract Win32 resource demo ############################
// This will extract the file "Test.cab" in the embedded Win32 resources in CabLib.dll
_RESOURCE:
i_Extract.SetDecryptionKey(""); // the CAB resource is not encrypted
Print(WHITE, "----------------------------------------------------------------");
Print(YELLOW, "\n WIN32 CAB RESOURCE EXTRACTION\n");
try
{
// Extract only one file from the cabinet which must be in the root folder!!
// i_Extract.SetSingleFile("Root.txt");
if (b_ExtractToMemory)
s_ResourceDir = "MEMORY";
// Now extract into subdirectory "_ExtractResource" and the corresponding subdirectories in the CAB file
i_Extract.ExtractResource("CabLib.dll", 101, "CABFILE", s_ResourceDir);
Print(GREEN, "\nSUCCESS: Extracted all files from Win32 resource Test.cab in CabLib.dll to\n" + s_ResourceDir);
}
catch (Exception Ex)
{
Print(RED, Ex.Message);
}
// ########################## Extract Stream demo ############################
// This will extract the file "Test.cab" in the embedded .NET resources in CabLibDemo.exe
Print(WHITE, "----------------------------------------------------------------");
Print(YELLOW, "\n .NET CAB STREAM EXTRACTION\n");
try
{
Assembly i_Exe = Assembly.GetExecutingAssembly();
Stream i_Strm = i_Exe.GetManifestResourceStream("CabLibDemo.Resources.Test.cab");
if (b_ExtractToMemory)
s_StreamDir = "MEMORY";
// Now extract into subdirectory "_ExtractStream" and the corresponding subdirectories in the CAB file
i_Extract.ExtractStream(i_Strm, s_StreamDir);
Print(GREEN, "\nSUCCESS: Extracted all files from .NET resource Test.cab in CabLibDemo.exe to\n" + s_StreamDir);
}
catch (Exception Ex)
{
Print(RED, Ex.Message);
}
// ########################## Extract URL demo ############################
// This will download and extract "UrlExtractDemo.cab"
Print(WHITE, "----------------------------------------------------------------");
Print(YELLOW, "\n URL EXTRACTION\n");
try
{
// !!!! IMPORTANT: Read in the documentation about the 100 possible ways to build the URL !!!!
String s_Url = "http://home.arcor.de/starwalker22/Test/UrlExtractDemo.cab";
// String s_Url = "http://server/Downloads/Installer_1.35.cab";
// String s_Url = "ftp://user:password@server/Downloads/Installer_1.35.cab";
// String s_Url = "file://C:/Downloads/Installer_1.35.cab";
// Size of blocks to be loaded to memory (HTTP Server must run a script, FTP Server must support "REST")
// Set zero for entire file download to disk
// !!!! IMPORTANT: Read in the documentation about the 100 possible types of downloading !!!!
int s32_BlockSize = 0;
// If s_LocalFile is an empty string -> create a temporary CAB file, extract it, then delete it.
// Otherwise download into the specified file, extract it and do NOT delete it.
string s_LocalFile = "";
// String s_LocalFile = "C:\\Downloaded.cab"; // Ignored if blocksize > 0
// Passive mode for FTP downloads
i_Extract.SetPassiveFtpMode(true);
// Proxy Format= "http=http://Proxy1.com:8000 https=https://Proxy2.com:443"
// Proxy = "" --> Use Internet Explorer default settings
i_Extract.SetProxy("");
// Modifies the HTTP headers which are sent to the server. (separated by pipe)
// e.g. "Referer: http://www.test.com|Accept-Language:en" (no space before or after pipe!!)
// If the value of a header is empty, the header is removed.
i_Extract.SetHttpHeaders("");
if (b_ExtractToMemory)
s_UrlDir = "MEMORY";
// !!!! IMPORTANT: Read in the documentation about the 100 possible types of downloading !!!!
Print(GREY, "Extracting: {0}", s_Url);
if (s32_BlockSize>0) Print(GREY, "Download to memory, Blocksize: {0} Bytes\n", s32_BlockSize);
else if (s_LocalFile.Length>0) Print(GREY, "Download to : {0}\n", s_LocalFile);
else Print(GREY, "Download to temporary file\n");
// Now extract into subdirectory "_ExtractUrl"
i_Extract.ExtractUrl(s_Url, s32_BlockSize, s_LocalFile, s_UrlDir);
// You can reutilize the downloaded CAB data for further extractions:
// i_Extract.ExtractMoreUrl("C:\\");
// IMPORTANT: Close all handles and free memory after every URL extraction!!
i_Extract.CleanUp();
Print(GREEN, "\nSUCCESS: Extracted all files from downloaded CAB file to\n" + s_UrlDir);
}
catch (Exception Ex)
{
Print(RED, Ex.Message);
}
// ############################## END #######################################
// Under some cirumstances the DOS window disappears immediately, so you cannot read anything!
Print(GREY, "\nHit any key to exit");
Console.Read();
}
/// <summary>
/// The lazy guys at Microsoft forgot to implement coloured text output into .NET framework
/// </summary>
static private void Print(Int16 u16_Color, string s_Format, object o_Param)
{
Print(u16_Color, string.Format(s_Format, o_Param));
}
static private void Print(Int16 u16_Color, string s_Text)
{
const int STD_OUTPUT_HANDLE = -11;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), u16_Color);
Console.WriteLine(s_Text);
}
// ##################### EXTRACT EVENT HANDLER ########################
/// <summary>
/// This event handler is called for every extratced file before it is written to disk
/// return false here if you want a file not to be extracted
/// </summary>
static private bool OnBeforeCopyFile(CabLib.Extract.kCabinetFileInfo k_Info)
{
string s_File = k_Info.s_File;
if (s_File[0] > 255) s_File = "Console cannot display Unicode filename.";
Print(GREY, "Callback OnBeforeCopyFile: " + s_File);
return true;
}
// This function will be called when a file has been succesfully extracted.
// If Extraction to Memory is enabled, no file is written to disk,
// instead the entire content of the file is passed in u8_ExtractMem
// If Extraction to Memory is not enabled, u8_ExtractMem is null
private static void OnAfterCopyFile(string s_File, Byte[] u8_ExtractMem)
{
s_File = Path.GetFileName(s_File);
if (s_File[0] > 255) s_File = "Console cannot display Unicode filename.";
Print(GREY, "Callback OnAfterCopyFile: " + s_File);
if (u8_ExtractMem != null)
{
// string s_FileContent = Encoding.ASCII.GetString(u8_ExtractMem);
}
}
// This callback is called every 200 ms when extracting to disk. (only when huge files are extracted)
// It shows the progress of the current file in percent ("82.4%")
// On extraction to memory it will not be called. (It would be nonsene to extract huge files to memory)
// This callback will not be called for all files that extract faster than 200 ms
private static void OnProgressInfo(CabLib.Extract.kProgressInfo k_Info)
{
Print(GREY, "Callback OnProgressInfo: " + k_Info.fl_Percent.ToString("N1") + "%");
}
private static void OnCabinetInfo(CabLib.Extract.kCabinetInfo k_Info)
{
Print(GREY, "Callback OnCabinetInfo: Next CAB: '" + k_Info.s_NextCabinet + "'");
}
private static void OnNextCabinet(CabLib.Extract.kCabinetInfo k_Info, int s32_FdiError)
{
Print(GREY, "Callback OnNextCabinet: Please insert '" + k_Info.s_NextDisk + "'");
}
// ##################### COMPRESS EVENT HANDLER ########################
private static int OnFilePlaced(string s_File, int s32_FileSize, bool bContinuation)
{
Print(GREY, "Callback OnFilePlaced: " + s_File);
return 0;
}
private static int OnUpdateStatus(CabLib.Compress.kCurStatus k_CurStatus)
{
if (k_CurStatus.u32_FolderPercent > 0)
Print(GREY, "Callback OnUpdateStatus: {0}% completed", k_CurStatus.u32_FolderPercent);
return 0;
}
// ###################################################################################################
// ###################################################################################################
// ###################################################################################################
// This is just a demo which compresses 2 huge folders into 2 CAB files at the same time.
// Or it can extract these CAB files into two new folders at the same time.
private static void StartThread(string s_Name)
{
Thread i_Thread = new Thread(new ThreadStart(MultiThread));
i_Thread.Name = s_Name;
i_Thread.Start();
}
private static void MultiThread()
{
// ATTENTION: The folders you compress must contain less than 2GB data!
string s_ComprFolder1 = @"C:\Program Files\Babylon6";
string s_ComprFolder2 = @"C:\Program Files\Common Files";
string s_CabFile1 = @"D:\Compressed\Babylon.cab";
string s_CabFile2 = @"D:\Compressed\Common.cab";
string s_ExtrFolder1 = @"D:\Extracted\Babylon";
string s_ExtrFolder2 = @"D:\Extracted\Common";
try
{
CabLib.Compress i_Compress = new CabLib.Compress();
CabLib.Extract i_Extract = new CabLib.Extract();
switch (Thread.CurrentThread.Name)
{
case "Compress1":
Print(GREY, "Compressing {0}", s_ComprFolder1);
i_Compress.CompressFolder(s_ComprFolder1, s_CabFile1, "*.*", true, true, 0);
break;
case "Compress2":
Print(GREY, "Compressing {0}", s_ComprFolder2);
i_Compress.CompressFolder(s_ComprFolder2, s_CabFile2, "*.*", true, true, 0);
break;
case "Extract1":
Print(GREY, "Extracting {0}", s_CabFile1);
i_Extract.ExtractFile(s_CabFile1, s_ExtrFolder1);
break;
case "Extract2":
Print(GREY, "Extracting {0}", s_CabFile2);
i_Extract.ExtractFile(s_CabFile2, s_ExtrFolder2);
break;
default:
return;
}
Print(GREEN, "Thread {0} exited successfully.", Thread.CurrentThread.Name);
}
catch (Exception Ex)
{
Print(RED, Ex.Message);
Print(YELLOW, Ex.StackTrace);
}
Console.Read();
}
}
}