Mercurial > wgsdk
view src/config.c @ 12:dd427b7cc459 default tip
json: replace with nxjson library
more lightweight, reduces the binary size by about 40 kb
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Fri, 15 Mar 2024 20:46:18 -0400 |
parents | e6a594f16403 |
children |
line wrap: on
line source
/** * config.c: * * Functions to load/save/edit the config. **/ #include "dirtools.h" #include "config.h" #include "ini.h" #include "plugin.h" /* g_plugin */ /* bypass intptr_t check */ #ifndef _MSC_VER #define _MSC_VER 1201 #define WGSDK_UGLY_MSC_HACK 1 #endif #include <Winamp/wa_ipc.h> #ifdef WGSDK_UGLY_MSC_HACK #undef _MSC_VER #endif #include <shlwapi.h> #include <shlobj.h> #include <assert.h> #define MAX_LINE_LENGTH 256 #ifndef IPC_GETPLUGINDIRECTORYW /* requires Winamp 5.58+ */ #define IPC_GETPLUGINDIRECTORYW 1336 #endif /* set defaults */ struct config config = { .display_title = 1, .display_artist_name = 1, .display_album_name = 1, .display_album_art = 1, .display_song_info = 1, .show_elapsed_time = 1 }; /* must be free'd by the caller */ LPWSTR cfg_get_path() { LPWSTR plugins_folder = NULL; DWORD winamp_version = SendMessage(g_plugin.hwndParent, WM_WA_IPC, 0, IPC_GETVERSION); if (winamp_version >= 0x5580) { /* Native wide string version of IPC_GETPLUGINDIRECTORY */ LPCWSTR w_plugins_folder = (LPCWSTR)SendMessage(g_plugin.hwndParent, WM_WA_IPC, 0, IPC_GETPLUGINDIRECTORYW); size_t len = wcslen(w_plugins_folder); plugins_folder = calloc(len + 1, sizeof(WCHAR)); if (!plugins_folder) return NULL; wcsncpy(plugins_folder, w_plugins_folder, len); } else if (winamp_version >= 0x5110) { /* ANSI string version of IPC_GETPLUGINDIRECTORY, convert */ LPCSTR plugins_folder_ansi = (LPCSTR)SendMessage(g_plugin.hwndParent, WM_WA_IPC, 0, IPC_GETPLUGINDIRECTORY); int required_size = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, plugins_folder_ansi, -1, NULL, 0); if (required_size < 0) return NULL; plugins_folder = calloc(required_size, sizeof(WCHAR)); if (!plugins_folder) return NULL; int size = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, plugins_folder_ansi, -1, plugins_folder, required_size); if (size < 0) return NULL; } else if (winamp_version >= 0x2900) { /* Ancient winamp, use IPC_GETINIDIRECTORY and find out from there */ LPCSTR ini_directory = (LPCSTR)SendMessage(g_plugin.hwndParent, WM_WA_IPC, 0, IPC_GETINIDIRECTORY); int required_size = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ini_directory, -1, NULL, 0); if (required_size < 0) return NULL; LPWSTR ini_directory_w = calloc(required_size, sizeof(WCHAR)); if (!ini_directory_w) return NULL; int size = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ini_directory, -1, ini_directory_w, required_size); if (size < 0) { free(ini_directory_w); return NULL; } plugins_folder = dirtools_concat_paths(ini_directory_w, L"Plugins"); free(ini_directory_w); } else { /* please, please for the love of God update winamp. */ WCHAR appdata[MAX_PATH] = {L'\0'}; HRESULT res = SHGetFolderPathW( g_plugin.hwndParent, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata ); if (res != S_OK) return NULL; plugins_folder = dirtools_concat_paths(appdata, L"Winamp\\Plugins"); } LPWSTR final = dirtools_concat_paths(plugins_folder, L"wgsdk"); free(plugins_folder); return final; } static int cfg_ini_handler(void* data, const char* section, const char* key, const char* value) { struct config* config = (struct config*)data; char* ptr; // used with strtol if (!strcmp(section, "Display configuration")) { if (!strcmp(key, "Display title")) { config->display_title = !!strtol(value, &ptr, 10); return 1; } else if (!strcmp(key, "Display artist name")) { config->display_artist_name = !!strtol(value, &ptr, 10); return 1; } else if (!strcmp(key, "Display album name")) { config->display_album_name = !!strtol(value, &ptr, 10); return 1; } else if (!strcmp(key, "Display album art")) { config->display_album_art = !!strtol(value, &ptr, 10); return 1; } else if (!strcmp(key, "Display song information")) { config->display_song_info = !!strtol(value, &ptr, 10); return 1; } else if (!strcmp(key, "Show elapsed time")) { config->show_elapsed_time = !!strtol(value, &ptr, 10); return 1; } else return 0; } else return 0; } char* cfg_ini_reader(char* str, int num, void* stream) { HANDLE file = (HANDLE)stream; DWORD bytes_read; return (ReadFile(file, str, num, &bytes_read, NULL) && num == bytes_read) ? str : NULL; } int cfg_load(struct config* restrict config) { LPWSTR fold_path = cfg_get_path(); assert(fold_path); LPWSTR path = dirtools_concat_paths(fold_path, L"config.ini"); free(fold_path); HANDLE file = CreateFileW(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (file == INVALID_HANDLE_VALUE) /* file doesn't exist? */ return 0; if (ini_parse_stream(cfg_ini_reader, file, cfg_ini_handler, config)) return 1; CloseHandle(file); free(path); return 0; } void cfg_write_int_key(HANDLE file, const char* key, int value) { DWORD bytes_written; /* write the key */ size_t len = strlen(key) * sizeof(*key); WriteFile(file, key, len, &bytes_written, NULL); assert(bytes_written == len); static const char equals[] = {'='}; WriteFile(file, equals, sizeof(equals), &bytes_written, NULL); assert(bytes_written == sizeof(equals)); char buf[16] = {'\0'}; _itoa(value, buf, 10); len = strlen(buf) * sizeof(buf[0]); WriteFile(file, (buf), len, &bytes_written, NULL); assert(bytes_written == len); static const char ln[] = {'\r', '\n'}; WriteFile(file, ln, sizeof(ln), &bytes_written, NULL); assert(bytes_written == sizeof(ln)); } void cfg_write_header(HANDLE file, const char* header) { DWORD bytes_written = 0; static const char l_bracket[] = {'['}; WriteFile(file, l_bracket, sizeof(l_bracket), &bytes_written, NULL); assert(bytes_written == sizeof(l_bracket)); const size_t len = strlen(header) * sizeof(*header); WriteFile(file, header, len, &bytes_written, NULL); assert(bytes_written == len); static const char r_bracket[] = {']'}; WriteFile(file, r_bracket, sizeof(r_bracket), &bytes_written, NULL); assert(bytes_written == sizeof(r_bracket)); static const char ln[] = {'\r', '\n'}; WriteFile(file, ln, sizeof(ln), &bytes_written, NULL); assert(bytes_written == sizeof(ln)); } int cfg_save(const struct config* config) { LPWSTR fold_path = cfg_get_path(); assert(fold_path); assert(!dirtools_create_directory(fold_path)); LPWSTR path = dirtools_concat_paths(fold_path, L"config.ini"); free(fold_path); /* dirty little hack that lets me not use goto */ do { HANDLE file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (file == INVALID_HANDLE_VALUE) /* huh */ break; cfg_write_header(file, "Display configuration"); cfg_write_int_key(file, "Display title", config->display_title); cfg_write_int_key(file, "Display artist name", config->display_artist_name); cfg_write_int_key(file, "Display album name", config->display_album_name); cfg_write_int_key(file, "Display album art", config->display_album_art); cfg_write_int_key(file, "Display song information", config->display_song_info); cfg_write_int_key(file, "Show elapsed time", config->show_elapsed_time); CloseHandle(file); } while (0); free(path); return 0; } #undef WritePrivateProfileIntW