/* * 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 Commands = new List(); 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 (Package to load.)"); Console.WriteLine(" -d (Destination extraction directory.)"); Console.WriteLine(" -x (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 (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 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 (Directory list.)"); Console.WriteLine("cd (Change directroy.)"); Console.WriteLine("info (Item information.)"); Console.WriteLine("extract (Extract item.)"); Console.WriteLine("validate (Validate item.)"); Console.WriteLine("defragment [force] (Defragment package.)"); Console.WriteLine("find (Find item.)"); Console.WriteLine("type (Type a file.)"); Console.WriteLine("open (Open a nested package.)"); Console.WriteLine("root (Go to the root folder.)"); Console.WriteLine("status (Package information.)"); Console.WriteLine("execute |... (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); } } } } }