msacm32: Fix buffer double free.
[wine/zf.git] / dlls / uxtheme / uxini.c
bloba2dfabfd0de32513c07a331792e1f092acfd8257
1 /*
2 * Win32 5.1 uxtheme ini file processing
4 * Copyright (C) 2004 Kevin Koltzau
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winnls.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(uxtheme);
33 /***********************************************************************
34 * Defines and global variables
37 static const WCHAR szTextFileResource[] = {
38 'T','E','X','T','F','I','L','E','\0'
41 typedef struct _UXINI_FILE {
42 LPCWSTR lpIni;
43 LPCWSTR lpCurLoc;
44 LPCWSTR lpEnd;
45 } UXINI_FILE, *PUXINI_FILE;
47 /***********************************************************************/
49 /**********************************************************************
50 * UXINI_LoadINI
52 * Load a theme INI file out of resources from the specified
53 * theme
55 * PARAMS
56 * tf Theme to load INI file out of resources
57 * lpName Resource name of the INI file
59 * RETURNS
60 * INI file, or NULL if not found
62 PUXINI_FILE UXINI_LoadINI(HMODULE hTheme, LPCWSTR lpName) {
63 HRSRC hrsc;
64 LPCWSTR lpThemesIni = NULL;
65 PUXINI_FILE uf;
66 DWORD dwIniSize;
68 TRACE("Loading resource INI %s\n", debugstr_w(lpName));
70 if((hrsc = FindResourceW(hTheme, lpName, szTextFileResource))) {
71 if(!(lpThemesIni = LoadResource(hTheme, hrsc))) {
72 TRACE("%s resource not found\n", debugstr_w(lpName));
73 return NULL;
77 dwIniSize = SizeofResource(hTheme, hrsc) / sizeof(WCHAR);
78 uf = HeapAlloc(GetProcessHeap(), 0, sizeof(UXINI_FILE));
79 uf->lpIni = lpThemesIni;
80 uf->lpCurLoc = lpThemesIni;
81 uf->lpEnd = lpThemesIni + dwIniSize;
82 return uf;
85 /**********************************************************************
86 * UXINI_CloseINI
88 * Close an open theme INI file
90 * PARAMS
91 * uf Theme INI file to close
93 void UXINI_CloseINI(PUXINI_FILE uf)
95 HeapFree(GetProcessHeap(), 0, uf);
98 /**********************************************************************
99 * UXINI_eof
101 * Determines if we are at the end of the INI file
103 * PARAMS
104 * uf Theme INI file to test
106 static inline BOOL UXINI_eof(PUXINI_FILE uf)
108 return uf->lpCurLoc >= uf->lpEnd;
111 /**********************************************************************
112 * UXINI_isspace
114 * Check if a character is a space character
116 * PARAMS
117 * c Character to test
119 static inline BOOL UXINI_isspace(WCHAR c)
121 if (isspace(c)) return TRUE;
122 if (c=='\r') return TRUE;
123 return FALSE;
126 /**********************************************************************
127 * UXINI_GetNextLine
129 * Get the next line in the INI file, non NULL terminated
130 * removes whitespace at beginning and end of line, and removes comments
132 * PARAMS
133 * uf INI file to retrieve next line
134 * dwLen Location to store pointer to line length
136 * RETURNS
137 * The section name, non NULL terminated
139 static LPCWSTR UXINI_GetNextLine(PUXINI_FILE uf, DWORD *dwLen)
141 LPCWSTR lpLineEnd;
142 LPCWSTR lpLineStart;
143 DWORD len;
144 do {
145 if(UXINI_eof(uf)) return NULL;
146 /* Skip whitespace and empty lines */
147 while(!UXINI_eof(uf) && (UXINI_isspace(*uf->lpCurLoc) || *uf->lpCurLoc == '\n')) uf->lpCurLoc++;
148 lpLineStart = uf->lpCurLoc;
149 lpLineEnd = uf->lpCurLoc;
150 while(!UXINI_eof(uf) && *uf->lpCurLoc != '\n' && *uf->lpCurLoc != ';') lpLineEnd = ++uf->lpCurLoc;
151 /* If comment was found, skip the rest of the line */
152 if(*uf->lpCurLoc == ';')
153 while(!UXINI_eof(uf) && *uf->lpCurLoc != '\n') uf->lpCurLoc++;
154 len = (lpLineEnd - lpLineStart);
155 if(*lpLineStart != ';' && len == 0)
156 return NULL;
157 } while(*lpLineStart == ';');
158 /* Remove whitespace from end of line */
159 while(UXINI_isspace(lpLineStart[len-1])) len--;
160 *dwLen = len;
162 return lpLineStart;
165 static inline void UXINI_UnGetToLine(PUXINI_FILE uf, LPCWSTR lpLine)
167 uf->lpCurLoc = lpLine;
170 /**********************************************************************
171 * UXINI_GetNextSection
173 * Locate the next section in the ini file, and return pointer to
174 * section name, non NULL terminated. Use dwLen to determine length
176 * PARAMS
177 * uf INI file to search, search starts at current location
178 * dwLen Location to store pointer to section name length
180 * RETURNS
181 * The section name, non NULL terminated
183 LPCWSTR UXINI_GetNextSection(PUXINI_FILE uf, DWORD *dwLen)
185 LPCWSTR lpLine;
186 while((lpLine = UXINI_GetNextLine(uf, dwLen))) {
187 /* Assuming a ']' ending to the section name */
188 if(lpLine[0] == '[') {
189 lpLine++;
190 *dwLen -= 2;
191 break;
194 return lpLine;
197 /**********************************************************************
198 * UXINI_FindSection
200 * Locate a section with the specified name, search starts
201 * at current location in ini file
203 * PARAMS
204 * uf INI file to search, search starts at current location
205 * lpName Name of the section to locate
207 * RETURNS
208 * TRUE if section was found, FALSE otherwise
210 BOOL UXINI_FindSection(PUXINI_FILE uf, LPCWSTR lpName)
212 LPCWSTR lpSection;
213 DWORD dwLen;
214 while((lpSection = UXINI_GetNextSection(uf, &dwLen))) {
215 if(CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lpSection, dwLen, lpName, -1) == CSTR_EQUAL) {
216 return TRUE;
219 return FALSE;
222 /**********************************************************************
223 * UXINI_GetNextValue
225 * Locate the next value in the current section
227 * PARAMS
228 * uf INI file to search, search starts at current location
229 * dwNameLen Location to store pointer to value name length
230 * lpValue Location to store pointer to the value
231 * dwValueLen Location to store pointer to value length
233 * RETURNS
234 * The value name, non NULL terminated
236 LPCWSTR UXINI_GetNextValue(PUXINI_FILE uf, DWORD *dwNameLen, LPCWSTR *lpValue, DWORD *dwValueLen)
238 LPCWSTR lpLine;
239 LPCWSTR lpLineEnd;
240 LPCWSTR name = NULL;
241 LPCWSTR value = NULL;
242 DWORD vallen = 0;
243 DWORD namelen = 0;
244 DWORD dwLen;
245 lpLine = UXINI_GetNextLine(uf, &dwLen);
246 if(!lpLine)
247 return NULL;
248 if(lpLine[0] == '[') {
249 UXINI_UnGetToLine(uf, lpLine);
250 return NULL;
252 lpLineEnd = lpLine + dwLen;
254 name = lpLine;
255 while(namelen < dwLen && *lpLine != '=') {
256 lpLine++;
257 namelen++;
259 if(*lpLine != '=') return NULL;
260 lpLine++;
262 /* Remove whitespace from end of name */
263 while(UXINI_isspace(name[namelen-1])) namelen--;
264 /* Remove whitespace from beginning of value */
265 while(UXINI_isspace(*lpLine) && lpLine < lpLineEnd) lpLine++;
266 value = lpLine;
267 vallen = dwLen-(value-name);
269 *dwNameLen = namelen;
270 *dwValueLen = vallen;
271 *lpValue = value;
273 return name;
276 /**********************************************************************
277 * UXINI_FindValue
279 * Locate a value by name
281 * PARAMS
282 * uf INI file to search, search starts at current location
283 * lpName Value name to locate
284 * lpValue Location to store pointer to the value
285 * dwValueLen Location to store pointer to value length
287 * RETURNS
288 * The value name, non NULL terminated
290 BOOL UXINI_FindValue(PUXINI_FILE uf, LPCWSTR lpName, LPCWSTR *lpValue, DWORD *dwValueLen)
292 LPCWSTR name;
293 DWORD namelen;
295 while((name = UXINI_GetNextValue(uf, &namelen, lpValue, dwValueLen))) {
296 if(CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, name, namelen, lpName, -1) == CSTR_EQUAL) {
297 return TRUE;
300 return FALSE;