I have created a function ListFilesBFS which lists folders and files using BFS and the output file undergoes compression and encryption. This works fine.
I tried to go 1 step further to also include a command argument to specify the type of extension that I want to list and created another function ListFilesByExtensionBFS. I managed to get the output file which lists the files based on the specific extension but my compression fails. Would like to seek some wisdom on this.
#include <iostream>#include <fstream>#include <Windows.h>#include <string>#include <vector>#include <queue>#include <compressapi.h> //Linker to Cabinet.lib#include <codecvt>#include <stdio.h>#include <bcrypt.h>#pragma comment(lib, "bcrypt.lib")#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)// Function to list files in BFS ordervoid ListFilesBFS(const std::wstring& inputDirectoryPath, std::wofstream& out) { // Create a queue to hold directory paths to be processed std::queue<std::wstring> pathsQueue; // Push the input directory path to start the traversal pathsQueue.push(inputDirectoryPath); // Loop until all directories have been processed while (!pathsQueue.empty()) { // Get the current directory path from the front of the queue std::wstring currentPath = pathsQueue.front(); // Remove element at front of the queue // FIFO pathsQueue.pop(); // Construct the search path with extended-length path format std::wstring searchPath = LR"(\\?\)" + currentPath + L"\\*"; // Find the first file or directory in the current directory WIN32_FIND_DATAW findFileData; HANDLE hFind = FindFirstFileW(searchPath.c_str(), &findFileData); if (hFind == INVALID_HANDLE_VALUE) { // If unable to traverse the directory, print error and continue to next iteration std::wcerr << L"Error traversing directory: " << currentPath << std::endl; continue; } // Iterate through all files and directories in the current directory do { // Get the name of the file or directory std::wstring fileName = findFileData.cFileName; // Ignore '.' and '..' directories if (fileName != L"." && fileName != L"..") { // Construct the full path of the file or directory std::wstring fullPath = currentPath + L"\\" + fileName; // Convert FILETIME to SYSTEMTIME SYSTEMTIME creationTime; FileTimeToSystemTime(&findFileData.ftCreationTime, &creationTime); // Format the creation time string wchar_t creationTimeString[20]; // Buffer for the formatted time string swprintf(creationTimeString, 20, L"%04d/%02d/%02d %02d:%02d:%02d", creationTime.wYear, creationTime.wMonth, creationTime.wDay, creationTime.wHour, creationTime.wMinute, creationTime.wSecond); // Construct the string containing file information std::wstring fileInfo = fullPath + L" " + std::to_wstring(findFileData.nFileSizeLow) + L" " + creationTimeString; // Write the file information string to the output file stream out << fileInfo << std::endl; // If it's a directory, add it to the queue for further traversal if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { pathsQueue.push(fullPath); } } } while (FindNextFileW(hFind, &findFileData) != 0); // Check for errors or end of directory DWORD dwError = GetLastError(); if (dwError != ERROR_NO_MORE_FILES){ std::wcerr << L"Error while traversing directory: " << dwError << std::endl; } // Close the handle to the directory FindClose(hFind); }}// Function to list files in BFS ordervoid ListFilesByExtensionBFS(const std::wstring& inputDirectoryPath, const std::wstring& extension, std::wofstream& out) { // Create a queue to hold directory paths to be processed std::queue<std::wstring> pathsQueue; // Push the input directory path to start the traversal pathsQueue.push(inputDirectoryPath); // Loop until all directories have been processed while (!pathsQueue.empty()) { // Get the current directory path from the front of the queue std::wstring currentPath = pathsQueue.front(); // Remove element at front of the queue // FIFO pathsQueue.pop(); // Construct the search path with extended-length path format std::wstring searchPath = LR"(\\?\)" + currentPath + L"\\*"; // Find the first file or directory in the current directory WIN32_FIND_DATAW findFileData; HANDLE hFind = FindFirstFileW(searchPath.c_str(), &findFileData); if (hFind == INVALID_HANDLE_VALUE) { // If unable to traverse the directory, print error and continue to next iteration std::wcerr << L"Error traversing directory: " << currentPath << std::endl; continue; } // Iterate through all files and directories in the current directory do { // Get the name of the file or directory std::wstring fileName = findFileData.cFileName; // Ignore '.' and '..' directories if (fileName != L"." && fileName != L"..") { // Construct the full path of the file or directory std::wstring fullPath = currentPath + L"\\" + fileName; // Convert FILETIME to SYSTEMTIME SYSTEMTIME creationTime; FileTimeToSystemTime(&findFileData.ftCreationTime, &creationTime); // Format the creation time string wchar_t creationTimeString[20]; // Buffer for the formatted time string swprintf(creationTimeString, 20, L"%04d/%02d/%02d %02d:%02d:%02d", creationTime.wYear, creationTime.wMonth, creationTime.wDay, creationTime.wHour, creationTime.wMinute, creationTime.wSecond); // If it's a directory, add it to the queue for further traversal if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { pathsQueue.push(fullPath); } else { // Check if the file has the specified extension std::wstring::size_type dotPos = fileName.rfind(L'.'); if (dotPos != std::wstring::npos && fileName.substr(dotPos + 1) == extension){ // Format the file information string std::wstring fileInfo = fullPath + L" " + std::to_wstring(findFileData.nFileSizeLow) + L" " + creationTimeString; // Write the file information string to the output file stream out << fileInfo << std::endl; } } } } while (FindNextFileW(hFind, &findFileData) != 0); // Close the handle to the directory FindClose(hFind); }}bool CompressWithLZMS(const wchar_t* inFile, const wchar_t* outFile){ // Open input file HANDLE hInFile = CreateFileW(inFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hInFile == INVALID_HANDLE_VALUE){ std::wcerr << L"Failed to open input file: " << inFile << std::endl; return false; } // Get input file size DWORD dwFileSize = GetFileSize(hInFile, NULL); if (dwFileSize == INVALID_FILE_SIZE){ CloseHandle(hInFile); std::wcerr << L"Failed to get input file size." << std::endl; return false; } // Allocate buffer to hold input file data BYTE* pInputBuffer = new BYTE[dwFileSize]; DWORD dwBytesRead; if (!ReadFile(hInFile, pInputBuffer, dwFileSize, &dwBytesRead, NULL)){ CloseHandle(hInFile); delete[] pInputBuffer; std::wcerr << L"Failed to read input file." << std::endl; return false; } // Close input file handle CloseHandle(hInFile); // Create compressor COMPRESSOR_HANDLE hCompressor; if (!::CreateCompressor(COMPRESS_ALGORITHM_LZMS, NULL, &hCompressor)){ delete[] pInputBuffer; std::wcerr << L"Failed to create compressor." << std::endl; return false; } // Estimate maximum possible size of compressed data ULONG cbCompressedData = dwFileSize / 2; // Allocate buffer to hold compressed data BYTE* pCompressedBuffer = new BYTE[cbCompressedData]; // Compress data SIZE_T cbWritten; if (!Compress(hCompressor, pInputBuffer, dwFileSize, pCompressedBuffer, cbCompressedData, &cbWritten)){ delete[] pInputBuffer; delete[] pCompressedBuffer; CloseCompressor(hCompressor); std::wcerr << L"Compression failed." << std::endl; return false; } // Write compressed data to output file HANDLE hOutFile = CreateFileW(outFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hOutFile == INVALID_HANDLE_VALUE){ delete[] pInputBuffer; delete[] pCompressedBuffer; CloseCompressor(hCompressor); std::wcerr << L"Failed to create output file: " << outFile << std::endl; return false; } //change cbWritten to static_cast<DWORD>(cbWritten) DWORD dwBytesWritten; if (!WriteFile(hOutFile, pCompressedBuffer, static_cast<DWORD>(cbWritten), &dwBytesWritten, NULL)){ delete[] pInputBuffer; delete[] pCompressedBuffer; CloseHandle(hOutFile); CloseCompressor(hCompressor); std::wcerr << L"Failed to write compressed data to output file." << std::endl; return false; } // Cleanup delete[] pInputBuffer; delete[] pCompressedBuffer; CloseHandle(hOutFile); CloseCompressor(hCompressor); return true;}// Function to decrypt using AES256 algorithmvoid EncryptDecryptString(const std::wstring& inputString, const std::wstring& outputFile, bool encrypt){// Encryption code here}// Entry point of the programint wmain(int argc, wchar_t* argv[]) { // Check if the command-line arguments are valid if (argc != 4 && !(argc == 2 && std::wstring(argv[1]) == L"-help")) { // Display usage information if incorrect arguments provided std::wcerr << L"Usage: " << argv[0] << L" -x <input_directory_path> <output_file_path>" << std::endl; return 1; } // If the help option is provided, display help information if (argc == 2 && std::wstring(argv[1]) == L"-help") { std::wcout << L"Usage: " << argv[0] << L" -x <input_directory_path> <output_file_path>" << std::endl; std::wcout << L"Options:" << std::endl; std::wcout << L" -x: Perform operation to list files in BFS order" << std::endl; std::wcout << L" -help: Show help information" << std::endl; std::wcout << L"Example:" << std::endl; std::wcout << L" " << argv[0] << L" -x C:\\InputDirectory C:\\OutputFile.txt" << std::endl; return 0; } // Check if the operation option is correct if (wcscmp(argv[1], L"-x") != 0) { std::wcerr << L"Invalid option. Use -x to specify the operation." << std::endl; return 1; } // Get the input directory path and output file path std::wstring inputDirectoryPath = argv[2]; std::wstring outputFile = argv[3]; // Open the output file std::wofstream out(outputFile); if (!out.is_open()) { std::wcerr << L"Unable to open output file." << std::endl; return 1; } // Create a locale object with std::codecvt_utf8 facet std::locale loc(std::locale::classic(), new std::codecvt_utf8<wchar_t>); // Imbue the file stream with system default locale out.imbue(loc); // Call the appropriate function based on the number of arguments if (argc == 4){ // If there are 4 arguments, call the original ListFileBFS function ListFilesBFS(inputDirectoryPath, out); } else { // If there are 5 arguments, the extension is provided, call the modified ListFilesByExtensionBFS function std::wstring extension = argv[4[; ListFilesByExtensionBFS(inputDirectoryPath, extension, out); } // Close the output file out.close(); const wchar_t* compressedFile = L"compressed.lzms"; // Compress the file using LZMS compression algorithm if (!CompressWithLZMS(outputFile.c_str(), compressedFile)){ std::wcerr << L"Compression failed." << std::endl; return 1; } std::wcout << L"Compression successful. Compressed file: " << compressedFile << std::endl; const wchar_t* encryptedFile = L"encrypted.aes"; EncryptDecryptString(compressedFile, encryptedFile, true); std::wcout << L"Encryption successful. Encrypted fileL " << encryptedFile << std::endl; return 0;}