//DEBUG MACRO #define log_debugc(str, ...) do { if (debug) fprintf(stdout, "[DEBUG] (%s:%d): " (str) "\n", __FILE__, __LINE__, ##__VA_ARGS__); } while (0) #define log_debugcpp(str) do { \ if (debug) std::cout << "[DEBUG]" << "(" << __FILE__ << ":" << __LINE__ << "): " << str << std::endl; \ } while (0) #define log_directory(str) if(debugVerbosity & DEBUG_DIRECTORY) log_debugcpp((str)) #define log_volume(str) if(debugVerbosity & DEBUG_VOLUME) log_debugcpp((str)) #define log_extension(str) if(debugVerbosity & DEBUG_EXTENSION) log_debugcpp((str)) //PATH MACRO #define MAX_LISTDIR_PATH_LENGTH (MAX_PATH - 3) #define MAX_ERRORSTR_LEN 512 //HISTORY HANDLING MACRO #define MIN_HISTORY_POS (history->historyTraversalPos <= 0) #define MAX_HISTORY_POS (history->historyTraversalPos >= history->historyDepth) #include #include #include #include #include #pragma once namespace fp { bool debug = true; // int debugVerbosity = 0; // enum enumDebugVerbosity { // DEBUG_DIRECTORY = (1<<0), // DEBUG_VOLUME = (1<<1), // DEBUG_EXTENSION = (1<<2) // }; // debugVerbosity = DEBUG_DIRECTORY | DEBUG_EXTENSION; // debugVerbosity &= ~DEBUG_DIRECTORY; // if (debugVerbosity & (DEBUG_DIRECTORY | DEBUG_EXTENSION)); int windowFlags = 0; typedef struct { long long size; //TODO yel spacsio NELLA MEMoria TCHAR name[MAX_LISTDIR_PATH_LENGTH]; SYSTEMTIME createTime; SYSTEMTIME lastAccessTime; SYSTEMTIME lastWriteTime; bool isFile; bool isHidden; } directoriesInfo; struct History{ std::vector previousPaths; //warnings e 1 cosa //int historyDepth = -1; //TODO Limitar historial //const int maxHistoryDepth = 10000; int historyDepth; int historyTraversalPos; bool isAdditionTime; History(){ historyTraversalPos = historyDepth = -1; isAdditionTime = true; } }; enum HistoryMovement { HISTORY_FORWARD = 1, HISTORY_BACKWARD = 0 }; enum ListDirectoryError { DIRECTORY_ERROR_PATH_TOO_LONG = -1, DIRECTORY_ERROR_ACCESSING_CONTENT = -2 }; enum agnosticDirError { AGDIR_ERROR_ACCESS_DENIED = 1 }; namespace ErrorMessages { char addrBarError[] = "Failed to open folder: invalid path"; char tableElementError[] = "Failed to open folder: access restricted to non-admin users"; char accessDeniedError[] = "Failed to open folder: access denied"; char listDirectoryError[] = "Failed to open folder: unknown error"; char moveUpError[] = "Failed to move up: reached volume root?"; }; //TODO UNICORDEO /* FILE PICKER MOMENTO */ /* DIRECTORIES */ bool retrieveCurrentDirectory(char** currentPath){ if(GetCurrentDirectory(MAX_PATH, *currentPath)) return true; return false; } bool moveDirectory(char** currentPath){ log_debugcpp(*currentPath); if(SetCurrentDirectory(*currentPath)) return true; return false; } int listDirectory(std::string path, std::vector *directoryContents){ HANDLE hFind = INVALID_HANDLE_VALUE; WIN32_FIND_DATA ffd; LARGE_INTEGER filesize; int numFiles = 0; if (path.length() > (MAX_LISTDIR_PATH_LENGTH)) return DIRECTORY_ERROR_PATH_TOO_LONG; path = path + "\\*"; hFind = FindFirstFile(path.c_str(), &ffd); if (INVALID_HANDLE_VALUE == hFind) return DIRECTORY_ERROR_ACCESSING_CONTENT; do { if(!strcmp(ffd.cFileName, ".") || !strcmp(ffd.cFileName, "..")) continue; log_debugcpp("BUCLE listDirectory iteracion " + std::to_string(numFiles)); directoriesInfo* itemInfo; if (directoryContents->size() <= numFiles){ itemInfo = new directoriesInfo(); directoryContents->push_back(itemInfo); } else { itemInfo = directoryContents->at(numFiles); } log_debugcpp("MEMORY ASSIGNES iteration " + std::to_string(numFiles)); //A registrar info, fiera itemInfo->isFile = (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false; itemInfo->isHidden = (ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? true : false; //Tamaño filesize.QuadPart = ((ffd.nFileSizeHigh * (MAXDWORD+1)) + ffd.nFileSizeLow); itemInfo->size = filesize.QuadPart; //Fechitssss FileTimeToSystemTime(&ffd.ftCreationTime, &itemInfo->createTime); FileTimeToSystemTime(&ffd.ftLastAccessTime, &itemInfo->lastAccessTime); FileTimeToSystemTime(&ffd.ftLastWriteTime, &itemInfo->lastWriteTime); //Nombre de la cosita uint64_t idx = 0; do { itemInfo->name[idx] = ffd.cFileName[idx]; idx++; } while (ffd.cFileName[idx]); itemInfo->name[idx] = '\0'; log_debugcpp("INFORMACION ALMACENADA iteracion " + std::to_string(numFiles)); numFiles++; } while (FindNextFile(hFind, &ffd) != 0); FindClose(hFind); return numFiles; } long getLastDirectorySystemError(){ long winLastError = GetLastError(); switch(winLastError){ case ERROR_ACCESS_DENIED: return AGDIR_ERROR_ACCESS_DENIED; break; default: return -1; break; } } /* VOLUMES */ //new char*[CharCount * sizeof(WCHAR) /*idea, si quisiera que empezase en punto X del string coger el param opcional y crear un puntero a la posicion X del array para empezar desde ahi int explodePaths(TCHAR* volumePaths, int volumePathLength, int volumePathBufferSize, char separator, std::vector *dest, , int startingFrom = 0); if (nextOcurrence == NULL) return 0; */ int explodePaths(TCHAR* volumePaths, int volumePathsBufferSize, char separator, std::vector *dest, int depth = 1){ //Por alguna razon esta puta mierda que dice acabar con 2 NULL acaba con 3; de locos. //https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumepathnamesforvolumenamew char* nextOcurrence = strchr(volumePaths, separator); char* itemPath; itemPath = (char*)calloc(1, volumePathsBufferSize); int pathLengthIdx = 0; for (; volumePaths[pathLengthIdx] != nextOcurrence[0]; pathLengthIdx++) { if (debug) { std::cout << volumePaths[0]; std::cout << " ENTERS " + std::to_string(pathLengthIdx) << std::endl; } itemPath[pathLengthIdx] = volumePaths[pathLengthIdx]; } itemPath[pathLengthIdx + 1] = '\0'; dest->push_back(itemPath); log_debugcpp(dest->at(dest->size() - 1) << " EXPLODEPATH"); if (nextOcurrence[0] == nextOcurrence[1]) return depth; depth++; return explodePaths(nextOcurrence + sizeof(TCHAR), (volumePathsBufferSize - pathLengthIdx), separator, dest, depth); } int listVolumes(std::vector *onPresentPaths){ HANDLE hFind = INVALID_HANDLE_VALUE; const char separator = '\0'; int numVolumes = 0; //Volume name TCHAR volumeName[MAX_PATH]; int volumeNameSize = sizeof volumeName / sizeof volumeName[0]; //Paths int volumePathsBufferSize = (MAX_PATH + 1) * sizeof(TCHAR); unsigned long volumePathLength; TCHAR volumePaths[volumePathsBufferSize]; std::fill(volumePaths, volumePaths + volumePathsBufferSize, '\0'); hFind = FindFirstVolume(volumeName, volumeNameSize); if (INVALID_HANDLE_VALUE == hFind) return -2; do { if(GetVolumePathNamesForVolumeName(volumeName, volumePaths, volumePathsBufferSize, &volumePathLength)){ if (volumePathLength == 1) { if (debug) std::cout << "Skill Issue" << std::endl; continue; } log_debugcpp(volumeName); //DEBUG: pathSchecker // if (debug && volumePaths[0] == 'E') { // std::cout << volumePathLength << std::endl; // /*exit(1);*/ // for (int i = 0; i < volumePathsBufferSize; i++){ // std::cout << std::to_string(i) + ": "; // std::cout << volumePaths[i]; // std::cout << " | "; // } // std::cout << std::endl << "I IA" << std::endl; // exit(1); // } if(numVolumes += explodePaths(volumePaths, volumePathsBufferSize, separator, onPresentPaths)){ for (int i = 0; i < onPresentPaths->size(); i++){ std::cout << onPresentPaths->at(i) << std::endl; } } //std::cout << volumePaths << std::endl; log_debugcpp(std::to_string(volumePathLength) + "<- VOLUME PATH LENGTH"); log_debugcpp("THE END"); }else{ log_debugcpp("no volumes found wtf"); } //TODO benchimarqui std::fill(volumePaths, volumePaths + volumePathsBufferSize, '\0'); } while (FindNextVolume(hFind, volumeName, volumeNameSize) != 0); log_debugcpp(std::to_string(onPresentPaths->size()) + " JUST BEFORE MAIN"); FindVolumeClose(hFind); return numVolumes; } /* DISPLAY */ bool compareLastChar(std::vector *lastCharCandidates, char* string){ bool matchingExtension = false; for (int i = 0; i < lastCharCandidates->size(); i++){ log_debugcpp(lastCharCandidates->at(i) + " <- FILTERING EXTENSION"); if(strlen(string) < lastCharCandidates->at(i).length()) continue; char* potentialExtension = &string[strlen(string) - lastCharCandidates->at(i).length()]; log_debugcpp(potentialExtension << " LEN " + std::to_string(strlen(potentialExtension)) + " <- VS -> " + lastCharCandidates->at(i) + " LEN " + std::to_string(lastCharCandidates->at(i).length())); //+ strlen(potentialExtension) + std::to_string(lastCharCandidates->at(i).length()) if(!strcmp(potentialExtension, lastCharCandidates->at(i).c_str())) { log_debugcpp("VALID EXTENSION"); matchingExtension = true; } } return matchingExtension; } bool inputMove(bool* error, char** str){ *error = false; if(!moveDirectory(str)) { *error = true; return false; } return true; } void handleFolderAccessResult(bool isListDirectoriesAdequate, char* currentPath, \ char* addrBarVal, char* errorDest, const char* errorContent, History* history){ if (isListDirectoriesAdequate) { strcpy(currentPath, addrBarVal); history->isAdditionTime = true; } else strcpy(addrBarVal, currentPath); strcpy(errorDest, errorContent); } /* HISTORIAL */ void addPathToHistory(History *history, char* pathToAdd){ char* path; //int ajjj = history->previousPaths.size(); if (history->historyTraversalPos + 1 >= history->previousPaths.size()){ path = (char*)calloc(1, MAX_PATH); history->previousPaths.push_back(path); } else { path = history->previousPaths.at(history->historyTraversalPos + 1); } strncpy(path, pathToAdd, MAX_PATH); history->historyTraversalPos++; history->historyDepth = history->historyTraversalPos; history->isAdditionTime = false; } char** moveThroughHistory(History *history, HistoryMovement movement) { int sign = (movement == HISTORY_BACKWARD ? -1 : 1); switch(movement){ case HISTORY_BACKWARD: if(MIN_HISTORY_POS) return &history->previousPaths.at(history->historyTraversalPos); break; case HISTORY_FORWARD: if(MAX_HISTORY_POS) return &history->previousPaths.at(history->historyDepth); break; default: return &history->previousPaths.at(history->historyDepth); } history->historyTraversalPos += sign; return &history->previousPaths.at(history->historyTraversalPos); } /* FIN FILE PICKER MOMENTO */ void filePickerMomento(bool isFullViewport = false){ if (isFullViewport){ ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f)); ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); windowFlags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize; } ImGui::Begin("File Picker in 4K", NULL, windowFlags); if (isFullViewport) ImGui::PopStyleVar(1); static History* history = new History(); static bool showError = false; static char error[MAX_ERRORSTR_LEN]; static bool isListVolumesAdequate = true; static bool isListDirectoriesAdequate = true; //Listar UNA VEZ volumenes static int numVolumes; static std::vector onPresentPaths; if (isListVolumesAdequate) { isListVolumesAdequate = false; //std::cout << isListVolumesAdequate << std::endl; numVolumes = listVolumes(&onPresentPaths); log_debugcpp(std::to_string(numVolumes) + "<- depth MAIN size() ->" + std::to_string(onPresentPaths.size())); } //Listar UNA VEZ directorios //cursed C momento: necesario ptr en otra var para mandar a char** de firma static char currentPath[MAX_PATH]; static char* currentPathPtr = ¤tPath[0]; static char addrBarVal[MAX_LISTDIR_PATH_LENGTH]; static char* addrBarValPtr = &addrBarVal[0]; //static int currentItemIdx = -1; //static std::vector directoryContents; static std::vector directoryContents; static int numFiles = 0; //ImGui::Text("%s PRE DIRECTORY TREATMENTO", currentPath); if(isListDirectoriesAdequate) { log_debugcpp("ADECUADO LISTAR DIRECTORIOS"); isListDirectoriesAdequate = false; if(!retrieveCurrentDirectory(¤tPathPtr)) { log_debugcpp("NO HABIA DIRECTORIO GetCurrentPath()"); goto filepickerFailure; } // //TODO ELIMINAR RESTRICCION EXE; PRUEBITA DEL SIGNIORE numFiles = listDirectory(std::string(currentPath), &directoryContents); //std::cout << numFiles; if (numFiles < 0) { //TODO quitar GetLastError() de aqui long directoryErrorCode; log_debugcpp("FALLO LA FUNCION, VALOR NEGATIVO " + std::to_string(numFiles)); if (numFiles == DIRECTORY_ERROR_ACCESSING_CONTENT) directoryErrorCode = getLastDirectorySystemError(); showError = true; switch(directoryErrorCode) { case AGDIR_ERROR_ACCESS_DENIED: strcpy(error, ErrorMessages::accessDeniedError); strcpy(addrBarVal, history->previousPaths.at(history->historyTraversalPos)); strcpy(currentPath, history->previousPaths.at(history->historyTraversalPos)); numFiles = listDirectory(history->previousPaths.at(history->historyTraversalPos), &directoryContents); break; default: strcpy(error, ErrorMessages::listDirectoryError); strcpy(currentPath, addrBarVal); numFiles = listDirectory(std::string(currentPath), &directoryContents); break; } history->isAdditionTime = false; } else { showError = false; strcpy(addrBarVal, currentPath); if(history->isAdditionTime) addPathToHistory(history, addrBarVal); } } /* It's renderin' time */ static bool showHidden = false; static bool filterByExtension = false; static std::vector extensions; if(showError){ ImGui::Text(error); } ImGui::Text("Select a file:"); //Permanentes e increiblemente utilitarios botones en Cuatro K: BACK ImGui::BeginDisabled(MIN_HISTORY_POS); if(ImGui::Button("Back")) { char** interfaceMovementButtonsPath = moveThroughHistory(history, HISTORY_BACKWARD); isListDirectoriesAdequate = inputMove(&showError, interfaceMovementButtonsPath); //TODO: ERROR strcpy(error, ErrorMessages::moveUpError); } ImGui::EndDisabled(); //FORWARD ImGui::SameLine(); ImGui::BeginDisabled(MAX_HISTORY_POS); if(ImGui::Button("Forward")) { char** interfaceMovementButtonsPath = moveThroughHistory(history, HISTORY_FORWARD); isListDirectoriesAdequate = inputMove(&showError, interfaceMovementButtonsPath); strcpy(error, ErrorMessages::moveUpError); } ImGui::EndDisabled(); //MOVE UP ImGui::SameLine(); //c pervirtio con unicode std::wstring s(L"←→↑↓"); static char moveUp[] = ".."; static char* moveUpPtr = &moveUp[0]; if(ImGui::Button("Move Up")) { isListDirectoriesAdequate = inputMove(&showError, (&moveUpPtr)); strcpy(error, ErrorMessages::moveUpError); history->isAdditionTime = true; } ImGui::SameLine(); //BARRA DE DIRECCIONES ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x - (ImGui::CalcTextSize("Enter").x + ImGui::GetStyle().ItemSpacing.x * 2) ); if(ImGui::InputText("##addrbar", addrBarVal, IM_ARRAYSIZE(addrBarVal), ImGuiInputTextFlags_EnterReturnsTrue )){ log_debugcpp(currentPath <<" ADDRBAR INTENTO"); isListDirectoriesAdequate = inputMove(&showError, &addrBarValPtr); handleFolderAccessResult(isListDirectoriesAdequate, currentPath, addrBarVal, error, ErrorMessages::addrBarError, history); }; ImGui::PopItemWidth(); ImGui::SameLine(); if(ImGui::Button("Enter")){ log_debugcpp(currentPath <<" ADDRBAR INTENTO"); isListDirectoriesAdequate = inputMove(&showError, &addrBarValPtr); handleFolderAccessResult(isListDirectoriesAdequate, currentPath, addrBarVal, error, ErrorMessages::addrBarError, history); } //ImGui::Text("%s TEMPADDRBAR", currentPath); //LA GRAN TABLACIÓN: ACTOR EN LAS SOMBRAS static ImGuiTableFlags splitterTableFlags = ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV; if (ImGui::BeginTable("##splitterTable", 2, splitterTableFlags, ImVec2(-FLT_MIN, 0.8f * ImGui::GetTextLineHeightWithSpacing()))){ ImGui::TableNextRow(); ImGui::TableNextColumn(); //VOLUMENES static ImGuiTableFlags volumesFlags = ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY ; if (ImGui::BeginTable("##volumesTable", 1, volumesFlags, ImVec2(-FLT_MIN, 20 * ImGui::GetTextLineHeightWithSpacing()))){ ImGui::TableSetupColumn("Volumes", ImGuiTableColumnFlags_NoHide); //ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f); //ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 18.0f); ImGui::TableHeadersRow(); ImGui::TableNextRow(); if (numVolumes > 0) { for (int i = 0; i < onPresentPaths.size(); i++) { ImGui::TableNextColumn(); // ImGui::PushID(i); ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f)); ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f)); if(ImGui::Button(onPresentPaths.at(i))){ isListDirectoriesAdequate = inputMove(&showError, &onPresentPaths.at(i)); history->isAdditionTime = true; } ImGui::PopStyleColor(3); if (i != onPresentPaths.size() - 1) ImGui::TableNextRow(); // ImGui::PopID(); } } ImGui::EndTable(); } ImGui::TableNextColumn(); //DIRECTORIOS ENCONTRADOS bien pinta2 static ImGuiTableFlags directoriesFlags = ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable |ImGuiTableFlags_ScrollY ; if (ImGui::BeginTable("##directoriesTable", 3, directoriesFlags, ImVec2(-FLT_MIN, 20 * ImGui::GetTextLineHeightWithSpacing()))){ ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide); ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_NoHide); ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_NoHide); //ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f); //ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 18.0f); ImGui::TableHeadersRow(); int idx = 0; for (; idx < numFiles; idx++) { if(directoryContents.at(idx)->isHidden && !showHidden) continue; if(filterByExtension && !directoryContents.at(idx)->isFile) { //TODO XAPUSITA extensions.clear(); extensions.push_back("exe"); if (!compareLastChar(&extensions, directoryContents.at(idx)->name)) continue; } ImGui::TableNextRow(); ImGui::TableNextColumn(); //NAME bool isSelected = false; if (ImGui::Selectable(directoryContents.at(idx)->name, &isSelected)){ strcat(addrBarVal, "\\"); strcat(addrBarVal, directoryContents.at(idx)->name); isListDirectoriesAdequate = inputMove(&showError, &addrBarValPtr); handleFolderAccessResult(isListDirectoriesAdequate, currentPath, addrBarVal, error, ErrorMessages::tableElementError, history); //currentItemIdx = -1; } ImGui::TableNextColumn(); //TYPE if (directoryContents.at(idx)->isFile) ImGui::Text("Folder"); else ImGui::Text("File"); ImGui::TableNextColumn(); //SIZE if (!directoryContents.at(idx)->isFile) ImGui::Text("%lld bytes", directoryContents.at(idx)->size); else ImGui::Text(""); //ImGui::SetItemDefaultFocus(); } //DISPLAYING ALTERNATIVE INFO if (!idx) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("Folder is empty"); } ImGui::EndTable(); } ImGui::EndTable(); } //ImGui::TreePop(); ImGui::Checkbox("Show hidden", &showHidden); ImGui::SameLine(); ImGui::Checkbox("Filter by .exe", &filterByExtension); ImGui::SameLine(); ImGui::Button("Select"); filepickerFailure: ImGui::End(); } }