/***************************************************************************** * asa: portable digital subtitle renderer ***************************************************************************** * Copyright (C) 2007 David Lamparter * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ****************************************************************************/ #include #include #include #include #include "../csrilib.h" #include "subhelp.h" static void csrilib_enum_dir(const wchar_t *dir); static const char *get_errstr() { static char msg[2048]; DWORD err = GetLastError(); if (!FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, 0, msg, sizeof(msg), NULL)) strcpy(msg, "Unknown Error"); else { size_t msglen = strlen(msg) - 1; if (msg[msglen] == '\n') msg[msglen] = '\0'; } return msg; } static void csrilib_add(csri_rend *rend, const struct csri_wrap_rend *tmp, struct csri_info *info) { struct csri_wrap_rend *wrend = (struct csri_wrap_rend *) malloc(sizeof(struct csri_wrap_rend)); if (!wrend) return; memcpy(wrend, tmp, sizeof(struct csri_wrap_rend)); wrend->rend = rend; wrend->info = info; csrilib_rend_initadd(wrend); } static void csrilib_do_load(const wchar_t *filename) { HMODULE dlhandle = LoadLibraryExW(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); struct csri_wrap_rend tmp; csri_rend *rend; struct csri_info *(*renderer_info)(csri_rend *rend); csri_rend *(*renderer_default)(); csri_rend *(*renderer_next)(csri_rend *prev); const char *sym; if (!dlhandle) { subhelp_log(CSRI_LOG_WARNING, "LoadLibraryEx(\"%ls\") failed: " "%s", filename, get_errstr()); return; } if (GetProcAddress(dlhandle, "csri_library")) { subhelp_log(CSRI_LOG_WARNING, "ignoring library %ls", filename); goto out_freelib; } subhelp_log(CSRI_LOG_INFO, "loading %ls", filename); tmp.os.dlhandle = dlhandle; /* okay, this is uber-ugly. either I end up casting from void * * to a fptr (which yields a cast warning), or I do a *(void **)&tmp.x * (which yields a strict-aliasing warning). * casting via char* works because char* can alias anything. */ #define _dl_map_function(x, dst) do { \ char *t1 = (char *)&dst; \ union x { FARPROC ptr; } *ptr = (union x *)t1; \ sym = "csri_" # x; \ ptr->ptr = GetProcAddress(dlhandle, sym);\ if (!ptr->ptr) goto out_dlfail; } while (0) #define dl_map_function(x) _dl_map_function(x, tmp.x) dl_map_function(query_ext); subhelp_logging_pass((struct csri_logging_ext *) tmp.query_ext(NULL, CSRI_EXT_LOGGING)); dl_map_function(open_file); dl_map_function(open_mem); dl_map_function(close); dl_map_function(request_fmt); dl_map_function(render); #define dl_map_local(x) _dl_map_function(x, x) dl_map_local(renderer_info); dl_map_local(renderer_default); dl_map_local(renderer_next); rend = renderer_default(); while (rend) { csrilib_add(rend, &tmp, renderer_info(rend)); rend = renderer_next(rend); } return; out_dlfail: subhelp_log(CSRI_LOG_WARNING, "%ls: symbol %s not found (%s)", filename, sym, get_errstr()); out_freelib: FreeLibrary(dlhandle); } static void csrilib_load(const wchar_t *filename) { DWORD attr = GetFileAttributesW(filename); if (attr == INVALID_FILE_ATTRIBUTES) return; if (attr & FILE_ATTRIBUTE_DIRECTORY) { csrilib_enum_dir(filename); return; } csrilib_do_load(filename); } static void csrilib_enum_dir(const wchar_t *dir) { WIN32_FIND_DATAW data; HANDLE res; wchar_t buf[MAX_PATH]; _snwprintf(buf, sizeof(buf) / sizeof(buf[0]), L"%ls\\*", dir); res = FindFirstFileW(buf, &data); if (res == INVALID_HANDLE_VALUE) { subhelp_log(CSRI_LOG_WARNING, "ignoring directory \"%ls\": %s", dir, get_errstr()); return; } subhelp_log(CSRI_LOG_INFO, "scanning directory \"%ls\"", dir); do { if (data.cFileName[0] == '.') continue; _snwprintf(buf, sizeof(buf) / sizeof(buf[0]), L"%ls\\%ls", dir, data.cFileName); csrilib_load(buf); } while (FindNextFileW(res, &data)); FindClose(res); } void csrilib_os_init() { wchar_t filename[MAX_PATH], *slash; DWORD rv = GetModuleFileNameW(NULL, filename, MAX_PATH); if (!rv) *filename = L'\0'; slash = wcsrchr(filename, L'\\'); slash = slash ? slash + 1 : filename; *slash = L'\0'; wcsncpy(slash, L"csri", filename + MAX_PATH - slash); csrilib_enum_dir(filename); }