/* * Win32 5.1 uxtheme ini file processing * * Copyright (C) 2004 Kevin Koltzau * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" #include <stdarg.h> #include "windef.h" #include "winbase.h" #include "winnls.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(uxtheme); /*********************************************************************** * Defines and global variables */ static const WCHAR szTextFileResource[] = { 'T','E','X','T','F','I','L','E','\0' }; typedef struct _UXINI_FILE { LPCWSTR lpIni; LPCWSTR lpCurLoc; LPCWSTR lpEnd; } UXINI_FILE, *PUXINI_FILE; /***********************************************************************/ /********************************************************************** * UXINI_LoadINI * * Load a theme INI file out of resources from the specified * theme * * PARAMS * tf Theme to load INI file out of resources * lpName Resource name of the INI file * * RETURNS * INI file, or NULL if not found */ PUXINI_FILE UXINI_LoadINI(HMODULE hTheme, LPCWSTR lpName) { HRSRC hrsc; LPCWSTR lpThemesIni = NULL; PUXINI_FILE uf; DWORD dwIniSize; TRACE("Loading resource INI %s\n", debugstr_w(lpName)); if((hrsc = FindResourceW(hTheme, lpName, szTextFileResource))) { if(!(lpThemesIni = (LPCWSTR)LoadResource(hTheme, hrsc))) { TRACE("%s resource not found\n", debugstr_w(lpName)); return NULL; } } dwIniSize = SizeofResource(hTheme, hrsc) / sizeof(WCHAR); uf = HeapAlloc(GetProcessHeap(), 0, sizeof(UXINI_FILE)); uf->lpIni = lpThemesIni; uf->lpCurLoc = lpThemesIni; uf->lpEnd = lpThemesIni + dwIniSize; return uf; } /********************************************************************** * UXINI_CloseINI * * Close an open theme INI file * * PARAMS * uf Theme INI file to close */ void UXINI_CloseINI(PUXINI_FILE uf) { HeapFree(GetProcessHeap(), 0, uf); } /********************************************************************** * UXINI_ResetINI * * Reset the current pointer into INI file to the beginning of the file * * PARAMS * uf Theme INI file to reset */ void UXINI_ResetINI(PUXINI_FILE uf) { uf->lpCurLoc = uf->lpIni; } /********************************************************************** * UXINI_eof * * Determines if we are at the end of the INI file * * PARAMS * uf Theme INI file to test */ static inline BOOL UXINI_eof(PUXINI_FILE uf) { return uf->lpCurLoc >= uf->lpEnd; } /********************************************************************** * UXINI_isspace * * Check if a character is a space character * * PARAMS * c Character to test */ static inline BOOL UXINI_isspace(WCHAR c) { if (isspace(c)) return TRUE; if (c=='\r') return TRUE; return FALSE; } /********************************************************************** * UXINI_GetNextLine * * Get the next line in the INI file, non NULL terminated * removes whitespace at beginning and end of line, and removes comments * * PARAMS * uf INI file to retrieve next line * dwLen Location to store pointer to line length * * RETURNS * The section name, non NULL terminated */ static LPCWSTR UXINI_GetNextLine(PUXINI_FILE uf, DWORD *dwLen) { LPCWSTR lpLineEnd; LPCWSTR lpLineStart; DWORD len; do { if(UXINI_eof(uf)) return NULL; /* Skip whitespace and empty lines */ while(!UXINI_eof(uf) && (UXINI_isspace(*uf->lpCurLoc) || *uf->lpCurLoc == '\n')) uf->lpCurLoc++; lpLineStart = uf->lpCurLoc; lpLineEnd = uf->lpCurLoc; while(!UXINI_eof(uf) && *uf->lpCurLoc != '\n' && *uf->lpCurLoc != ';') lpLineEnd = ++uf->lpCurLoc; /* If comment was found, skip the rest of the line */ if(*uf->lpCurLoc == ';') while(!UXINI_eof(uf) && *uf->lpCurLoc != '\n') uf->lpCurLoc++; len = (lpLineEnd - lpLineStart); if(*lpLineStart != ';' && len == 0) return NULL; } while(*lpLineStart == ';'); /* Remove whitespace from end of line */ while(UXINI_isspace(lpLineStart[len-1])) len--; *dwLen = len; return lpLineStart; } static inline void UXINI_UnGetToLine(PUXINI_FILE uf, LPCWSTR lpLine) { uf->lpCurLoc = lpLine; } /********************************************************************** * UXINI_GetNextSection * * Locate the next section in the ini file, and return pointer to * section name, non NULL terminated. Use dwLen to determine length * * PARAMS * uf INI file to search, search starts at current location * dwLen Location to store pointer to section name length * * RETURNS * The section name, non NULL terminated */ LPCWSTR UXINI_GetNextSection(PUXINI_FILE uf, DWORD *dwLen) { LPCWSTR lpLine; while((lpLine = UXINI_GetNextLine(uf, dwLen))) { /* Assuming a ']' ending to the section name */ if(lpLine[0] == '[') { lpLine++; *dwLen -= 2; break; } } return lpLine; } /********************************************************************** * UXINI_FindSection * * Locate a section with the specified name, search starts * at current location in ini file * to start search from start, call UXINI_ResetINI * * PARAMS * uf INI file to search, search starts at current location * lpName Name of the section to locate * * RETURNS * TRUE if section was found, FALSE otherwise */ BOOL UXINI_FindSection(PUXINI_FILE uf, LPCWSTR lpName) { LPCWSTR lpSection; DWORD dwLen; while((lpSection = UXINI_GetNextSection(uf, &dwLen))) { if(CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lpSection, dwLen, lpName, -1) == CSTR_EQUAL) { return TRUE; } } return FALSE; } /********************************************************************** * UXINI_GetNextValue * * Locate the next value in the current section * * PARAMS * uf INI file to search, search starts at current location * dwNameLen Location to store pointer to value name length * lpValue Location to store pointer to the value * dwValueLen Location to store pointer to value length * * RETURNS * The value name, non NULL terminated */ LPCWSTR UXINI_GetNextValue(PUXINI_FILE uf, DWORD *dwNameLen, LPCWSTR *lpValue, DWORD *dwValueLen) { LPCWSTR lpLine; LPCWSTR lpLineEnd; LPCWSTR name = NULL; LPCWSTR value = NULL; DWORD vallen = 0; DWORD namelen = 0; DWORD dwLen; lpLine = UXINI_GetNextLine(uf, &dwLen); if(!lpLine) return NULL; if(lpLine[0] == '[') { UXINI_UnGetToLine(uf, lpLine); return NULL; } lpLineEnd = lpLine + dwLen; name = lpLine; while(namelen < dwLen && *lpLine != '=') { lpLine++; namelen++; } if(*lpLine != '=') return NULL; lpLine++; /* Remove whitespace from end of name */ while(UXINI_isspace(name[namelen-1])) namelen--; /* Remove whitespace from beginning of value */ while(UXINI_isspace(*lpLine) && lpLine < lpLineEnd) lpLine++; value = lpLine; vallen = dwLen-(value-name); *dwNameLen = namelen; *dwValueLen = vallen; *lpValue = value; return name; } /********************************************************************** * UXINI_FindValue * * Locate a value by name * * PARAMS * uf INI file to search, search starts at current location * lpName Value name to locate * lpValue Location to store pointer to the value * dwValueLen Location to store pointer to value length * * RETURNS * The value name, non NULL terminated */ BOOL UXINI_FindValue(PUXINI_FILE uf, LPCWSTR lpName, LPCWSTR *lpValue, DWORD *dwValueLen) { LPCWSTR name; DWORD namelen; while((name = UXINI_GetNextValue(uf, &namelen, lpValue, dwValueLen))) { if(CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, name, namelen, lpName, -1) == CSTR_EQUAL) { return TRUE; } } return FALSE; }