//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 { 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?"; }; enum listFlags { LIST_DIRECTORY = (1<<0), LIST_VOLUME = (1<<1) }; //VARS bool debug = true; History* history = new History(); //Flags used to determine: // window format int windowFlags = 0; // if it's time to load new data int listFlags = LIST_DIRECTORY | LIST_VOLUME; //Array used to display current error char error[MAX_ERRORSTR_LEN]; bool showError = false; //Stores found volumes //TODO onPresentPaths???? wtf is dis naem bru std::vector onPresentPaths; int numVolumes; //currentPath is the one used to retrieve data, then copied to addrBalVar for display. //addrBalVar is also used as a bacukp in case new currentPath is invalid //TODO: hay historial. Coalescer en una sola? //TODO: david wtf //cursed C momento: necesario ptr en otra var para mandar a char** de firma char currentPath[MAX_PATH]; char* currentPathPtr = ¤tPath[0]; char addrBarVal[MAX_LISTDIR_PATH_LENGTH]; char* addrBarValPtr = &addrBarVal[0]; //Stores entires found within a given directory //static int currentItemIdx = -1; std::vector directoryContents; int numFiles = 0; //Going one level up needs to be hardcoded like this due to function inputMove needing a char** //c pervirtio con unicode std::wstring s(L"←→↑↓"); char moveUp[] = ".."; char* moveUpPtr = &moveUp[0]; bool isListVolumesAdequate = true; bool isListDirectoriesAdequate = true; //RenderTime vars for filtering bool showHidden = false; bool filterByExtension = false; std::vector extensions; // 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)); //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++) { log_debugcpp(volumePaths[0] << " ENTERS " << std::to_string(pathLengthIdx)); 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) { log_debugcpp("Skill Issue"); 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 (debug) { if(numVolumes += explodePaths(volumePaths, volumePathsBufferSize, separator, onPresentPaths)){ for (int i = 0; i < onPresentPaths->size(); i++){ log_debugcpp(onPresentPaths->at(i)); } } } //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; } //TODO huh // int handleFolderAccessResult(int listFlags, char* nextPath, bool* error, char* errorDest, \ // const char* errorContent, History* history, char* currentPath = NULL, char* addrBarVal = NULL){ // *error = false; // if(!moveDirectory(nextPath)) { // *error = true; // if(currentPath && addrBarVal) { // strcpy(errorDest, errorContent); // strcpy(addrBarVal, currentPath); // } // return listFlags; // } // if(currentPath && addrBarVal) { // strcpy(currentPath, addrBarVal); // history->isAdditionTime = true; // } // return (listFlags |= LIST_DIRECTORY); // } //TODO huh, vale, no pasa por listdirectory por la flag, pero esto se podria hacer mejor manteniendo el no tirar de disco tb? int handleFolderAccessResult(int listFlags, char* nextPath, bool* error, char* errorDest, \ const char* errorContent, History* history, char* currentPath , char* addrBarVal){ *error = false; if(!moveDirectory(nextPath)) { *error = true; strcpy(errorDest, errorContent); strcpy(addrBarVal, currentPath); return listFlags; } //strcpy(currentPath, addrBarVal); history->isAdditionTime = true; return (listFlags |= LIST_DIRECTORY); } int handleFolderAccessResult(int listFlags, char* nextPath, bool* error, char* errorDest, \ const char* errorContent, History* history, bool isAdditionTime){ *error = false; if(!moveDirectory(nextPath)) { *error = true; strcpy(errorDest, errorContent); return listFlags; } if (isAdditionTime) history->isAdditionTime = true; return (listFlags |= LIST_DIRECTORY); } /* HISTORIAL */ void addPathToHistory(History *history, char* pathToAdd){ char* path; 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); //Listar UNA VEZ volumenes if (listFlags & LIST_VOLUME) { listFlags &= ~LIST_VOLUME; numVolumes = listVolumes(&onPresentPaths); log_debugcpp(std::to_string(numVolumes) + "<- depth MAIN size() ->" + std::to_string(onPresentPaths.size())); } //Listar UNA VEZ directorios //ImGui::Text("%s PRE DIRECTORY TREATMENTO", currentPath); if (listFlags & LIST_DIRECTORY) { listFlags &= ~LIST_DIRECTORY; log_debugcpp("ADECUADO LISTAR DIRECTORIOS"); if(!retrieveCurrentDirectory(currentPath)) { log_debugcpp("NO HABIA DIRECTORIO GetCurrentPath()"); exit(EXIT_FAILURE); } // //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 */ 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); //TODO: ERROR listFlags = handleFolderAccessResult(listFlags, interfaceMovementButtonsPath, &showError, error, ErrorMessages::moveUpError, history, false); } ImGui::EndDisabled(); //FORWARD ImGui::SameLine(); ImGui::BeginDisabled(MAX_HISTORY_POS); if(ImGui::Button("Forward")) { //TODO david???????????????????????????????????? char* interfaceMovementButtonsPath = moveThroughHistory(history, HISTORY_FORWARD); listFlags = handleFolderAccessResult(listFlags, interfaceMovementButtonsPath, &showError, error, ErrorMessages::moveUpError, history, false); } ImGui::EndDisabled(); //MOVE UP ImGui::SameLine(); if(ImGui::Button("Move Up")) { listFlags = handleFolderAccessResult(listFlags, moveUp, &showError, error, ErrorMessages::moveUpError, history, 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"); listFlags = handleFolderAccessResult(listFlags, addrBarVal, &showError, error, ErrorMessages::addrBarError, history, currentPath, addrBarVal); }; ImGui::PopItemWidth(); ImGui::SameLine(); if(ImGui::Button("Enter")){ log_debugcpp(currentPath <<" ADDRBAR INTENTO"); listFlags = handleFolderAccessResult(listFlags, addrBarVal, &showError, error, ErrorMessages::addrBarError, history, currentPath, addrBarVal); } //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))){ //TODO xdddddddd listFlags = handleFolderAccessResult(listFlags, onPresentPaths.at(i), &showError, error, ErrorMessages::moveUpError, history, 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); listFlags = handleFolderAccessResult(listFlags, addrBarVal, &showError, error, ErrorMessages::tableElementError, history, currentPath, addrBarVal); //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"); ImGui::End(); } }