X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fcross.cc;h=53ef5723ac50232d5e05fb8664a7b8dc3eba766d;hb=3574212ee42b2bd924eb95d5c0f4f69ec9e0a2f0;hp=f232f1779dabc432445c5f1a6d44240f43c611bd;hpb=28dbf4fd074d2046a3c8ddebac9a537a80fd457a;p=dcpomatic.git diff --git a/src/lib/cross.cc b/src/lib/cross.cc index f232f1779..53ef5723a 100644 --- a/src/lib/cross.cc +++ b/src/lib/cross.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012 Carl Hetherington + Copyright (C) 2012-2014 Carl Hetherington 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 @@ -17,14 +17,48 @@ */ +#include +#include #include "cross.h" -#ifdef DCPOMATIC_POSIX +#include "compose.hpp" +#include "log.h" +#ifdef DCPOMATIC_LINUX #include +#include #endif #ifdef DCPOMATIC_WINDOWS -#include "windows.h" +#include +#undef DATADIR +#include +#endif +#ifdef DCPOMATIC_OSX +#include +#include +#include #endif +#ifdef DCPOMATIC_POSIX +#include +#include +#include +#include +#endif +#include "exceptions.h" + +#include "i18n.h" +#define LOG_GENERAL(...) log->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL); +#define LOG_ERROR(...) log->log (String::compose (__VA_ARGS__), Log::TYPE_ERROR); +#define LOG_ERROR_NC(...) log->log (__VA_ARGS__, Log::TYPE_ERROR); + +using std::pair; +using std::list; +using std::ifstream; +using std::string; +using std::wstring; +using std::make_pair; +using boost::shared_ptr; + +/** @param s Number of seconds to sleep for */ void dcpomatic_sleep (int s) { @@ -35,3 +69,264 @@ dcpomatic_sleep (int s) Sleep (s * 1000); #endif } + +/** @return A string of CPU information (model name etc.) */ +string +cpu_info () +{ + string info; + +#ifdef DCPOMATIC_LINUX + /* This use of ifstream is ok; the filename can never + be non-Latin + */ + ifstream f ("/proc/cpuinfo"); + while (f.good ()) { + string l; + getline (f, l); + if (boost::algorithm::starts_with (l, "model name")) { + string::size_type const c = l.find (':'); + if (c != string::npos) { + info = l.substr (c + 2); + } + } + } +#endif + +#ifdef DCPOMATIC_OSX + char buffer[64]; + size_t N = sizeof (buffer); + if (sysctlbyname ("machdep.cpu.brand_string", buffer, &N, 0, 0) == 0) { + info = buffer; + } +#endif + +#ifdef DCPOMATIC_WINDOWS + HKEY key; + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &key) != ERROR_SUCCESS) { + return info; + } + + DWORD type; + DWORD data; + if (RegQueryValueEx (key, L"ProcessorNameString", 0, &type, 0, &data) != ERROR_SUCCESS) { + return info; + } + + if (type != REG_SZ) { + return info; + } + + wstring value (data / sizeof (wchar_t), L'\0'); + if (RegQueryValueEx (key, L"ProcessorNameString", 0, 0, reinterpret_cast (&value[0]), &data) != ERROR_SUCCESS) { + RegCloseKey (key); + return info; + } + + info = string (value.begin(), value.end()); + + RegCloseKey (key); + +#endif + + return info; +} + +#ifdef DCPOMATIC_OSX +/** @return Path of the Contents directory in the .app */ +boost::filesystem::path +app_contents () +{ + uint32_t size = 1024; + char buffer[size]; + if (_NSGetExecutablePath (buffer, &size)) { + throw StringError ("_NSGetExecutablePath failed"); + } + + boost::filesystem::path path (buffer); + path = boost::filesystem::canonical (path); + path = path.parent_path (); + path = path.parent_path (); + return path; +} +#endif + +void +run_ffprobe (boost::filesystem::path content, boost::filesystem::path out, shared_ptr log) +{ +#ifdef DCPOMATIC_WINDOWS + SECURITY_ATTRIBUTES security; + security.nLength = sizeof (security); + security.bInheritHandle = TRUE; + security.lpSecurityDescriptor = 0; + + HANDLE child_stderr_read; + HANDLE child_stderr_write; + if (!CreatePipe (&child_stderr_read, &child_stderr_write, &security, 0)) { + LOG_ERROR_NC ("ffprobe call failed (could not CreatePipe)"); + return; + } + + wchar_t dir[512]; + GetModuleFileName (GetModuleHandle (0), dir, sizeof (dir)); + PathRemoveFileSpec (dir); + SetCurrentDirectory (dir); + + STARTUPINFO startup_info; + ZeroMemory (&startup_info, sizeof (startup_info)); + startup_info.cb = sizeof (startup_info); + startup_info.hStdError = child_stderr_write; + startup_info.dwFlags |= STARTF_USESTDHANDLES; + + wchar_t command[512]; + wcscpy (command, L"ffprobe.exe \""); + + wchar_t file[512]; + MultiByteToWideChar (CP_UTF8, 0, content.string().c_str(), -1, file, sizeof(file)); + wcscat (command, file); + + wcscat (command, L"\""); + + PROCESS_INFORMATION process_info; + ZeroMemory (&process_info, sizeof (process_info)); + if (!CreateProcess (0, command, 0, 0, TRUE, CREATE_NO_WINDOW, 0, 0, &startup_info, &process_info)) { + LOG_ERROR_NC (N_("ffprobe call failed (could not CreateProcess)")); + return; + } + + FILE* o = fopen_boost (out, "w"); + if (!o) { + LOG_ERROR_NC (N_("ffprobe call failed (could not create output file)")); + return; + } + + CloseHandle (child_stderr_write); + + while (1) { + char buffer[512]; + DWORD read; + if (!ReadFile(child_stderr_read, buffer, sizeof(buffer), &read, 0) || read == 0) { + break; + } + fwrite (buffer, read, 1, o); + } + + fclose (o); + + WaitForSingleObject (process_info.hProcess, INFINITE); + CloseHandle (process_info.hProcess); + CloseHandle (process_info.hThread); + CloseHandle (child_stderr_read); +#endif + +#ifdef DCPOMATIC_LINUX + string ffprobe = "ffprobe \"" + content.string() + "\" 2> \"" + out.string() + "\""; + LOG_GENERAL (N_("Probing with %1"), ffprobe); + system (ffprobe.c_str ()); +#endif + +#ifdef DCPOMATIC_OSX + boost::filesystem::path path = app_contents(); + path /= "MacOS"; + path /= "ffprobe"; + + string ffprobe = path.string() + " \"" + content.string() + "\" 2> \"" + out.string() + "\""; + LOG_GENERAL (N_("Probing with %1"), ffprobe); + system (ffprobe.c_str ()); +#endif +} + +list > +mount_info () +{ + list > m; + +#ifdef DCPOMATIC_LINUX + FILE* f = setmntent ("/etc/mtab", "r"); + if (!f) { + return m; + } + + while (1) { + struct mntent* mnt = getmntent (f); + if (!mnt) { + break; + } + + m.push_back (make_pair (mnt->mnt_dir, mnt->mnt_type)); + } + + endmntent (f); +#endif + + return m; +} + +boost::filesystem::path +openssl_path () +{ +#ifdef DCPOMATIC_WINDOWS + wchar_t dir[512]; + GetModuleFileName (GetModuleHandle (0), dir, sizeof (dir)); + PathRemoveFileSpec (dir); + + boost::filesystem::path path = dir; + path /= "openssl.exe"; + return path; +#else + /* We assume that it's on the path for Linux and OS X */ + return "openssl"; +#endif + +} + +/* Apparently there is no way to create an ofstream using a UTF-8 + filename under Windows. We are hence reduced to using fopen + with this wrapper. +*/ +FILE * +fopen_boost (boost::filesystem::path p, string t) +{ +#ifdef DCPOMATIC_WINDOWS + wstring w (t.begin(), t.end()); + /* c_str() here should give a UTF-16 string */ + return _wfopen (p.c_str(), w.c_str ()); +#else + return fopen (p.c_str(), t.c_str ()); +#endif +} + +int +dcpomatic_fseek (FILE* stream, int64_t offset, int whence) +{ +#ifdef DCPOMATIC_WINDOWS + return _fseeki64 (stream, offset, whence); +#else + return fseek (stream, offset, whence); +#endif +} + +void +Waker::nudge () +{ +#ifdef DCPOMATIC_WINDOWS + SetThreadExecutionState (ES_CONTINUOUS); +#endif +} + +Waker::Waker () +{ +#ifdef DCPOMATIC_OSX + /* We should use this */ + // IOPMAssertionCreateWithName (kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, CFSTR ("Encoding DCP"), &_assertion_id); + /* but it's not available on 10.5, so we use this */ + IOPMAssertionCreate (kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, &_assertion_id); +#endif +} + +Waker::~Waker () +{ +#ifdef DCPOMATIC_OSX + IOPMAssertionRelease (_assertion_id); +#endif +}