316 lines
8.9 KiB
C
316 lines
8.9 KiB
C
/*
|
|
* 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 = 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;
|
|
}
|