/* * HLExtract * Copyright (C) 2006-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. */ #ifdef _WIN32 # include "..\lib\HLLib.h" # ifdef _MSC_VER # ifdef _DEBUG # ifdef _WIN64 # pragma comment(lib, "../HLLib/x64/Debug/HLLib.lib") # else # pragma comment(lib, "../HLLib/Win32/Debug/HLLib.lib") # endif # else # ifdef _WIN64 # pragma comment(lib, "../HLLib/x64/Release/HLLib.lib") # else # pragma comment(lib, "../HLLib/Win32/Release/HLLib.lib") # endif # endif # endif #else # include "../lib/HLLib.h" #endif #if _MSC_VER # define _CRT_SECURE_NO_WARNINGS # define _CRT_NONSTDC_NO_DEPRECATE #endif #include #include #include #include #include #include #include #include #ifdef _WIN32 # define WIN32_LEAN_AND_MEAN # define UNUSED # include #else # include # include # define MAX_PATH PATH_MAX # define UNUSED __attribute__((__unused__)) # define FOREGROUND_RED 0x0001 # define FOREGROUND_GREEN 0x0002 # define FOREGROUND_BLUE 0x0004 # define FOREGROUND_INTENSITY 0x0008 # define stricmp strcasecmp # define strnicmp strncasecmp #endif hlUInt16 GetColor(); hlVoid SetColor(hlUInt16 uiColor); hlVoid Print(hlUInt16 uiColor, const hlChar *lpFormat, ...); hlVoid PrintUsage(); hlVoid List(FILE *pFile, HLDirectoryItem *pItem, hlBool bListFolders, hlBool bListFiles); hlVoid ProgressStart(); hlVoid ProgressUpdate(hlULongLong uiBytesDone, hlULongLong uiBytesTotal); hlVoid ExtractItemStartCallback(HLDirectoryItem *pItem); hlVoid FileProgressCallback(HLDirectoryItem *pFile, hlUInt uiBytesExtracted, hlUInt uiBytesTotal, hlBool *pCancel); hlVoid ExtractItemEndCallback(HLDirectoryItem *pItem, hlBool bSuccess); hlVoid DefragmentProgressCallback(HLDirectoryItem *pFile, hlUInt uiFilesDefragmented, hlUInt uiFilesTotal, hlULongLong uiBytesDefragmented, hlULongLong uiBytesTotal, hlBool *pCancel); HLValidation Validate(HLDirectoryItem *pItem); hlVoid PrintAttribute(hlChar *lpPrefix, HLAttribute *pAttribute, hlChar *lpPostfix); hlVoid PrintValidation(HLValidation eValidation); hlVoid EnterConsole(hlUInt uiPackage, hlUInt uiConsoleCommands, hlChar *lpConsoleCommands[]); #define MAX_ITEMS 1024 #define BUFFER_SIZE 1024 static hlChar lpDestination[MAX_PATH] = ""; static hlBool bSilent = hlFalse; #ifndef _WIN32 static hlUInt uiProgressLast = 0; static hlUInt16 uiCurrentColor = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; #endif int main(hlInt argc, hlChar* argv[]) { hlUInt i; // Arguments. hlUInt uiArgumentCount = (hlUInt)argc; hlChar *lpPackage = 0; hlUInt uiExtractItems = 0; hlChar *lpExtractItems[MAX_ITEMS]; hlUInt uiValidateItems = 0; hlChar *lpValidateItems[MAX_ITEMS]; hlChar *lpList = 0; hlBool bDefragment = hlFalse; hlChar *lpNCFRootPath = 0; hlBool bList = hlFalse; hlBool bListFolders = hlFalse; hlBool bListFiles = hlFalse; FILE *pFile = 0; hlBool bConsoleMode = hlFalse; hlUInt uiConsoleCommands = 0; hlChar *lpConsoleCommands[MAX_ITEMS]; hlBool bFileMapping = hlFalse; hlBool bQuickFileMapping = hlFalse; hlBool bVolatileAccess = hlFalse; hlBool bOverwriteFiles = hlTrue; hlBool bForceDefragment = hlFalse; // Package stuff. HLPackageType ePackageType = HL_PACKAGE_NONE; hlUInt uiPackage = HL_ID_INVALID, uiMode = HL_MODE_INVALID; HLDirectoryItem *pItem = 0; if(hlGetUnsignedInteger(HL_VERSION) < HL_VERSION_NUMBER) { printf("Wrong HLLib version: v%s.\n", hlGetString(HL_VERSION)); return 1; } // Process switches. if(uiArgumentCount == 2) { // The user just specified a file, drop into console mode. lpPackage = argv[1]; bConsoleMode = hlTrue; bVolatileAccess = hlTrue; } else { for(i = 1; i < uiArgumentCount; i++) { if(stricmp(argv[i], "-p") == 0 || stricmp(argv[i], "--package") == 0) { if(lpPackage == 0 && i + 1 < uiArgumentCount) { lpPackage = argv[++i]; } else { PrintUsage(); return 2; } } else if(stricmp(argv[i], "-d") == 0 || stricmp(argv[i], "--dest") == 0) { if(*lpDestination == 0 && i + 1 < uiArgumentCount) { strcpy(lpDestination, argv[++i]); } else { PrintUsage(); return 2; } } else if(stricmp(argv[i], "-e") == 0 || stricmp(argv[i], "--extract") == 0) { if(i + 1 < uiArgumentCount) { if(uiExtractItems == MAX_ITEMS) { Print(FOREGROUND_RED | FOREGROUND_INTENSITY, "Error loading package:\nMAX_ITEMS\n"); return 2; } lpExtractItems[uiExtractItems++] = argv[++i]; } else { PrintUsage(); return 2; } } else if(stricmp(argv[i], "-t") == 0 || stricmp(argv[i], "--validate") == 0) { if(i + 1 < uiArgumentCount) { if(uiValidateItems == MAX_ITEMS) { Print(FOREGROUND_RED | FOREGROUND_INTENSITY, "Error loading package:\nMAX_ITEMS\n"); return 2; } lpValidateItems[uiValidateItems++] = argv[++i]; } else { PrintUsage(); return 2; } } else if(strnicmp(argv[i], "-l", 2) == 0 || stricmp(argv[i], "--list") == 0) { if(bList) { PrintUsage(); return 2; } bList = hlTrue; if(stricmp(argv[i], "-l") == 0 || stricmp(argv[i], "--list") == 0) { // By default list everything. bListFolders = hlTrue; bListFiles = hlTrue; } else { // List folders and files if specified. bListFolders = strcspn(argv[i], "dD") != strlen(argv[i]); bListFiles = strcspn(argv[i], "fF") != strlen(argv[i]); } // Check to see if we need to dump our list to a file. if(i + 1 < uiArgumentCount && *argv[i + 1] != '-') { lpList = argv[++i]; } } else if(stricmp(argv[i], "-f") == 0 || stricmp(argv[i], "--defragment") == 0) { bDefragment = hlTrue; } else if(stricmp(argv[i], "-n") == 0 || stricmp(argv[i], "--ncfroot") == 0) { if(lpNCFRootPath == 0 && i + 1 < uiArgumentCount) { lpNCFRootPath = argv[++i]; } else { PrintUsage(); return 2; } } else if(stricmp(argv[i], "-s") == 0 || stricmp(argv[i], "--silent") == 0) { bSilent = hlTrue; } else if(stricmp(argv[i], "-c") == 0 || stricmp(argv[i], "--console") == 0) { bConsoleMode = hlTrue; } else if(stricmp(argv[i], "-x") == 0 || stricmp(argv[i], "--execute") == 0) { if(i + 1 < uiArgumentCount) { if(uiConsoleCommands == MAX_ITEMS) { Print(FOREGROUND_RED | FOREGROUND_INTENSITY, "Error loading package:\nMAX_ITEMS\n"); return 2; } lpConsoleCommands[uiConsoleCommands++] = argv[++i]; } else { PrintUsage(); return 2; } } else if(stricmp(argv[i], "-m") == 0 || stricmp(argv[i], "--filemapping") == 0) { bFileMapping = hlTrue; } else if(stricmp(argv[i], "-q") == 0 || stricmp(argv[i], "--quick-filemapping") == 0) { bFileMapping = hlTrue; bQuickFileMapping = hlTrue; } else if(stricmp(argv[i], "-v") == 0 || stricmp(argv[i], "--volatile") == 0) { bVolatileAccess = hlTrue; } else if(stricmp(argv[i], "-o") == 0 || stricmp(argv[i], "--overwrite") == 0) { bOverwriteFiles = hlFalse; } else if(stricmp(argv[i], "-r") == 0 || stricmp(argv[i], "--force-defragment") == 0) { bDefragment = hlTrue; bForceDefragment = hlTrue; } else { PrintUsage(); return 2; } } } // Make sure we have something to do. if(lpPackage == 0 || (uiExtractItems == 0 && uiValidateItems == 0 && !bList && !bDefragment && !bConsoleMode)) { PrintUsage(); return 2; } // If the destination directory is not specified, make it the input directory. if(*lpDestination == 0) { const hlChar *pForward = strrchr(lpPackage, '\\'); const hlChar *pBackward = strrchr(lpPackage, '/'); const hlChar *pEnd = pForward > pBackward ? pForward : pBackward; if(pEnd != 0) { strncpy(lpDestination, lpPackage, pEnd - lpPackage); lpDestination[pEnd - lpPackage] = '\0'; } } hlInitialize(); hlSetBoolean(HL_OVERWRITE_FILES, bOverwriteFiles); hlSetBoolean(HL_FORCE_DEFRAGMENT, bForceDefragment); hlSetVoid(HL_PROC_EXTRACT_ITEM_START, ExtractItemStartCallback); hlSetVoid(HL_PROC_EXTRACT_ITEM_END, ExtractItemEndCallback); hlSetVoid(HL_PROC_EXTRACT_FILE_PROGRESS, FileProgressCallback); hlSetVoid(HL_PROC_VALIDATE_FILE_PROGRESS, FileProgressCallback); hlSetVoid(HL_PROC_DEFRAGMENT_PROGRESS_EX, DefragmentProgressCallback); // Get the package type from the filename extension. ePackageType = hlGetPackageTypeFromName(lpPackage); // If the above fails, try getting the package type from the data at the start of the file. if(ePackageType == HL_PACKAGE_NONE) { pFile = fopen(lpPackage, "rb"); if(pFile != 0) { hlByte lpBuffer[HL_DEFAULT_PACKAGE_TEST_BUFFER_SIZE]; hlUInt uiBufferSize = (hlUInt)fread(lpBuffer, 1, HL_DEFAULT_PACKAGE_TEST_BUFFER_SIZE, pFile); ePackageType = hlGetPackageTypeFromMemory(lpBuffer, uiBufferSize); fclose(pFile); pFile = 0; } } if(ePackageType == HL_PACKAGE_NONE) { Print(FOREGROUND_RED | FOREGROUND_INTENSITY, "Error loading %s:\nUnsupported package type.\n", lpPackage); hlShutdown(); 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(!hlCreatePackage(ePackageType, &uiPackage)) { Print(FOREGROUND_RED | FOREGROUND_INTENSITY, "Error loading %s:\n%s\n", lpPackage, hlGetString(HL_ERROR_SHORT_FORMATED)); hlShutdown(); return 3; } hlBindPackage(uiPackage); uiMode = HL_MODE_READ | (bDefragment ? HL_MODE_WRITE : 0); uiMode |= !bFileMapping ? HL_MODE_NO_FILEMAPPING : 0; uiMode |= bQuickFileMapping ? HL_MODE_QUICK_FILEMAPPING : 0; uiMode |= bVolatileAccess ? HL_MODE_VOLATILE : 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(!hlPackageOpenFile(lpPackage, uiMode)) { Print(FOREGROUND_RED | FOREGROUND_INTENSITY, "Error loading %s:\n%s\n", lpPackage, hlGetString(HL_ERROR_SHORT_FORMATED)); hlShutdown(); 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 == HL_PACKAGE_NCF) { hlNCFFileSetRootPath(lpNCFRootPath); } if(!bSilent) Print(FOREGROUND_GREEN | FOREGROUND_INTENSITY, "%s opened.\n", lpPackage); // Extract the requested items. for(i = 0; i < uiExtractItems; i++) { // Find the item. pItem = hlFolderGetItemByPath(hlPackageGetRoot(), lpExtractItems[i], HL_FIND_ALL); if(pItem == 0) { printf("%s not found in package.\n", lpExtractItems[i]); continue; } if(!bSilent) { Print(FOREGROUND_GREEN | FOREGROUND_INTENSITY, "Extracting %s...\n", hlItemGetName(pItem)); printf("\n"); } // Extract the item. // Item is extracted to cDestination\Item->GetName(). hlItemExtract(pItem, lpDestination); if(!bSilent) { printf("\n"); printf("Done.\n"); } } // Validate the requested items. for(i = 0; i < uiValidateItems; i++) { // Find the item. pItem = hlFolderGetItemByPath(hlPackageGetRoot(), lpValidateItems[i], HL_FIND_ALL); if(pItem == 0) { printf("%s not found in package.\n", lpValidateItems[i]); continue; } if(!bSilent) { Print(FOREGROUND_GREEN | FOREGROUND_INTENSITY, "Validating %s...\n", hlItemGetName(pItem)); printf("\n"); } // Validate the item. Validate(pItem); if(!bSilent) { printf("\n"); printf("Done.\n"); } } // List items in package. if(bList) { if(!bSilent) { printf("Listing...\n"); printf("\n"); } pFile = stdout; if(lpList != 0) { pFile = fopen(lpList, "wt"); if(pFile == 0) { Print(FOREGROUND_RED | FOREGROUND_INTENSITY, "Error opening %s:\n%s\n", lpList, "fopen() failed."); pFile = stdout; } } List(pFile, hlPackageGetRoot(), bListFolders, bListFiles); if(lpList != 0) { fclose(pFile); pFile = 0; } if(!bSilent) { printf("\n"); printf("Done.\n"); } } if(bDefragment) { if(!bSilent) { printf("Defragmenting...\n"); printf("\n"); ProgressStart(); printf(" Progress: "); } if(!hlPackageDefragment()) { Print(FOREGROUND_RED | FOREGROUND_INTENSITY, " %s", hlGetString(HL_ERROR_SHORT_FORMATED)); } if(!bSilent) { printf("\n"); printf("\n"); printf("Done.\n"); } } // Interactive console mode. // Commands: dir, cd, root, info, extract, find, type, cls, help, exit. if(bConsoleMode) { EnterConsole(uiPackage, uiConsoleCommands, lpConsoleCommands); } // Close the package. hlPackageClose(); if(!bSilent) Print(FOREGROUND_GREEN | FOREGROUND_INTENSITY, "%s closed.\n", lpPackage); // Free up the allocated memory. hlDeletePackage(uiPackage); hlShutdown(); return 0; } hlUInt16 GetColor() { #ifdef _WIN32 HANDLE Handle = GetStdHandle(STD_OUTPUT_HANDLE); if (Handle != INVALID_HANDLE_VALUE) { CONSOLE_SCREEN_BUFFER_INFO Info; if(GetConsoleScreenBufferInfo(Handle, &Info)) { return Info.wAttributes; } } return FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; #else return uiCurrentColor; #endif } hlVoid SetColor(hlUInt16 uiColor) { #ifdef _WIN32 HANDLE Handle = GetStdHandle(STD_OUTPUT_HANDLE); if (Handle == INVALID_HANDLE_VALUE) { return; } SetConsoleTextAttribute(Handle, uiColor); #else hlUInt16 uiColorPart; if (!isatty(fileno(stdout))) { // cowardly refuse to write colors into things that aren't terminals return; } uiColorPart = (uiColor & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)); if (uiColorPart == 0) { // cowardly refuse to switch to black return; } // start with "reset" attribute printf("\033[0"); // handle white as the default case if (uiColorPart != (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)) { printf(";3%d", uiColorPart); } // activate intensity if wanted if ((uiColor & FOREGROUND_INTENSITY) != 0) { printf(";1"); } // finish printf("m"); fflush(stdout); // store for next time uiCurrentColor = uiColor; #endif } hlVoid Print(hlUInt16 uiColor, const hlChar *lpFormat, ...) { hlUInt16 uiDefaultColor; va_list List; uiDefaultColor = GetColor(); if(uiDefaultColor != uiColor) { SetColor(uiColor); } va_start(List, lpFormat); vprintf(lpFormat, List); va_end(List); if(uiDefaultColor != uiColor) { SetColor(uiDefaultColor); } } hlVoid PrintUsage() { printf("HLExtract using HLLib v%s\n", hlGetString(HL_VERSION)); printf("\n"); printf("Correct HLExtract usage:\n"); printf(" -p (Package to load.)\n"); printf(" -d (Destination extraction directory.)\n"); printf(" -e (Item in package to extract.)\n"); printf(" -t (Item in package to validate.)\n"); printf(" -l[d][f] [filepath] (List the contents of the package.)\n"); printf(" -f (Defragment package.)\n"); printf(" -c (Console mode.)\n"); printf(" -x (Execute console command.)\n"); printf(" -s (Silent mode.)\n"); printf(" -m (Use file mapping.)\n"); printf(" -q (Use quick file mapping.)\n"); printf(" -v (Allow volatile access.)\n"); printf(" -o (Don't overwrite files.)\n"); printf(" -r (Force defragmenting on all files.)\n"); printf(" -n (NCF file's root path.)\n"); printf("\n"); printf("Example HLExtract usage:\n"); #ifdef _WIN32 printf("HLExtract.exe -p \"C:\\half-life.gcf\" -d \"C:\\backup\" -e \"root\\valve\\models\" -e \"root\\valve\\config.cfg\"\n"); printf("HLExtract.exe -p \"C:\\half-life.gcf\" -c -m -v\n"); printf("HLExtract.exe -p \"C:\\half-life.gcf\" -lf \"C:\\half-life.txt\" -m -s\n"); printf("HLExtract.exe -p \"C:\\half-life.gcf\" -m -f\n"); #else printf("hlextract -p ~/half-life.gcf -d ~/backup -e \"root/valve/models\" -e \"root/valve/config.cfg\"\n"); printf("hlextract -p ~/half-life.gcf -c -m -v\n"); printf("hlextract -p ~/half-life.gcf -lf ~/half-life.txt -m -s\n"); printf("hlextract -p ~/half-life.gcf -m -f\n"); #endif } hlVoid List(FILE *pFile, HLDirectoryItem *pItem, hlBool bListFolders, hlBool bListFiles) { hlUInt i, uiItemCount; hlChar lpPath[512] = ""; switch(hlItemGetType(pItem)) { case HL_ITEM_FOLDER: if(bListFolders) { hlItemGetPath(pItem, lpPath, sizeof(lpPath)); fprintf(pFile, "%s\n", lpPath); } uiItemCount = hlFolderGetCount(pItem); for(i = 0; i < uiItemCount; i++) { List(pFile, hlFolderGetItem(pItem, i), bListFolders, bListFiles); } break; case HL_ITEM_FILE: if(bListFiles) { hlItemGetPath(pItem, lpPath, sizeof(lpPath)); fprintf(pFile, "%s\n", lpPath); } break; default: break; } } hlVoid ProgressStart() { #ifndef _WIN32 uiProgressLast = 0; printf("0%%"); #endif } hlVoid ProgressUpdate(hlULongLong uiBytesDone, hlULongLong uiBytesTotal) { if(!bSilent) { #ifdef _WIN32 HANDLE Handle = GetStdHandle(STD_OUTPUT_HANDLE); if (Handle != INVALID_HANDLE_VALUE) { CONSOLE_SCREEN_BUFFER_INFO Info; if(GetConsoleScreenBufferInfo(Handle, &Info)) { if(uiBytesTotal == 0) { printf("100.0%%"); } else { printf("%0.0f%%", (hlSingle)((hlDouble)uiBytesDone / (hlDouble)uiBytesTotal * 100.0)); } SetConsoleCursorPosition(Handle, Info.dwCursorPosition); } } #else hlUInt uiProgress = uiBytesTotal == 0 ? 100 : (hlUInt)((hlUInt64)uiBytesDone * 100 / (hlUInt64)uiBytesTotal); while(uiProgress >= uiProgressLast + 10) { uiProgressLast += 10; if(uiProgressLast == 100) { printf("100%% "); } else if(uiProgressLast == 50) { printf("50%%"); } else { printf("."); } } fflush(stdout); #endif } } hlVoid ExtractItemStartCallback(HLDirectoryItem *pItem) { if(!bSilent) { if(hlItemGetType(pItem) == HL_ITEM_FILE) { printf(" Extracting %s: ", hlItemGetName(pItem)); ProgressStart(); } else { Print(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, " Extracting %s:\n", hlItemGetName(pItem)); } } } hlVoid FileProgressCallback(HLDirectoryItem *pFile UNUSED, hlUInt uiBytesExtracted, hlUInt uiBytesTotal, hlBool *pCancel UNUSED) { ProgressUpdate((hlULongLong)uiBytesExtracted, (hlULongLong)uiBytesTotal); } hlVoid ExtractItemEndCallback(HLDirectoryItem *pItem, hlBool bSuccess) { hlUInt uiSize = 0; hlChar lpPath[512] = ""; if(bSuccess) { if(!bSilent) { hlItemGetSize(pItem, &uiSize); if(hlItemGetType(pItem) == HL_ITEM_FILE) { Print(FOREGROUND_GREEN | FOREGROUND_INTENSITY, "OK"); printf(" (%u B)\n", uiSize); } else { Print(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, " Done %s: ", hlItemGetName(pItem)); Print(FOREGROUND_GREEN | FOREGROUND_INTENSITY, "OK"); Print(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, " (%u B)\n", uiSize); } } } else { if(!bSilent) { if(hlItemGetType(pItem) == HL_ITEM_FILE) { Print(FOREGROUND_RED | FOREGROUND_INTENSITY, "Errored\n"); Print(FOREGROUND_RED | FOREGROUND_INTENSITY, " %s\n", hlGetString(HL_ERROR_SHORT_FORMATED)); } else { Print(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, " Done %s: ", hlItemGetName(pItem)); Print(FOREGROUND_RED | FOREGROUND_INTENSITY, "Errored\n"); } } else { hlItemGetPath(pItem, lpPath, sizeof(lpPath)); if(hlItemGetType(pItem) == HL_ITEM_FILE) { Print(FOREGROUND_RED | FOREGROUND_INTENSITY, " Error extracting %s:\n", lpPath); Print(FOREGROUND_RED | FOREGROUND_INTENSITY, " %s\n", hlGetString(HL_ERROR_SHORT_FORMATED)); } else { Print(FOREGROUND_RED | FOREGROUND_INTENSITY, " Error extracting %s.\n", lpPath); } } } } hlVoid DefragmentProgressCallback(HLDirectoryItem *pFile UNUSED, hlUInt uiFilesDefragmented UNUSED, hlUInt uiFilesTotal UNUSED, hlULongLong uiBytesDefragmented, hlULongLong uiBytesTotal, hlBool *pCancel UNUSED) { ProgressUpdate(uiBytesDefragmented, uiBytesTotal); } HLValidation Validate(HLDirectoryItem *pItem) { hlUInt i, uiItemCount; hlChar lpPath[512] = ""; HLValidation eValidation = HL_VALIDATES_OK, eTest; switch(hlItemGetType(pItem)) { case HL_ITEM_FOLDER: if(!bSilent) { Print(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, " Validating %s:\n", hlItemGetName(pItem)); } uiItemCount = hlFolderGetCount(pItem); for(i = 0; i < uiItemCount; i++) { eTest = Validate(hlFolderGetItem(pItem, i)); if(eTest > eValidation) { eValidation = eTest; } } if(!bSilent) { Print(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, " Done %s: ", hlItemGetName(pItem)); PrintValidation(eValidation); printf("\n"); } break; case HL_ITEM_FILE: if(!bSilent) { printf(" Validating %s: ", hlItemGetName(pItem)); ProgressStart(); } eValidation = hlFileGetValidation(pItem); if(bSilent) { switch(eValidation) { case HL_VALIDATES_INCOMPLETE: case HL_VALIDATES_CORRUPT: hlItemGetPath(pItem, lpPath, sizeof(lpPath)); printf(" Validating %s: ", lpPath); PrintValidation(eValidation); printf("\n"); break; default: break; } } else { PrintValidation(eValidation); printf(" \n"); } break; default: break; } return eValidation; } hlVoid PrintAttribute(hlChar *lpPrefix, HLAttribute *pAttribute, hlChar *lpPostfix) { switch(pAttribute->eAttributeType) { case HL_ATTRIBUTE_BOOLEAN: printf("%s%s: %s%s\n", lpPrefix, pAttribute->lpName, pAttribute->Value.Boolean.bValue ? "True" : "False", lpPostfix); break; case HL_ATTRIBUTE_INTEGER: printf("%s%s: %i%s\n", lpPrefix, pAttribute->lpName, pAttribute->Value.Integer.iValue, lpPostfix); break; case HL_ATTRIBUTE_UNSIGNED_INTEGER: if(pAttribute->Value.UnsignedInteger.bHexadecimal) { printf("%s%s: %#.8x%s\n", lpPrefix, pAttribute->lpName, pAttribute->Value.UnsignedInteger.uiValue, lpPostfix); } else { printf("%s%s: %u%s\n", lpPrefix, pAttribute->lpName, pAttribute->Value.UnsignedInteger.uiValue, lpPostfix); } break; case HL_ATTRIBUTE_FLOAT: printf("%s%s: %f%s\n", lpPrefix, pAttribute->lpName, pAttribute->Value.Float.fValue, lpPostfix); break; case HL_ATTRIBUTE_STRING: printf("%s%s: %s%s\n", lpPrefix, pAttribute->lpName, pAttribute->Value.String.lpValue, lpPostfix); break; default: break; } } hlVoid PrintValidation(HLValidation eValidation) { switch(eValidation) { case HL_VALIDATES_ASSUMED_OK: Print(FOREGROUND_GREEN | FOREGROUND_INTENSITY, "Assumed OK"); break; case HL_VALIDATES_OK: Print(FOREGROUND_GREEN | FOREGROUND_INTENSITY, "OK"); break; case HL_VALIDATES_INCOMPLETE: Print(FOREGROUND_RED | FOREGROUND_INTENSITY, "Incomplete"); break; case HL_VALIDATES_CORRUPT: Print(FOREGROUND_RED | FOREGROUND_INTENSITY, "Corrupt"); break; case HL_VALIDATES_CANCELED: Print(FOREGROUND_RED | FOREGROUND_INTENSITY, "Canceled"); break; case HL_VALIDATES_ERROR: Print(FOREGROUND_RED | FOREGROUND_INTENSITY, "Error"); break; default: printf("Unknown"); break; } } hlVoid EnterConsole(hlUInt uiPackage, hlUInt uiConsoleCommands, hlChar *lpConsoleCommands[]) { hlUInt i; hlChar lpBuffer[BUFFER_SIZE]; // Input string. hlChar lpCommand[BUFFER_SIZE]; // Input command (i.e. first word in input string). hlChar lpArgument[BUFFER_SIZE]; // Input argument (i.e. rest of input string). hlChar *lpTemp; hlChar lpTempBuffer[BUFFER_SIZE]; hlUInt16 uiColor; HLDirectoryItem *pItem = 0, *pSubItem = 0; hlBool bFound; hlUInt uiItemCount, uiFolderCount, uiFileCount; hlChar iChar; HLStream *pStream = 0; HLAttribute Attribute; HLPackageType ePackageType = HL_PACKAGE_NONE; hlUInt uiSubPackage = HL_ID_INVALID; pItem = hlPackageGetRoot(); while(hlTrue) { uiColor = GetColor(); SetColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); if(uiConsoleCommands > 0) { printf("%s>%s\n", hlItemGetName(pItem), *lpConsoleCommands); strncpy(lpBuffer, *lpConsoleCommands, sizeof(lpBuffer)); lpBuffer[sizeof(lpBuffer) - 1] = '\0'; uiConsoleCommands--; lpConsoleCommands++; } else { // Command prompt. printf("%s>", hlItemGetName(pItem)); // Get and parse line. fgets(lpBuffer, sizeof(lpBuffer), stdin); } SetColor(uiColor); i = (hlUInt)strlen(lpBuffer); while(i > 0 && (lpBuffer[i - 1] == '\r' || lpBuffer[i - 1] == '\n')) { i--; lpBuffer[i] = '\0'; } *lpCommand = *lpArgument = 0; strcpy(lpCommand, lpBuffer); lpTemp = strchr(lpCommand, ' '); if(lpTemp != 0) { strcpy(lpArgument, lpTemp + 1); *lpTemp = 0; } // Cycle through commands. // // Directory listing. // Good example of CDirectoryItem::GetType(). // #ifdef _WIN32 if(stricmp(lpCommand, "dir") == 0) #else if(stricmp(lpCommand, "ls") == 0) #endif { uiItemCount = hlFolderGetCount(pItem); uiFolderCount = 0, uiFileCount = 0; *lpTempBuffer = 0; hlItemGetPath(pItem, lpTempBuffer, sizeof(lpTempBuffer)); printf("Directory of %s:\n", lpTempBuffer); printf("\n"); if(*lpArgument == 0) { // List all items in the current folder. for(i = 0; i < uiItemCount; i++) { pSubItem = hlFolderGetItem(pItem, i); if(hlItemGetType(pSubItem) == HL_ITEM_FOLDER) { uiFolderCount++; printf(" <%s>\n", hlItemGetName(pSubItem)); } else if(hlItemGetType(pSubItem) == HL_ITEM_FILE) { uiFileCount++; printf(" %s\n", hlItemGetName(pSubItem)); } } } else { pSubItem = hlFolderFindFirst(pItem, lpArgument, HL_FIND_ALL | HL_FIND_NO_RECURSE); while(pSubItem) { if(hlItemGetType(pSubItem) == HL_ITEM_FOLDER) { uiFolderCount++; printf(" <%s>\n", hlItemGetName(pSubItem)); } else if(hlItemGetType(pSubItem) == HL_ITEM_FILE) { uiFileCount++; printf(" %s\n", hlItemGetName(pSubItem)); } pSubItem = hlFolderFindNext(pItem, pSubItem, lpArgument, HL_FIND_ALL | HL_FIND_NO_RECURSE); } } printf("\n"); // Could also have used hlFolderGetFolderCount() and // hlFolderGetFileCount(). printf("Summary:\n"); printf("\n"); printf(" %u Folder%s.\n", uiFolderCount, uiFolderCount != 1 ? "s" : ""); printf(" %u File%s.\n", uiFileCount, uiFileCount != 1 ? "s" : ""); printf("\n"); } // // Change directory. // Good example of CDirectoryFolder::GetParent() and item casting. // else if(stricmp(lpCommand, "cd") == 0) { if(*lpArgument == 0) { printf("No argument for command cd supplied.\n"); } else { if(stricmp(lpArgument, ".") == 0) { } else if(stricmp(lpArgument, "..") == 0) { if(hlItemGetParent(pItem) != 0) { pItem = hlItemGetParent(pItem); } else { printf("Folder does not have a parent.\n"); } } else { bFound = hlFalse; uiItemCount = hlFolderGetCount(pItem); for(i = 0; i < uiItemCount; i++) { pSubItem = hlFolderGetItem(pItem, i); if(hlItemGetType(pSubItem) == HL_ITEM_FOLDER && stricmp(lpArgument, hlItemGetName(pSubItem)) == 0) { bFound = hlTrue; pItem = pSubItem; break; } } if(!bFound) { printf("%s not found.\n", lpArgument); } } } } // // Go to the root folder. // else if(stricmp(lpCommand, "root") == 0) { pItem = hlPackageGetRoot(); } // // Item information. // Good example of CPackageUtility helper functions. // else if(stricmp(lpCommand, "info") == 0) { if(*lpArgument == 0) { printf("No argument for command info supplied.\n"); } else { pSubItem = hlFolderGetItemByPath(pItem, lpArgument, HL_FIND_ALL); if(pSubItem != 0) { *lpTempBuffer = 0; hlItemGetPath(pSubItem, lpTempBuffer, sizeof(lpTempBuffer)); printf("Information for %s:\n", lpTempBuffer); printf("\n"); switch(hlItemGetType(pSubItem)) { case HL_ITEM_FOLDER: printf(" Type: Folder\n"); #ifdef _WIN32 printf(" Size: %I64u B\n", hlFolderGetSizeEx(pSubItem, hlTrue)); printf(" Size On Disk: %I64u B\n", hlFolderGetSizeOnDiskEx(pSubItem, hlTrue)); #else printf(" Size: %llu B\n", hlFolderGetSizeEx(pSubItem, hlTrue)); printf(" Size On Disk: %llu B\n", hlFolderGetSizeOnDiskEx(pSubItem, hlTrue)); #endif printf(" Folders: %u\n", hlFolderGetFolderCount(pSubItem, hlTrue)); printf(" Files: %u\n", hlFolderGetFileCount(pSubItem, hlTrue)); break; case HL_ITEM_FILE: printf(" Type: File\n"); printf(" Extractable: %s\n", hlFileGetExtractable(pSubItem) ? "True" : "False"); //printf(" Validates: %s\n", hlFileGetValidates(pSubItem) ? "True" : "False"); printf(" Size: %u B\n", hlFileGetSize(pSubItem)); printf(" Size On Disk: %u B\n", hlFileGetSizeOnDisk(pSubItem)); break; default: break; } uiItemCount = hlPackageGetItemAttributeCount(); for(i = 0; i < uiItemCount; i++) { if(hlPackageGetItemAttribute(pSubItem, i, &Attribute)) { PrintAttribute(" ", &Attribute, ""); } } printf("\n"); } else { printf("%s not found.\n", lpArgument); } } } // // Extract item. // Good example of CPackageUtility extract functions. // else if(stricmp(lpCommand, "extract") == 0) { if(*lpArgument == 0) { printf("No argument for command extract supplied.\n"); } else { if(stricmp(lpArgument, ".") == 0) { pSubItem = pItem; } else { pSubItem = hlFolderGetItemByName(pItem, lpArgument, HL_FIND_ALL); } if(pSubItem) { // Extract the item. // Item is extracted to cDestination\Item->GetName(). if(!bSilent) { printf("Extracting %s...\n", hlItemGetName(pSubItem)); printf("\n"); } hlItemExtract(pSubItem, lpDestination); if(!bSilent) { printf("\n"); printf("Done.\n"); } } else { printf("%s not found.\n", lpArgument); } } } // // Validate item. // Validates the checksums of each item. // else if(stricmp(lpCommand, "validate") == 0) { if(*lpArgument == 0) { printf("No argument for command extract supplied.\n"); } else { if(stricmp(lpArgument, ".") == 0) { pSubItem = pItem; } else { pSubItem = hlFolderGetItemByName(pItem, lpArgument, HL_FIND_ALL); } if(pSubItem) { if(!bSilent) { printf("Validating %s...\n", hlItemGetName(pSubItem)); printf("\n"); } Validate(pSubItem); if(!bSilent) { printf("\n"); printf("Done.\n"); } } else { printf("%s not found.\n", lpArgument); } } } // // Find items. // Good example of recursive directory navigation (Search() function). // else if(stricmp(lpCommand, "find") == 0) { if(*lpArgument == 0) { printf("No argument for command find supplied.\n"); } else { // Search for the requested items. if(!bSilent) { printf("Searching for %s...\n", lpArgument); printf("\n"); } uiItemCount = 0; pSubItem = hlFolderFindFirst(pItem, lpArgument, HL_FIND_ALL); while(pSubItem) { hlItemGetPath(pSubItem, lpTempBuffer, sizeof(lpTempBuffer)); // Print the path. uiItemCount++; Print(hlItemGetType(pSubItem) == HL_ITEM_FILE ? FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY : GetColor(), " Found %s: %s\n", hlItemGetType(pSubItem) == HL_ITEM_FOLDER ? "folder" : "file", lpTempBuffer); pSubItem = hlFolderFindNext(pItem, pSubItem, lpArgument, HL_FIND_ALL); } if(!bSilent) { if(uiItemCount != 0) { printf("\n"); } printf(" %u item%s found.\n", uiItemCount, uiItemCount != 1 ? "s" : ""); printf("\n"); } } } // // Type files. // Good example of reading files into memory. // else if(stricmp(lpCommand, "type") == 0) { if(*lpArgument == 0) { printf("No argument for command type supplied.\n"); } else { pSubItem = hlFolderGetItemByName(pItem, lpArgument, HL_FIND_FILES); if(pSubItem) { *lpTempBuffer = 0; hlItemGetPath(pSubItem, lpTempBuffer, sizeof(lpTempBuffer)); if(!bSilent) { printf("Type for %s:\n", lpTempBuffer); printf("\n"); } if(hlFileCreateStream(pSubItem, &pStream)) { if(hlStreamOpen(pStream, HL_MODE_READ)) { uiColor = GetColor(); SetColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); while(hlStreamReadChar(pStream, &iChar)) { if((iChar >= ' ' && iChar <= '~') || iChar == '\n' || iChar == '\t') { putc(iChar, stdout); } } SetColor(uiColor); hlStreamClose(pStream); } else { Print(FOREGROUND_RED | FOREGROUND_INTENSITY, "Error typing %s:\n%s\n", hlItemGetName(pSubItem), hlGetString(HL_ERROR_SHORT_FORMATED)); } hlFileReleaseStream(pSubItem, pStream); pStream = 0; } else { Print(FOREGROUND_RED | FOREGROUND_INTENSITY, "Error typing %s:\n%s\n", hlItemGetName(pSubItem), hlGetString(HL_ERROR_SHORT_FORMATED)); } if(!bSilent) { printf("\n"); printf("Done.\n"); } } else { printf("%s not found.\n", lpArgument); } } } // // Open item. // Good example of opening packages inside packages. // else if(stricmp(lpCommand, "open") == 0) { if(*lpArgument == 0) { printf("No argument for command open supplied.\n"); } else { pSubItem = hlFolderGetItemByName(pItem, lpArgument, HL_FIND_FILES); if(pSubItem) { if(hlFileCreateStream(pSubItem, &pStream)) { if(hlStreamOpen(pStream, HL_MODE_READ)) { ePackageType = hlGetPackageTypeFromStream(pStream); if(hlCreatePackage(ePackageType, &uiSubPackage)) { hlBindPackage(uiSubPackage); if(hlPackageOpenStream(pStream, HL_MODE_READ)) { if(!bSilent) Print(FOREGROUND_GREEN | FOREGROUND_INTENSITY, "%s opened.\n", hlItemGetName(pSubItem)); EnterConsole(uiSubPackage, uiConsoleCommands, lpConsoleCommands); hlPackageClose(); if(!bSilent) Print(FOREGROUND_GREEN | FOREGROUND_INTENSITY, "%s closed.\n", hlItemGetName(pSubItem)); } else { Print(FOREGROUND_RED | FOREGROUND_INTENSITY, "Error opening %s:\n%s\n", hlItemGetName(pSubItem), hlGetString(HL_ERROR_SHORT_FORMATED)); } hlDeletePackage(uiSubPackage); hlBindPackage(uiPackage); } else { Print(FOREGROUND_RED | FOREGROUND_INTENSITY, "Error opening %s:\n%s\n", hlItemGetName(pSubItem), hlGetString(HL_ERROR_SHORT_FORMATED)); } hlStreamClose(pStream); } else { Print(FOREGROUND_RED | FOREGROUND_INTENSITY, "Error opening %s:\n%s\n", hlItemGetName(pSubItem), hlGetString(HL_ERROR_SHORT_FORMATED)); } hlFileReleaseStream(pSubItem, pStream); pStream = 0; } else { Print(FOREGROUND_RED | FOREGROUND_INTENSITY, "Error opening %s:\n%s\n", hlItemGetName(pSubItem), hlGetString(HL_ERROR_SHORT_FORMATED)); } } else { printf("%s not found.\n", lpArgument); } } } // // Clear screen. // else if(stricmp(lpCommand, "status") == 0) { #ifdef _WIN32 printf("Total size: %I64u B\n", hlGetUnsignedLongLong(HL_PACKAGE_SIZE)); #else printf("Total size: %llu B\n", hlGetUnsignedLongLong(HL_PACKAGE_SIZE)); #endif printf("Total mapping allocations: %u\n", hlGetUnsignedInteger(HL_PACKAGE_TOTAL_ALLOCATIONS)); #ifdef _WIN32 printf("Total mapping memory allocated: %I64u B\n", hlGetUnsignedLongLong(HL_PACKAGE_TOTAL_MEMORY_ALLOCATED)); printf("Total mapping memory used: %I64u B\n", hlGetUnsignedLongLong(HL_PACKAGE_TOTAL_MEMORY_USED)); #else printf("Total mapping memory allocated: %llu B\n", hlGetUnsignedLongLong(HL_PACKAGE_TOTAL_MEMORY_ALLOCATED)); printf("Total mapping memory used: %llu B\n", hlGetUnsignedLongLong(HL_PACKAGE_TOTAL_MEMORY_USED)); #endif uiItemCount = hlPackageGetAttributeCount(); for(i = 0; i < uiItemCount; i++) { if(hlPackageGetAttribute(i, &Attribute)) { PrintAttribute("", &Attribute, ""); } } } #ifdef _WIN32 else if(stricmp(lpCommand, "cls") == 0) { system("cls"); } #endif else if(stricmp(lpCommand, "help") == 0) { printf("Valid commands:\n"); printf("\n"); #ifdef _WIN32 printf("dir (Directory list.)\n"); #else printf("ls (Directory list.)\n"); #endif printf("cd (Change directroy.)\n"); printf("info (Item information.)\n"); printf("extract (Extract item.)\n"); printf("validate (Validate item.)\n"); printf("find (Find item.)\n"); printf("type (Type a file.)\n"); printf("open (Open a nested package.)\n"); printf("root (Go to the root folder.)\n"); printf("status (Package information.)\n"); #ifdef _WIN32 printf("cls (Clear the screen.)\n"); #endif printf("help (Program help.)\n"); printf("exit (Quit program.)\n"); printf("\n"); } else if(stricmp(lpCommand, "exit") == 0) { break; } else { printf("Unkown command: %s\n", lpCommand); } } }