HLLib/HLExtract.Net/Program.cs

1157 lines
44 KiB
C#

/*
* HLExtract.Net
* Copyright (C) 2008-2010 Ryan Gregg
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
namespace HLExtract.Net
{
class Program
{
static bool bSilent = false;
static bool bPause = true;
static string sDestination = string.Empty;
static int Main(string[] args)
{
// Arguments.
string sPackage = string.Empty;
List<string> Commands = new List<string>();
string sNCFRootPath = string.Empty;
bool bFileMapping = false;
bool bQuickFileMapping = false;
bool bVolatileAccess = false;
bool bWriteAccess = false;
bool bOverwriteFiles = true;
// Package stuff.
HLLib.HLPackageType ePackageType = HLLib.HLPackageType.HL_PACKAGE_NONE;
uint uiPackage = HLLib.HL_ID_INVALID;
uint uiMode = (uint)HLLib.HLFileMode.HL_MODE_INVALID;
if(HLLib.hlGetUnsignedInteger(HLLib.HLOption.HL_VERSION) < HLLib.HL_VERSION_NUMBER)
{
Console.WriteLine("Wrong HLLib version: v{0}.", HLLib.hlGetString(HLLib.HLOption.HL_VERSION));
return 1;
}
// Process switches.
if(args.Length == 1)
{
sPackage = args[0];
}
else
{
for(int i = 0; i < args.Length; i++)
{
if(string.Equals(args[i], "-p", StringComparison.CurrentCultureIgnoreCase) || string.Equals(args[i], "--package", StringComparison.CurrentCultureIgnoreCase))
{
if(sPackage.Length == 0 && i + 1 < args.Length)
{
sPackage = args[++i];
}
else
{
PrintUsage();
return 2;
}
}
else if(string.Equals(args[i], "-d", StringComparison.CurrentCultureIgnoreCase) || string.Equals(args[i], "--dest", StringComparison.CurrentCultureIgnoreCase))
{
if(sDestination.Length == 0 && i + 1 < args.Length)
{
sDestination = args[++i];
}
else
{
PrintUsage();
return 2;
}
}
else if(string.Equals(args[i], "-x", StringComparison.CurrentCultureIgnoreCase) || string.Equals(args[i], "--execute", StringComparison.CurrentCultureIgnoreCase))
{
if(sDestination.Length == 0 && i + 1 < args.Length)
{
Commands.Add(args[++i]);
}
else
{
PrintUsage();
return 2;
}
}
else if(string.Equals(args[i], "-n", StringComparison.CurrentCultureIgnoreCase) || string.Equals(args[i], "--ncfroot", StringComparison.CurrentCultureIgnoreCase))
{
if(sNCFRootPath.Length == 0 && i + 1 < args.Length)
{
sNCFRootPath = args[++i];
}
else
{
PrintUsage();
return 2;
}
}
else if(string.Equals(args[i], "-s", StringComparison.CurrentCultureIgnoreCase) || string.Equals(args[i], "--silent", StringComparison.CurrentCultureIgnoreCase))
{
bSilent = true;
}
else if(string.Equals(args[i], "-u", StringComparison.CurrentCultureIgnoreCase) || string.Equals(args[i], "--no-pause", StringComparison.CurrentCultureIgnoreCase))
{
bPause = false;
}
else if(string.Equals(args[i], "-m", StringComparison.CurrentCultureIgnoreCase) || string.Equals(args[i], "--filemapping", StringComparison.CurrentCultureIgnoreCase))
{
bFileMapping = true;
}
else if(string.Equals(args[i], "-q", StringComparison.CurrentCultureIgnoreCase) || string.Equals(args[i], "--quick-filemapping", StringComparison.CurrentCultureIgnoreCase))
{
bFileMapping = true;
bQuickFileMapping = true;
}
else if(string.Equals(args[i], "-v", StringComparison.CurrentCultureIgnoreCase) || string.Equals(args[i], "--volatile", StringComparison.CurrentCultureIgnoreCase))
{
bVolatileAccess = true;
}
else if(string.Equals(args[i], "-w", StringComparison.CurrentCultureIgnoreCase) || string.Equals(args[i], "--write", StringComparison.CurrentCultureIgnoreCase))
{
bWriteAccess = true;
}
else if(string.Equals(args[i], "-o", StringComparison.CurrentCultureIgnoreCase) || string.Equals(args[i], "--no-overwrite", StringComparison.CurrentCultureIgnoreCase))
{
bOverwriteFiles = false;
}
else
{
PrintUsage();
return 2;
}
}
}
// Make sure we have something to do.
if(sPackage.Length == 0)
{
PrintUsage();
return 2;
}
// If the destination directory is not specified, make it the input directory.
if(sDestination.Length == 0)
{
int iIndex = sPackage.LastIndexOfAny(new char[]{'\\', '/'});
if(iIndex != -1)
{
sDestination = sPackage.Substring(0, iIndex + 1);
}
}
HLLib.hlInitialize();
// Keep the delegates alive so they don't get garbage collected.
HLLib.HLExtractItemStartProc HLExtractItemStartProc = new HLLib.HLExtractItemStartProc(ExtractItemStartCallback);
HLLib.HLExtractItemEndProc HLExtractItemEndProc = new HLLib.HLExtractItemEndProc(ExtractItemEndCallback);
HLLib.HLExtractFileProgressProc HLExtractFileProgressProc = new HLLib.HLExtractFileProgressProc(FileProgressCallback);
HLLib.HLValidateFileProgressProc HLValidateFileProgressProc = new HLLib.HLValidateFileProgressProc(FileProgressCallback);
HLLib.HLDefragmentFileProgressExProc HLDefragmentFileProgressProc = new HLLib.HLDefragmentFileProgressExProc(DefragmentProgressCallback);
HLLib.hlSetBoolean(HLLib.HLOption.HL_OVERWRITE_FILES, bOverwriteFiles);
HLLib.hlSetVoid(HLLib.HLOption.HL_PROC_EXTRACT_ITEM_START, Marshal.GetFunctionPointerForDelegate(HLExtractItemStartProc));
HLLib.hlSetVoid(HLLib.HLOption.HL_PROC_EXTRACT_ITEM_END, Marshal.GetFunctionPointerForDelegate(HLExtractItemEndProc));
HLLib.hlSetVoid(HLLib.HLOption.HL_PROC_EXTRACT_FILE_PROGRESS, Marshal.GetFunctionPointerForDelegate(HLExtractFileProgressProc));
HLLib.hlSetVoid(HLLib.HLOption.HL_PROC_VALIDATE_FILE_PROGRESS, Marshal.GetFunctionPointerForDelegate(HLValidateFileProgressProc));
HLLib.hlSetVoid(HLLib.HLOption.HL_PROC_DEFRAGMENT_PROGRESS_EX, Marshal.GetFunctionPointerForDelegate(HLDefragmentFileProgressProc));
// Get the package type from the filename extension.
ePackageType = HLLib.hlGetPackageTypeFromName(sPackage);
// If the above fails, try getting the package type from the data at the start of the file.
if(ePackageType == HLLib.HLPackageType.HL_PACKAGE_NONE && File.Exists(sPackage))
{
FileStream Reader = null;
try
{
byte[] lpBuffer = new byte[HLLib.HL_DEFAULT_PACKAGE_TEST_BUFFER_SIZE];
Reader = new FileStream(sPackage, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
int iBytesRead = Reader.Read(lpBuffer, 0, lpBuffer.Length);
if(iBytesRead > 0)
{
IntPtr lpBytesRead = Marshal.AllocHGlobal(iBytesRead);
try
{
Marshal.Copy(lpBuffer, 0, lpBytesRead, iBytesRead);
ePackageType = HLLib.hlGetPackageTypeFromMemory(lpBytesRead, (uint)iBytesRead);
}
finally
{
Marshal.FreeHGlobal(lpBytesRead);
}
}
}
finally
{
if(Reader != null)
{
Reader.Close();
}
}
}
if(ePackageType == HLLib.HLPackageType.HL_PACKAGE_NONE)
{
Console.WriteLine("Error loading {0}:", sPackage);
Console.WriteLine("Unsupported package type.");
HLLib.hlShutdown();
Pause();
return 3;
}
// Create a package element, the element is allocated by the library and cleaned
// up by the library. An ID is generated which must be bound to apply operations
// to the package.
if(!HLLib.hlCreatePackage(ePackageType, out uiPackage))
{
Console.WriteLine("Error loading {0}:", sPackage);
Console.WriteLine(HLLib.hlGetString(HLLib.HLOption.HL_ERROR_SHORT_FORMATED));
HLLib. hlShutdown();
Pause();
return 3;
}
HLLib.hlBindPackage(uiPackage);
uiMode = (uint)HLLib.HLFileMode.HL_MODE_READ;
uiMode |= !bFileMapping ? (uint)HLLib.HLFileMode.HL_MODE_NO_FILEMAPPING : 0;
uiMode |= bQuickFileMapping ? (uint)HLLib.HLFileMode.HL_MODE_QUICK_FILEMAPPING : 0;
uiMode |= bVolatileAccess ? (uint)HLLib.HLFileMode.HL_MODE_VOLATILE : 0;
uiMode |= bWriteAccess ? (uint)HLLib.HLFileMode.HL_MODE_WRITE : 0;
// Open the package.
// Of the above modes, only HL_MODE_READ is required. HL_MODE_WRITE is present
// only for future use. File mapping is recommended as an efficient way to load
// packages. Quick file mapping maps the entire file (instead of bits as they are
// needed) and thus should only be used in Windows 2000 and up (older versions of
// Windows have poor virtual memory management which means large files won't be able
// to find a continues block and will fail to load). Volatile access allows HLLib
// to share files with other applications that have those file open for writing.
// This is useful for, say, loading .gcf files while Steam is running.
if(!HLLib.hlPackageOpenFile(sPackage, uiMode))
{
Console.WriteLine("Error loading {0}:", sPackage);
Console.WriteLine(HLLib.hlGetString(HLLib.HLOption.HL_ERROR_SHORT_FORMATED));
HLLib. hlShutdown();
Pause();
return 3;
}
// If we have a .ncf file, the package file data is stored externally. In order to
// validate the file data etc., HLLib needs to know where to look. Tell it where.
if(ePackageType == HLLib.HLPackageType.HL_PACKAGE_NCF && sNCFRootPath.Length > 0)
{
HLLib.hlNCFFileSetRootPath(sNCFRootPath);
}
if(!bSilent)
Console.WriteLine("{0} opened.", sPackage);
// Interactive console mode.
EnterConsole(uiPackage, Commands);
// Close the package.
HLLib.hlPackageClose();
if(!bSilent)
Console.WriteLine("{0} closed.", sPackage);
// Free up the allocated memory.
HLLib.hlDeletePackage(uiPackage);
HLLib.hlShutdown();
return 0;
}
static void Pause()
{
if(bPause)
{
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
static void PrintUsage()
{
System.Reflection.AssemblyName Name = System.Reflection.Assembly.GetExecutingAssembly().GetName();
Console.WriteLine("HLExtract.Net v{0}.{1}.{2} using HLLib v{3}", Name.Version.Major, Name.Version.Minor, Name.Version.Build, HLLib.hlGetString(HLLib.HLOption.HL_VERSION));
Console.WriteLine();
Console.WriteLine("Correct HLExtract.Net usage:");
Console.WriteLine(" -p <filepath> (Package to load.)");
Console.WriteLine(" -d <path> (Destination extraction directory.)");
Console.WriteLine(" -x <command> (Execute console command.)");
Console.WriteLine(" -s (Silent mode.)");
Console.WriteLine(" -u (Don't pause on error..)");
Console.WriteLine(" -m (Use file mapping.)");
Console.WriteLine(" -q (Use quick file mapping.)");
Console.WriteLine(" -v (Allow volatile access.)");
Console.WriteLine(" -w (Allow write access.)");
Console.WriteLine(" -o (Don't overwrite files.)");
Console.WriteLine(" -n <path> (NCF file's root path.)");
Console.WriteLine();
Console.WriteLine("Example HLExtract.Net usage:");
Console.WriteLine("HLExtract.Net.exe -p \"C:\\half-life.gcf\" -d \"C:\\backup\"");
Console.WriteLine("HLExtract.Net.exe -p \"C:\\half-life.gcf\" -m -v");
Console.WriteLine("HLExtract.Net.exe -p \"C:\\half-life.gcf\" -w -x defragment -x exit");
Console.WriteLine();
Console.WriteLine("Batching HLExtract.Net:");
Console.WriteLine("for %%F in (*.gcf) do HLExtract.Net.exe -p \"%%F\" -u -v -x \"info .\" -x exit");
Console.WriteLine("for %%F in (*.gcf) do HLExtract.Net.exe -p \"%%F\" -s -u -x \"validate .\" -x exit");
Console.WriteLine("for %%F in (*.gcf) do HLExtract.Net.exe -p \"%%F\" -s -u -w -x defragment -x exit");
Pause();
}
static readonly uint MAX_PATH_SIZE = 512;
static string GetPath(IntPtr pItem)
{
string sPath = string.Empty;
IntPtr lpPath = IntPtr.Zero;
try
{
lpPath = Marshal.AllocHGlobal((int)MAX_PATH_SIZE);
HLLib.hlItemGetPath(pItem, lpPath, MAX_PATH_SIZE);
sPath = Marshal.PtrToStringAnsi(lpPath);
}
finally
{
if(lpPath != IntPtr.Zero)
{
Marshal.FreeHGlobal(lpPath);
}
}
return sPath;
}
#region Progress Callbacks
static uint uiProgressLast;
static void ProgressStart()
{
uiProgressLast = 0;
Console.Write("0%");
}
static void ProgressUpdate(UInt64 uiBytesDone, UInt64 uiBytesTotal)
{
if(!bSilent)
{
uint uiProgress = uiBytesTotal == 0 ? 100 : (uint)(uiBytesDone * 100 / uiBytesTotal);
while(uiProgress >= uiProgressLast + 10)
{
uiProgressLast += 10;
if(uiProgressLast == 100)
{
Console.Write("100% ");
}
else if(uiProgressLast == 50)
{
Console.Write("50%");
}
else
{
Console.Write(".");
}
}
}
}
static void ExtractItemStartCallback(IntPtr pItem)
{
if(!bSilent)
{
if(HLLib.hlItemGetType(pItem) == HLLib.HLDirectoryItemType.HL_ITEM_FILE)
{
Console.Write(" Extracting {0}: ", HLLib.hlItemGetName(pItem));
ProgressStart();
}
else
{
Console.WriteLine(" Extracting {0}:", HLLib.hlItemGetName(pItem));
}
}
}
static void FileProgressCallback(IntPtr pFile, uint uiBytesExtracted, uint uiBytesTotal, ref bool pCancel)
{
ProgressUpdate((UInt64)uiBytesExtracted, (UInt64)uiBytesTotal);
}
static void ExtractItemEndCallback(IntPtr pItem, bool bSuccess)
{
if(bSuccess)
{
if(!bSilent)
{
uint uiSize = 0;
HLLib.hlItemGetSize(pItem, out uiSize);
if(HLLib.hlItemGetType(pItem) == HLLib.HLDirectoryItemType.HL_ITEM_FILE)
{
Console.WriteLine("OK ({0} B)", uiSize);
}
else
{
Console.WriteLine(" Done {0}: OK ({1} B)", HLLib.hlItemGetName(pItem), uiSize);
}
}
}
else
{
if(!bSilent)
{
if(HLLib.hlItemGetType(pItem) == HLLib.HLDirectoryItemType.HL_ITEM_FILE)
{
Console.WriteLine("Errored");
Console.WriteLine(" {0}", HLLib.hlGetString(HLLib.HLOption.HL_ERROR_SHORT_FORMATED));
}
else
{
Console.WriteLine(" Done {0}: Errored", HLLib.hlItemGetName(pItem));
}
}
else
{
if(HLLib.hlItemGetType(pItem) == HLLib.HLDirectoryItemType.HL_ITEM_FILE)
{
Console.WriteLine(" Error extracting {0}:", GetPath(pItem));
Console.WriteLine(" {0}", HLLib.hlGetString(HLLib.HLOption.HL_ERROR_SHORT_FORMATED));
}
else
{
Console.WriteLine(" Error extracting {0}.", GetPath(pItem));
}
}
}
}
static void DefragmentProgressCallback(IntPtr pFile, uint uiFilesDefragmented, uint uiFilesTotal, UInt64 uiBytesDefragmented, UInt64 uiBytesTotal, ref bool pCancel)
{
ProgressUpdate(uiBytesDefragmented, uiBytesTotal);
}
#endregion
static readonly string[] ValidationNames = new string[] { "OK", "Assumed OK", "Incomplete", "Corrupt", "Canceled", "Error" };
static string GetValidation(HLLib.HLValidation eValidation)
{
if(eValidation >= HLLib.HLValidation.HL_VALIDATES_OK && eValidation <= HLLib.HLValidation.HL_VALIDATES_ERROR)
{
return ValidationNames[(uint)eValidation];
}
return string.Empty;
}
static HLLib.HLValidation Validate(IntPtr pItem)
{
HLLib.HLValidation eValidation = HLLib.HLValidation.HL_VALIDATES_OK, eTest;
switch(HLLib.hlItemGetType(pItem))
{
case HLLib.HLDirectoryItemType.HL_ITEM_FOLDER:
if(!bSilent)
{
Console.WriteLine(" Validating {0}:", HLLib.hlItemGetName(pItem));
}
uint uiItemCount = HLLib.hlFolderGetCount(pItem);
for(uint i = 0; i < uiItemCount; i++)
{
eTest = Validate(HLLib.hlFolderGetItem(pItem, i));
if(eTest > eValidation)
{
eValidation = eTest;
}
}
if(!bSilent)
{
Console.WriteLine(" Done {0}: {1}", HLLib.hlItemGetName(pItem), GetValidation(eValidation));
}
break;
case HLLib.HLDirectoryItemType.HL_ITEM_FILE:
if(!bSilent)
{
Console.Write(" Validating {0}: ", HLLib.hlItemGetName(pItem));
ProgressStart();
}
eValidation = HLLib.hlFileGetValidation(pItem);
if(bSilent)
{
switch(eValidation)
{
case HLLib.HLValidation.HL_VALIDATES_INCOMPLETE:
case HLLib.HLValidation.HL_VALIDATES_CORRUPT:
Console.WriteLine(" Validating {0}: {1}", GetPath(pItem), GetValidation(eValidation));
break;
}
}
else
{
Console.WriteLine(GetValidation(eValidation));
}
break;
}
return eValidation;
}
static void EnterConsole(uint uiPackage, List<string> Commands)
{
IntPtr pItem = HLLib.hlPackageGetRoot();
while(true)
{
string sLine;
if(Commands.Count > 0)
{
sLine = Commands[0].Trim();
Console.WriteLine("{0}>{1}", HLLib.hlItemGetName(pItem), sLine);
Commands.RemoveAt(0);
}
else
{
// Command prompt.
Console.Write("{0}>", HLLib.hlItemGetName(pItem));
// Get and parse line.
sLine = Console.ReadLine().Trim();
}
if(sLine == null)
{
break;
}
int iIndex;
for(iIndex = 0; iIndex < sLine.Length; iIndex++)
{
if(!Char.IsLetter(sLine[iIndex]))
{
break;
}
}
string sCommand, sArgument;
if(iIndex == sLine.Length)
{
sCommand = sLine;
sArgument = string.Empty;
}
else
{
sCommand = sLine.Substring(0, iIndex).TrimEnd();
sArgument = sLine.Substring(iIndex).TrimStart();
}
// Cycle through commands.
//
// Directory listing.
// Good example of CDirectoryItem::GetType().
//
if(String.Equals(sCommand, "dir", StringComparison.CurrentCultureIgnoreCase))
{
uint uiItemCount = HLLib.hlFolderGetCount(pItem);
uint uiFolderCount = 0, uiFileCount = 0;
Console.WriteLine("Directory of {0}:", GetPath(pItem));
Console.WriteLine();
if(sArgument.Length == 0)
{
// List all items in the current folder.
for(uint i = 0; i < uiItemCount; i++)
{
IntPtr pSubItem = HLLib.hlFolderGetItem(pItem, i);
if(HLLib.hlItemGetType(pSubItem) == HLLib.HLDirectoryItemType.HL_ITEM_FOLDER)
{
uiFolderCount++;
Console.WriteLine(" <{0}>", HLLib.hlItemGetName(pSubItem));
}
else if(HLLib.hlItemGetType(pSubItem) == HLLib.HLDirectoryItemType.HL_ITEM_FILE)
{
uiFileCount++;
Console.WriteLine(" {0}", HLLib.hlItemGetName(pSubItem));
}
}
}
else
{
IntPtr pSubItem = HLLib.hlFolderFindFirst(pItem, sArgument, HLLib.HLFindType.HL_FIND_ALL | HLLib.HLFindType.HL_FIND_NO_RECURSE);
while(pSubItem != IntPtr.Zero)
{
if(HLLib.hlItemGetType(pSubItem) == HLLib.HLDirectoryItemType.HL_ITEM_FOLDER)
{
uiFolderCount++;
Console.WriteLine(" <{0}>", HLLib.hlItemGetName(pSubItem));
}
else if(HLLib.hlItemGetType(pSubItem) == HLLib.HLDirectoryItemType.HL_ITEM_FILE)
{
uiFileCount++;
Console.WriteLine(" {0}", HLLib.hlItemGetName(pSubItem));
}
pSubItem = HLLib.hlFolderFindNext(pItem, pSubItem, sArgument, HLLib.HLFindType.HL_FIND_ALL | HLLib.HLFindType.HL_FIND_NO_RECURSE);
}
}
Console.WriteLine();
// Could also have used hlFolderGetFolderCount() and
// hlFolderGetFileCount().
Console.WriteLine("Summary:");
Console.WriteLine();
Console.WriteLine(" {0} Folder{1}.", uiFolderCount, uiFolderCount != 1 ? "s" : "");
Console.WriteLine(" {0} File{1}.", uiFileCount, uiFileCount != 1 ? "s" : "");
Console.WriteLine();
}
//
// Change directory.
// Good example of CDirectoryFolder::GetParent() and item casting.
//
else if(String.Equals(sCommand, "cd", StringComparison.CurrentCultureIgnoreCase))
{
if(sArgument.Length == 0)
{
Console.WriteLine("No argument for command cd supplied.");
}
else
{
if(String.Equals(sArgument, ".", StringComparison.CurrentCultureIgnoreCase))
{
}
else if(String.Equals(sArgument, "..", StringComparison.CurrentCultureIgnoreCase))
{
if(HLLib.hlItemGetParent(pItem) != IntPtr.Zero)
{
pItem = HLLib.hlItemGetParent(pItem);
}
else
{
Console.WriteLine("Folder does not have a parent.");
}
}
else
{
bool bFound = false;
uint uiItemCount = HLLib.hlFolderGetCount(pItem);
for(uint i = 0; i < uiItemCount; i++)
{
IntPtr pSubItem = HLLib.hlFolderGetItem(pItem, i);
if(HLLib.hlItemGetType(pSubItem) == HLLib.HLDirectoryItemType.HL_ITEM_FOLDER && String.Equals(sArgument, HLLib.hlItemGetName(pSubItem), StringComparison.CurrentCultureIgnoreCase))
{
bFound = true;
pItem = pSubItem;
break;
}
}
if(!bFound)
{
Console.WriteLine("{0} not found.", sArgument);
}
}
}
}
//
// Go to the root folder.
//
else if(String.Equals(sCommand, "root", StringComparison.CurrentCultureIgnoreCase))
{
pItem = HLLib.hlPackageGetRoot();
}
//
// Item information.
// Good example of CPackageUtility helper functions.
//
else if(String.Equals(sCommand, "info", StringComparison.CurrentCultureIgnoreCase))
{
if(sArgument.Length == 0)
{
Console.WriteLine("No argument for command info supplied.");
}
else
{
IntPtr pSubItem = HLLib.hlFolderGetItemByPath(pItem, sArgument, HLLib.HLFindType.HL_FIND_ALL);
if(pSubItem != IntPtr.Zero)
{
Console.WriteLine("Information for {0}:", GetPath(pSubItem));
Console.WriteLine();
switch(HLLib.hlItemGetType(pSubItem))
{
case HLLib.HLDirectoryItemType.HL_ITEM_FOLDER:
Console.WriteLine(" Type: Folder");
Console.WriteLine(" Size: {0} B", HLLib.hlFolderGetSizeEx(pSubItem, true));
Console.WriteLine(" Size On Disk: {0} B", HLLib.hlFolderGetSizeOnDiskEx(pSubItem, true));
Console.WriteLine(" Folders: {0}", HLLib.hlFolderGetFolderCount(pSubItem, true));
Console.WriteLine(" Files: {0}", HLLib.hlFolderGetFileCount(pSubItem, true));
break;
case HLLib.HLDirectoryItemType.HL_ITEM_FILE:
Console.WriteLine(" Type: File");
Console.WriteLine(" Extractable: {0}", HLLib.hlFileGetExtractable(pSubItem) != 0 ? "True" : "False");
//Console.WriteLine(" Validates: {0}", HLLib.hlFileGetValidates(pSubItem) ? "True" : "False");
Console.WriteLine(" Size: {0} B", HLLib.hlFileGetSize(pSubItem));
Console.WriteLine(" Size On Disk: {0} B", HLLib.hlFileGetSizeOnDisk(pSubItem));
break;
}
uint uiAttributeCount = HLLib.hlPackageGetItemAttributeCount();
for(uint i = 0; i < uiAttributeCount; i++)
{
HLLib.HLAttribute Attribute;
if(HLLib.hlPackageGetItemAttribute(pSubItem, (HLLib.HLPackageAttribute)i, out Attribute))
{
if(Attribute.eAttributeType != HLLib.HLAttributeType.HL_ATTRIBUTE_INVALID)
{
Console.WriteLine(" {0}: {1}", Attribute.GetName(), Attribute.ToString());
}
}
}
Console.WriteLine();
}
else
{
Console.WriteLine("{0} not found.", sArgument);
}
}
}
//
// Extract item.
// Good example of CPackageUtility extract functions.
//
else if(String.Equals(sCommand, "extract", StringComparison.CurrentCultureIgnoreCase))
{
if(sArgument.Length == 0)
{
Console.WriteLine("No argument for command extract supplied.");
}
else
{
IntPtr pSubItem;
if(String.Equals(sArgument, ".", StringComparison.CurrentCultureIgnoreCase))
{
pSubItem = pItem;
}
else
{
pSubItem = HLLib.hlFolderGetItemByName(pItem, sArgument, HLLib.HLFindType.HL_FIND_ALL);
}
if(pSubItem != IntPtr.Zero)
{
// Extract the item.
// Item is extracted to cDestination\Item->GetName().
if(!bSilent)
{
Console.WriteLine("Extracting {0}...", HLLib.hlItemGetName(pSubItem));
Console.WriteLine();
}
HLLib.hlItemExtract(pSubItem, sDestination);
if(!bSilent)
{
Console.WriteLine("");
Console.WriteLine("Done.");
}
}
else
{
Console.WriteLine("{0} not found.", sArgument);
}
}
}
//
// Validate item.
// Validates the checksums of each item.
//
else if(String.Equals(sCommand, "validate", StringComparison.CurrentCultureIgnoreCase))
{
if(sArgument.Length == 0)
{
Console.WriteLine("No argument for command extract supplied.");
}
else
{
IntPtr pSubItem;
if(String.Equals(sArgument, ".", StringComparison.CurrentCultureIgnoreCase))
{
pSubItem = pItem;
}
else
{
pSubItem = HLLib.hlFolderGetItemByName(pItem, sArgument, HLLib.HLFindType.HL_FIND_ALL);
}
if(pSubItem != IntPtr.Zero)
{
if(!bSilent)
{
Console.WriteLine("Validating {0}...", HLLib.hlItemGetName(pSubItem));
Console.WriteLine();
}
Validate(pSubItem);
if(!bSilent)
{
Console.WriteLine();
Console.WriteLine("Done.");
}
}
else
{
Console.WriteLine("{0} not found.", sArgument);
}
}
}
//
// Defragment package.
// Validates the checksums of each item.
//
else if(String.Equals(sCommand, "defragment", StringComparison.CurrentCultureIgnoreCase))
{
bool bForceDefragment = false;
if(sArgument.Length != 0)
{
try
{
bForceDefragment = Convert.ToBoolean(sArgument);
}
catch
{
}
}
if(!bSilent)
{
Console.WriteLine("Defragmenting...");
Console.WriteLine();
}
HLLib.hlSetBoolean(HLLib.HLOption.HL_FORCE_DEFRAGMENT, bForceDefragment);
Console.Write(" Progress: ");
ProgressStart();
if(!HLLib.hlPackageDefragment())
{
Console.Write(" {0}", HLLib.hlGetString(HLLib.HLOption.HL_ERROR_SHORT_FORMATED));
}
if(!bSilent)
{
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("Done.");
}
}
//
// Find items.
// Good example of recursive directory navigation (Search() function).
//
else if(String.Equals(sCommand, "find", StringComparison.CurrentCultureIgnoreCase))
{
if(sArgument.Length == 0)
{
Console.WriteLine("No argument for command find supplied.");
}
else
{
// Search for the requested items.
if(!bSilent)
{
Console.WriteLine("Searching for {0}...", sArgument);
Console.WriteLine();
}
uint uiFolderCount = 0, uiFileCount = 0;
IntPtr pSubItem = HLLib.hlFolderFindFirst(pItem, sArgument, HLLib.HLFindType.HL_FIND_ALL);
while(pSubItem != IntPtr.Zero)
{
switch(HLLib.hlItemGetType(pSubItem))
{
case HLLib.HLDirectoryItemType.HL_ITEM_FOLDER:
uiFolderCount++;
Console.WriteLine(" Found folder: {0}", GetPath(pSubItem));
break;
case HLLib.HLDirectoryItemType.HL_ITEM_FILE:
uiFileCount++;
Console.WriteLine(" Found file: {0}", GetPath(pSubItem));
break;
}
pSubItem = HLLib.hlFolderFindNext(pItem, pSubItem, sArgument, HLLib.HLFindType.HL_FIND_ALL);
}
if(!bSilent)
{
if(uiFolderCount != 0 || uiFileCount != 0)
{
Console.WriteLine();
}
Console.WriteLine(" {0} folder{1} and {2} file{3} found.", uiFolderCount, uiFolderCount != 1 ? "s" : "", uiFileCount, uiFileCount != 1 ? "s" : "");
Console.WriteLine();
}
}
}
//
// Type files.
// Good example of reading files into memory.
//
else if(String.Equals(sCommand, "type", StringComparison.CurrentCultureIgnoreCase))
{
if(sArgument.Length == 0)
{
Console.WriteLine("No argument for command type supplied.");
}
else
{
IntPtr pSubItem = HLLib.hlFolderGetItemByName(pItem, sArgument, HLLib.HLFindType.HL_FIND_FILES);
if(pSubItem != IntPtr.Zero)
{
if(!bSilent)
{
Console.WriteLine("Type for {0}:", GetPath(pSubItem));
Console.WriteLine();
}
IntPtr pStream;
if(HLLib.hlFileCreateStream(pSubItem, out pStream))
{
if(HLLib.hlStreamOpen(pStream, (uint)HLLib.HLFileMode.HL_MODE_READ))
{
char iChar;
while(HLLib.hlStreamReadChar(pStream, out iChar))
{
if((iChar >= ' ' && iChar <= '~') || iChar == '\n' || iChar == '\t')
{
Console.Write(iChar);
}
}
HLLib.hlStreamClose(pStream);
}
else
{
Console.WriteLine("Error typing {0}:", HLLib.hlItemGetName(pSubItem));
Console.WriteLine(HLLib.hlGetString(HLLib.HLOption.HL_ERROR_SHORT_FORMATED));
}
HLLib.hlFileReleaseStream(pSubItem, pStream);
}
else
{
Console.WriteLine("Error typing {0}:", HLLib.hlItemGetName(pSubItem));
Console.WriteLine(HLLib.hlGetString(HLLib.HLOption.HL_ERROR_SHORT_FORMATED));
}
if(!bSilent)
{
Console.WriteLine();
Console.WriteLine("Done.");
}
}
else
{
Console.WriteLine("{0} not found.", sArgument);
}
}
}
//
// Open item.
// Good example of opening packages inside packages.
//
else if(String.Equals(sCommand, "open", StringComparison.CurrentCultureIgnoreCase))
{
if(sArgument.Length == 0)
{
Console.WriteLine("No argument for command open supplied.");
}
else
{
IntPtr pSubItem = HLLib.hlFolderGetItemByName(pItem, sArgument, HLLib.HLFindType.HL_FIND_FILES);
if(pSubItem != IntPtr.Zero)
{
IntPtr pStream;
if(HLLib.hlFileCreateStream(pSubItem, out pStream))
{
if(HLLib.hlStreamOpen(pStream, (uint)HLLib.HLFileMode.HL_MODE_READ))
{
HLLib.HLPackageType ePackageType = HLLib.hlGetPackageTypeFromStream(pStream);
uint uiSubPackage;
if(HLLib.hlCreatePackage(ePackageType, out uiSubPackage))
{
HLLib.hlBindPackage(uiSubPackage);
if(HLLib.hlPackageOpenStream(pStream, (uint)HLLib.HLFileMode.HL_MODE_READ))
{
if(!bSilent)
Console.WriteLine("{0} opened.", HLLib.hlItemGetName(pSubItem));
EnterConsole(uiSubPackage, Commands);
HLLib.hlPackageClose();
if(!bSilent)
Console.WriteLine("{0} closed.", HLLib.hlItemGetName(pSubItem));
}
else
{
Console.WriteLine("Error opening {0}:", HLLib.hlItemGetName(pSubItem));
Console.WriteLine(HLLib.hlGetString(HLLib.HLOption.HL_ERROR_SHORT_FORMATED));
}
HLLib.hlDeletePackage(uiSubPackage);
HLLib.hlBindPackage(uiPackage);
}
else
{
Console.WriteLine("Error opening {0}:", HLLib.hlItemGetName(pSubItem));
Console.WriteLine(HLLib.hlGetString(HLLib.HLOption.HL_ERROR_SHORT_FORMATED));
}
HLLib.hlStreamClose(pStream);
}
else
{
Console.WriteLine("Error opening {0}:", HLLib.hlItemGetName(pSubItem));
Console.WriteLine(HLLib.hlGetString(HLLib.HLOption.HL_ERROR_SHORT_FORMATED));
}
HLLib.hlFileReleaseStream(pSubItem, pStream);
}
else
{
Console.WriteLine("Error opening {0}:", HLLib.hlItemGetName(pSubItem));
Console.WriteLine(HLLib.hlGetString(HLLib.HLOption.HL_ERROR_SHORT_FORMATED));
}
}
else
{
Console.WriteLine("{0} not found.", sArgument);
}
}
}
//
// Clear screen.
//
else if(String.Equals(sCommand, "status", StringComparison.CurrentCultureIgnoreCase))
{
Console.WriteLine("Total size: {0} B", HLLib.hlGetUnsignedLong(HLLib.HLOption.HL_PACKAGE_SIZE));
Console.WriteLine("Total mapping allocations: {0}", HLLib.hlGetUnsignedInteger(HLLib.HLOption.HL_PACKAGE_TOTAL_ALLOCATIONS));
Console.WriteLine("Total mapping memory allocated: {0} B", HLLib.hlGetUnsignedLong(HLLib.HLOption.HL_PACKAGE_TOTAL_MEMORY_ALLOCATED));
Console.WriteLine("Total mapping memory used: {0} B", HLLib.hlGetUnsignedLong(HLLib.HLOption.HL_PACKAGE_TOTAL_MEMORY_USED));
uint uiAttributeCount = HLLib.hlPackageGetAttributeCount();
for(uint i = 0; i < uiAttributeCount; i++)
{
HLLib.HLAttribute Attribute;
if(HLLib.hlPackageGetAttribute((HLLib.HLPackageAttribute)i, out Attribute))
{
if(Attribute.eAttributeType != HLLib.HLAttributeType.HL_ATTRIBUTE_INVALID)
{
Console.WriteLine("{0}: {1}", Attribute.GetName(), Attribute.ToString());
}
}
}
}
else if(String.Equals(sCommand, "exec", StringComparison.CurrentCultureIgnoreCase) || String.Equals(sCommand, "execute", StringComparison.CurrentCultureIgnoreCase))
{
if(sArgument.Length == 0)
{
Console.WriteLine("No argument for command open supplied.");
}
else
{
string[] NewCommands = sArgument.Split(new char[] { '|' });
Commands.AddRange(NewCommands);
}
}
else if(String.Equals(sCommand, "cls", StringComparison.CurrentCultureIgnoreCase))
{
try
{
Console.Clear();
}
catch
{
}
}
else if(String.Equals(sCommand, "help", StringComparison.CurrentCultureIgnoreCase))
{
Console.WriteLine("Valid commands:");
Console.WriteLine();
Console.WriteLine("dir <filter> (Directory list.)");
Console.WriteLine("cd <folder> (Change directroy.)");
Console.WriteLine("info <item> (Item information.)");
Console.WriteLine("extract <item> (Extract item.)");
Console.WriteLine("validate <item> (Validate item.)");
Console.WriteLine("defragment [force] (Defragment package.)");
Console.WriteLine("find <filter> (Find item.)");
Console.WriteLine("type <file> (Type a file.)");
Console.WriteLine("open <file> (Open a nested package.)");
Console.WriteLine("root (Go to the root folder.)");
Console.WriteLine("status (Package information.)");
Console.WriteLine("execute <cmd>|... (Execute 1 or more pipe delimited commands.)");
Console.WriteLine("cls (Clear the screen.)");
Console.WriteLine("help (Program help.)");
Console.WriteLine("exit (Quit program.)");
Console.WriteLine();
}
else if(String.Equals(sCommand, "exit", StringComparison.CurrentCultureIgnoreCase))
{
break;
}
else
{
Console.WriteLine("Unkown command: {0}", sCommand);
}
}
}
}
}