diff --git a/vav2/Vav2Player/Vav2Player/Vav2Player.vcxproj b/vav2/Vav2Player/Vav2Player/Vav2Player.vcxproj
index c74f4dc..272ee60 100644
--- a/vav2/Vav2Player/Vav2Player/Vav2Player.vcxproj
+++ b/vav2/Vav2Player/Vav2Player/Vav2Player.vcxproj
@@ -108,7 +108,7 @@
$(ProjectDir)..\..\..\lib\libwebm;$(ProjectDir)..\..\..\lib\dav1d;%(AdditionalLibraryDirectories)
- webm-debug.lib;dav1d-debug.lib
+ webm-debug.lib;dav1d-debug.lib;shell32.lib;user32.lib;advapi32.lib;ole32.lib
@@ -117,7 +117,7 @@
$(ProjectDir)..\..\..\lib\libwebm;$(ProjectDir)..\..\..\lib\dav1d;%(AdditionalLibraryDirectories)
- webm.lib;dav1d.lib
+ webm.lib;dav1d.lib;shell32.lib;user32.lib;advapi32.lib;ole32.lib
true
true
@@ -140,6 +140,7 @@
+
@@ -165,6 +166,7 @@
+
diff --git a/vav2/Vav2Player/Vav2Player/src/Common/PermissionUtils.cpp b/vav2/Vav2Player/Vav2Player/src/Common/PermissionUtils.cpp
new file mode 100644
index 0000000..ce3b233
--- /dev/null
+++ b/vav2/Vav2Player/Vav2Player/src/Common/PermissionUtils.cpp
@@ -0,0 +1,253 @@
+#include "pch.h"
+#include "PermissionUtils.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace Vav2Player {
+
+PermissionUtils::PermissionResult PermissionUtils::CheckDirectoryCreatePermission(const std::filesystem::path& directory_path) {
+ try {
+ // 1. 디렉토리가 이미 존재하면 쓰기 권한 체크
+ if (std::filesystem::exists(directory_path)) {
+ if (TestDirectoryWrite(directory_path)) {
+ OutputDebugStringA(("[PermissionUtils] Directory exists and writable: " + directory_path.string() + "\n").c_str());
+ return PermissionResult::Granted;
+ } else {
+ OutputDebugStringA(("[PermissionUtils] Directory exists but not writable: " + directory_path.string() + "\n").c_str());
+ return PermissionResult::Denied;
+ }
+ }
+
+ // 2. 부모 디렉토리에서 생성 권한 체크
+ std::filesystem::path parent_path = directory_path.parent_path();
+ if (!std::filesystem::exists(parent_path)) {
+ // 부모 디렉토리가 없으면 재귀적으로 체크
+ auto parent_result = CheckDirectoryCreatePermission(parent_path);
+ if (parent_result != PermissionResult::Granted) {
+ return parent_result;
+ }
+ }
+
+ // 3. 실제로 임시 디렉토리 생성 테스트
+ std::filesystem::path test_dir = parent_path / ("test_permission_" + std::to_string(GetTickCount64()));
+
+ std::error_code ec;
+ bool created = std::filesystem::create_directory(test_dir, ec);
+
+ if (created && !ec) {
+ // 생성 성공, 정리
+ std::filesystem::remove(test_dir, ec);
+ OutputDebugStringA(("[PermissionUtils] Directory creation test successful: " + directory_path.string() + "\n").c_str());
+ return PermissionResult::Granted;
+ } else {
+ OutputDebugStringA(("[PermissionUtils] Directory creation test failed: " + directory_path.string() + ", Error: " + ec.message() + "\n").c_str());
+ return PermissionResult::Denied;
+ }
+
+ } catch (const std::exception& e) {
+ OutputDebugStringA(("[PermissionUtils] Exception in CheckDirectoryCreatePermission: " + std::string(e.what()) + "\n").c_str());
+ return PermissionResult::Error;
+ }
+}
+
+PermissionUtils::PermissionResult PermissionUtils::CheckFileWritePermission(const std::filesystem::path& file_path) {
+ try {
+ // 1. 디렉토리 존재 확인
+ std::filesystem::path parent_dir = file_path.parent_path();
+ if (!std::filesystem::exists(parent_dir)) {
+ auto dir_result = CheckDirectoryCreatePermission(parent_dir);
+ if (dir_result != PermissionResult::Granted) {
+ return dir_result;
+ }
+ }
+
+ // 2. 임시 파일 생성 테스트
+ std::filesystem::path test_file = parent_dir / ("test_write_" + std::to_string(GetTickCount64()) + ".tmp");
+
+ std::ofstream test_stream(test_file, std::ios::binary);
+ if (test_stream.is_open()) {
+ test_stream << "permission test";
+ test_stream.close();
+
+ // 정리
+ std::error_code ec;
+ std::filesystem::remove(test_file, ec);
+
+ OutputDebugStringA(("[PermissionUtils] File write test successful: " + file_path.string() + "\n").c_str());
+ return PermissionResult::Granted;
+ } else {
+ OutputDebugStringA(("[PermissionUtils] File write test failed: " + file_path.string() + "\n").c_str());
+ return PermissionResult::Denied;
+ }
+
+ } catch (const std::exception& e) {
+ OutputDebugStringA(("[PermissionUtils] Exception in CheckFileWritePermission: " + std::string(e.what()) + "\n").c_str());
+ return PermissionResult::Error;
+ }
+}
+
+bool PermissionUtils::IsRunningAsAdmin() {
+ BOOL is_admin = FALSE;
+ PSID admin_group = nullptr;
+ SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY;
+
+ if (AllocateAndInitializeSid(&nt_authority, 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0,
+ &admin_group)) {
+
+ if (!::CheckTokenMembership(nullptr, admin_group, &is_admin)) {
+ is_admin = FALSE;
+ }
+ FreeSid(admin_group);
+ }
+
+ OutputDebugStringA(is_admin ? "[PermissionUtils] Running as administrator\n" : "[PermissionUtils] Not running as administrator\n");
+ return is_admin == TRUE;
+}
+
+bool PermissionUtils::RequestAdminRestart() {
+ wchar_t exe_path[MAX_PATH];
+ DWORD path_length = GetModuleFileNameW(nullptr, exe_path, MAX_PATH);
+
+ if (path_length == 0 || path_length == MAX_PATH) {
+ OutputDebugStringA("[PermissionUtils] Failed to get executable path for restart\n");
+ return false;
+ }
+
+ // ShellExecute로 관리자 권한 요청
+ HINSTANCE result = ShellExecuteW(nullptr, L"runas", exe_path, nullptr, nullptr, SW_SHOWNORMAL);
+
+ bool success = reinterpret_cast(result) > 32;
+ if (success) {
+ OutputDebugStringA("[PermissionUtils] Requested admin restart\n");
+ // 현재 프로세스 종료
+ PostQuitMessage(0);
+ } else {
+ OutputDebugStringA("[PermissionUtils] Failed to request admin restart\n");
+ }
+
+ return success;
+}
+
+bool PermissionUtils::ShowPermissionDialog(const std::wstring& message, const std::wstring& title) {
+ int result = MessageBoxW(nullptr, message.c_str(), title.c_str(),
+ MB_YESNO | MB_ICONWARNING | MB_TOPMOST);
+
+ return result == IDYES;
+}
+
+std::filesystem::path PermissionUtils::GetSafeOutputDirectory() {
+ // 우선순위 순서로 안전한 디렉토리 시도
+ std::vector safe_directories;
+
+ // 1. 사용자 문서 폴더
+ wchar_t* documents_path = nullptr;
+ if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, nullptr, &documents_path))) {
+ safe_directories.push_back(std::filesystem::path(documents_path) / "Vav2Player");
+ CoTaskMemFree(documents_path);
+ }
+
+ // 2. 사용자 임시 폴더
+ wchar_t temp_path[MAX_PATH];
+ if (GetTempPathW(MAX_PATH, temp_path)) {
+ safe_directories.push_back(std::filesystem::path(temp_path) / "Vav2Player");
+ }
+
+ // 3. 현재 사용자 프로필 폴더
+ wchar_t* profile_path = nullptr;
+ if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Profile, 0, nullptr, &profile_path))) {
+ safe_directories.push_back(std::filesystem::path(profile_path) / "Vav2Player");
+ CoTaskMemFree(profile_path);
+ }
+
+ // 4. 실행파일과 같은 디렉토리
+ wchar_t exe_path[MAX_PATH];
+ if (GetModuleFileNameW(nullptr, exe_path, MAX_PATH)) {
+ std::filesystem::path exe_dir = std::filesystem::path(exe_path).parent_path();
+ safe_directories.push_back(exe_dir / "output");
+ }
+
+ // 각 디렉토리 권한 체크
+ for (const auto& dir : safe_directories) {
+ if (CheckDirectoryCreatePermission(dir) == PermissionResult::Granted) {
+ OutputDebugStringA(("[PermissionUtils] Found safe directory: " + dir.string() + "\n").c_str());
+ return dir;
+ }
+ }
+
+ // 모든 시도 실패 시 기본값
+ OutputDebugStringA("[PermissionUtils] No safe directory found, using fallback\n");
+ return std::filesystem::path("C:\\temp\\Vav2Player");
+}
+
+PermissionUtils::PermissionResult PermissionUtils::CheckAndHandlePermissions(const std::filesystem::path& output_directory) {
+ OutputDebugStringA(("[PermissionUtils] Checking permissions for: " + output_directory.string() + "\n").c_str());
+
+ // 1. 기본 권한 체크
+ auto result = CheckDirectoryCreatePermission(output_directory);
+
+ if (result == PermissionResult::Granted) {
+ return result;
+ }
+
+ // 2. 권한 없는 경우 처리
+ std::wstring message;
+
+ if (result == PermissionResult::Denied) {
+ std::wstring dir_path = std::wstring(output_directory.string().begin(), output_directory.string().end());
+ message = L"출력 디렉토리에 쓰기 권한이 없습니다:\n" + dir_path +
+ L"\n\n관리자 권한으로 다시 시작하시겠습니까?\n(아니오를 선택하면 안전한 위치를 사용합니다)";
+ } else {
+ std::wstring dir_path = std::wstring(output_directory.string().begin(), output_directory.string().end());
+ message = L"디렉토리 권한 확인 중 오류가 발생했습니다:\n" + dir_path +
+ L"\n\n관리자 권한으로 다시 시작하시겠습니까?";
+ }
+
+ // 3. 사용자에게 선택 제공
+ if (ShowPermissionDialog(message, L"디렉토리 권한 필요")) {
+ // 관리자 권한으로 재시작 요청
+ if (RequestAdminRestart()) {
+ // 재시작 요청 성공 (앱이 종료될 예정)
+ return PermissionResult::Granted;
+ } else {
+ // 재시작 실패 - 안전한 디렉토리 사용
+ return PermissionResult::Denied;
+ }
+ } else {
+ // 사용자가 관리자 권한 거부 - 안전한 디렉토리 사용
+ return PermissionResult::Denied;
+ }
+}
+
+bool PermissionUtils::TestDirectoryWrite(const std::filesystem::path& directory_path) {
+ try {
+ std::filesystem::path test_file = directory_path / ("write_test_" + std::to_string(GetTickCount64()) + ".tmp");
+
+ std::ofstream test_stream(test_file, std::ios::binary);
+ if (!test_stream.is_open()) {
+ return false;
+ }
+
+ test_stream << "write permission test";
+ test_stream.close();
+
+ // 정리
+ std::error_code ec;
+ std::filesystem::remove(test_file, ec);
+
+ return true;
+
+ } catch (const std::exception&) {
+ return false;
+ }
+}
+
+
+} // namespace Vav2Player
\ No newline at end of file
diff --git a/vav2/Vav2Player/Vav2Player/src/Common/PermissionUtils.h b/vav2/Vav2Player/Vav2Player/src/Common/PermissionUtils.h
new file mode 100644
index 0000000..0f960b1
--- /dev/null
+++ b/vav2/Vav2Player/Vav2Player/src/Common/PermissionUtils.h
@@ -0,0 +1,44 @@
+#pragma once
+#include
+#include
+#include
+
+namespace Vav2Player {
+
+class PermissionUtils {
+public:
+ // 권한 체크 결과
+ enum class PermissionResult {
+ Granted, // 권한 있음
+ Denied, // 권한 없음
+ Error // 체크 중 오류 발생
+ };
+
+ // 디렉토리 생성 권한 체크
+ static PermissionResult CheckDirectoryCreatePermission(const std::filesystem::path& directory_path);
+
+ // 파일 쓰기 권한 체크
+ static PermissionResult CheckFileWritePermission(const std::filesystem::path& file_path);
+
+ // 관리자 권한으로 실행 중인지 확인
+ static bool IsRunningAsAdmin();
+
+ // 관리자 권한으로 재시작 요청
+ static bool RequestAdminRestart();
+
+ // 사용자에게 권한 관련 메시지 표시
+ static bool ShowPermissionDialog(const std::wstring& message, const std::wstring& title = L"권한 필요");
+
+ // 안전한 출력 디렉토리 제안
+ static std::filesystem::path GetSafeOutputDirectory();
+
+ // 권한 체크 및 처리 (통합 함수)
+ static PermissionResult CheckAndHandlePermissions(const std::filesystem::path& output_directory);
+
+private:
+ // 디렉토리에 대한 실제 쓰기 테스트
+ static bool TestDirectoryWrite(const std::filesystem::path& directory_path);
+
+};
+
+} // namespace Vav2Player
\ No newline at end of file
diff --git a/vav2/Vav2Player/Vav2Player/src/Output/FileOutput.cpp b/vav2/Vav2Player/Vav2Player/src/Output/FileOutput.cpp
index 1da0246..0c142e7 100644
--- a/vav2/Vav2Player/Vav2Player/src/Output/FileOutput.cpp
+++ b/vav2/Vav2Player/Vav2Player/src/Output/FileOutput.cpp
@@ -1,5 +1,6 @@
#include "pch.h"
#include "FileOutput.h"
+#include "../Common/PermissionUtils.h"
#include
#include
#include
@@ -31,6 +32,11 @@ FileOutput::FileOutput(const OutputConfig& config)
OutputDebugStringA("[FileOutput] YUV->RGB conversion will use lookup table optimization\n");
}
+ // 권한 체크 및 설정
+ if (!CheckAndSetupPermissions()) {
+ OutputDebugStringA("[FileOutput] Warning: Failed to setup proper permissions for output directory\n");
+ }
+
InitializeCache();
}
@@ -764,4 +770,91 @@ void FileOutput::StoreRGB24_SIMD(uint8_t* dst, __m256i r_vec, __m256i g_vec, __m
}
}
+bool FileOutput::CheckAndSetupPermissions() {
+ try {
+ std::filesystem::path exe_path = GetProcessPath();
+ std::filesystem::path full_output_path = exe_path / m_config.output_directory;
+
+ OutputDebugStringA(("[FileOutput] Checking permissions for output directory: " + full_output_path.string() + "\n").c_str());
+
+ // 권한 체크 및 처리
+ auto permission_result = PermissionUtils::CheckAndHandlePermissions(full_output_path);
+
+ switch (permission_result) {
+ case PermissionUtils::PermissionResult::Granted:
+ OutputDebugStringA("[FileOutput] Permissions granted for output directory\n");
+ return true;
+
+ case PermissionUtils::PermissionResult::Denied:
+ OutputDebugStringA("[FileOutput] Permissions denied, attempting to use safe directory\n");
+ return HandlePermissionDenied();
+
+ case PermissionUtils::PermissionResult::Error:
+ OutputDebugStringA("[FileOutput] Error checking permissions, attempting to use safe directory\n");
+ return HandlePermissionDenied();
+
+ default:
+ return false;
+ }
+
+ } catch (const std::exception& e) {
+ OutputDebugStringA(("[FileOutput] Exception in CheckAndSetupPermissions: " + std::string(e.what()) + "\n").c_str());
+ return HandlePermissionDenied();
+ }
+}
+
+bool FileOutput::HandlePermissionDenied() {
+ try {
+ // 안전한 출력 디렉토리 찾기
+ std::filesystem::path safe_directory = PermissionUtils::GetSafeOutputDirectory();
+
+ OutputDebugStringA(("[FileOutput] Using safe output directory: " + safe_directory.string() + "\n").c_str());
+
+ // 설정 업데이트
+ m_config.output_directory = safe_directory;
+
+ // 캐시 재초기화
+ InitializeCache();
+
+ // 권한 재체크
+ auto permission_result = PermissionUtils::CheckDirectoryCreatePermission(safe_directory);
+
+ if (permission_result == PermissionUtils::PermissionResult::Granted) {
+ OutputDebugStringA("[FileOutput] Safe directory permissions verified\n");
+
+ // 사용자에게 알림
+ std::wstring safe_dir_wstr = std::wstring(safe_directory.string().begin(), safe_directory.string().end());
+ std::wstring message = L"원래 출력 디렉토리에 권한이 없어 다음 위치를 사용합니다:\n" + safe_dir_wstr;
+ PermissionUtils::ShowPermissionDialog(message, L"출력 디렉토리 변경");
+
+ return true;
+ } else {
+ OutputDebugStringA("[FileOutput] Safe directory also lacks permissions\n");
+
+ // 마지막 수단: 임시 디렉토리
+ wchar_t temp_path[MAX_PATH];
+ if (GetTempPathW(MAX_PATH, temp_path)) {
+ std::filesystem::path temp_dir = std::filesystem::path(temp_path) / "Vav2Player_Emergency";
+ m_config.output_directory = temp_dir;
+ InitializeCache();
+
+ OutputDebugStringA(("[FileOutput] Using emergency temp directory: " + temp_dir.string() + "\n").c_str());
+
+ std::wstring temp_dir_wstr = std::wstring(temp_dir.string().begin(), temp_dir.string().end());
+ std::wstring message = L"안전한 출력 디렉토리를 찾을 수 없어 임시 폴더를 사용합니다:\n" + temp_dir_wstr;
+ PermissionUtils::ShowPermissionDialog(message, L"긴급 출력 디렉토리");
+
+ return true;
+ } else {
+ OutputDebugStringA("[FileOutput] Failed to get temp directory\n");
+ return false;
+ }
+ }
+
+ } catch (const std::exception& e) {
+ OutputDebugStringA(("[FileOutput] Exception in HandlePermissionDenied: " + std::string(e.what()) + "\n").c_str());
+ return false;
+ }
+}
+
} // namespace Vav2Player
\ No newline at end of file
diff --git a/vav2/Vav2Player/Vav2Player/src/Output/FileOutput.h b/vav2/Vav2Player/Vav2Player/src/Output/FileOutput.h
index 2b28d1e..7d05d01 100644
--- a/vav2/Vav2Player/Vav2Player/src/Output/FileOutput.h
+++ b/vav2/Vav2Player/Vav2Player/src/Output/FileOutput.h
@@ -1,5 +1,6 @@
#pragma once
#include "../Common/VideoTypes.h"
+#include "../Common/PermissionUtils.h"
#include
#include
#include
@@ -64,6 +65,10 @@ public:
bool CreateOutputDirectory();
void ClearOutputDirectory();
+ // 권한 체크 및 처리
+ bool CheckAndSetupPermissions();
+ bool HandlePermissionDenied();
+
// 통계 정보
struct OutputStats {
uint64_t frames_saved = 0;