| /* | |
| * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 | |
| */ | |
| 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; | |
| } |