- Fix warnings
[reactos.git] / reactos / lib / uxtheme / uxini.c
1 /*
2 * Win32 5.1 uxtheme ini file processing
3 *
4 * Copyright (C) 2004 Kevin Koltzau
5 *
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.
10 *
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.
15 *
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24 #include <ctype.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29
30 #include "wine/debug.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(uxtheme);
33
34 /***********************************************************************
35 * Defines and global variables
36 */
37
38 static const WCHAR szTextFileResource[] = {
39 'T','E','X','T','F','I','L','E','\0'
40 };
41
42 typedef struct _UXINI_FILE {
43 LPCWSTR lpIni;
44 LPCWSTR lpCurLoc;
45 LPCWSTR lpEnd;
46 } UXINI_FILE, *PUXINI_FILE;
47
48 /***********************************************************************/
49
50 /**********************************************************************
51 * UXINI_LoadINI
52 *
53 * Load a theme INI file out of resources from the specified
54 * theme
55 *
56 * PARAMS
57 * tf Theme to load INI file out of resources
58 * lpName Resource name of the INI file
59 *
60 * RETURNS
61 * INI file, or NULL if not found
62 */
63 PUXINI_FILE UXINI_LoadINI(HMODULE hTheme, LPCWSTR lpName) {
64 HRSRC hrsc;
65 LPCWSTR lpThemesIni = NULL;
66 PUXINI_FILE uf;
67 DWORD dwIniSize;
68
69 TRACE("Loading resource INI %s\n", debugstr_w(lpName));
70
71 if((hrsc = FindResourceW(hTheme, lpName, szTextFileResource))) {
72 if(!(lpThemesIni = (LPCWSTR)LoadResource(hTheme, hrsc))) {
73 TRACE("%s resource not found\n", debugstr_w(lpName));
74 return NULL;
75 }
76 }
77
78 dwIniSize = SizeofResource(hTheme, hrsc) / sizeof(WCHAR);
79 uf = HeapAlloc(GetProcessHeap(), 0, sizeof(UXINI_FILE));
80 uf->lpIni = lpThemesIni;
81 uf->lpCurLoc = lpThemesIni;
82 uf->lpEnd = lpThemesIni + dwIniSize;
83 return uf;
84 }
85
86 /**********************************************************************
87 * UXINI_CloseINI
88 *
89 * Close an open theme INI file
90 *
91 * PARAMS
92 * uf Theme INI file to close
93 */
94 void UXINI_CloseINI(PUXINI_FILE uf)
95 {
96 HeapFree(GetProcessHeap(), 0, uf);
97 }
98
99 /**********************************************************************
100 * UXINI_ResetINI
101 *
102 * Reset the current pointer into INI file to the beginning of the file
103 *
104 * PARAMS
105 * uf Theme INI file to reset
106 */
107 void UXINI_ResetINI(PUXINI_FILE uf)
108 {
109 uf->lpCurLoc = uf->lpIni;
110 }
111
112 /**********************************************************************
113 * UXINI_eof
114 *
115 * Determines if we are at the end of the INI file
116 *
117 * PARAMS
118 * uf Theme INI file to test
119 */
120 static inline BOOL UXINI_eof(PUXINI_FILE uf)
121 {
122 return uf->lpCurLoc >= uf->lpEnd;
123 }
124
125 /**********************************************************************
126 * UXINI_isspace
127 *
128 * Check if a character is a space character
129 *
130 * PARAMS
131 * c Character to test
132 */
133 static inline BOOL UXINI_isspace(WCHAR c)
134 {
135 if (isspace(c)) return TRUE;
136 if (c=='\r') return TRUE;
137 return FALSE;
138 }
139
140 /**********************************************************************
141 * UXINI_GetNextLine
142 *
143 * Get the next line in the INI file, non NULL terminated
144 * removes whitespace at beginning and end of line, and removes comments
145 *
146 * PARAMS
147 * uf INI file to retrieve next line
148 * dwLen Location to store pointer to line length
149 *
150 * RETURNS
151 * The section name, non NULL terminated
152 */
153 static LPCWSTR UXINI_GetNextLine(PUXINI_FILE uf, DWORD *dwLen)
154 {
155 LPCWSTR lpLineEnd;
156 LPCWSTR lpLineStart;
157 DWORD len;
158 do {
159 if(UXINI_eof(uf)) return NULL;
160 /* Skip whitespace and empty lines */
161 while(!UXINI_eof(uf) && (UXINI_isspace(*uf->lpCurLoc) || *uf->lpCurLoc == '\n')) uf->lpCurLoc++;
162 lpLineStart = uf->lpCurLoc;
163 lpLineEnd = uf->lpCurLoc;
164 while(!UXINI_eof(uf) && *uf->lpCurLoc != '\n' && *uf->lpCurLoc != ';') lpLineEnd = ++uf->lpCurLoc;
165 /* If comment was found, skip the rest of the line */
166 if(*uf->lpCurLoc == ';')
167 while(!UXINI_eof(uf) && *uf->lpCurLoc != '\n') uf->lpCurLoc++;
168 len = (lpLineEnd - lpLineStart);
169 if(*lpLineStart != ';' && len == 0)
170 return NULL;
171 } while(*lpLineStart == ';');
172 /* Remove whitespace from end of line */
173 while(UXINI_isspace(lpLineStart[len-1])) len--;
174 *dwLen = len;
175
176 return lpLineStart;
177 }
178
179 static inline void UXINI_UnGetToLine(PUXINI_FILE uf, LPCWSTR lpLine)
180 {
181 uf->lpCurLoc = lpLine;
182 }
183
184 /**********************************************************************
185 * UXINI_GetNextSection
186 *
187 * Locate the next section in the ini file, and return pointer to
188 * section name, non NULL terminated. Use dwLen to determine length
189 *
190 * PARAMS
191 * uf INI file to search, search starts at current location
192 * dwLen Location to store pointer to section name length
193 *
194 * RETURNS
195 * The section name, non NULL terminated
196 */
197 LPCWSTR UXINI_GetNextSection(PUXINI_FILE uf, DWORD *dwLen)
198 {
199 LPCWSTR lpLine;
200 while((lpLine = UXINI_GetNextLine(uf, dwLen))) {
201 /* Assuming a ']' ending to the section name */
202 if(lpLine[0] == '[') {
203 lpLine++;
204 *dwLen -= 2;
205 break;
206 }
207 }
208 return lpLine;
209 }
210
211 /**********************************************************************
212 * UXINI_FindSection
213 *
214 * Locate a section with the specified name, search starts
215 * at current location in ini file
216 * to start search from start, call UXINI_ResetINI
217 *
218 * PARAMS
219 * uf INI file to search, search starts at current location
220 * lpName Name of the section to locate
221 *
222 * RETURNS
223 * TRUE if section was found, FALSE otherwise
224 */
225 BOOL UXINI_FindSection(PUXINI_FILE uf, LPCWSTR lpName)
226 {
227 LPCWSTR lpSection;
228 DWORD dwLen;
229 while((lpSection = UXINI_GetNextSection(uf, &dwLen))) {
230 if(CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lpSection, dwLen, lpName, -1) == CSTR_EQUAL) {
231 return TRUE;
232 }
233 }
234 return FALSE;
235 }
236
237 /**********************************************************************
238 * UXINI_GetNextValue
239 *
240 * Locate the next value in the current section
241 *
242 * PARAMS
243 * uf INI file to search, search starts at current location
244 * dwNameLen Location to store pointer to value name length
245 * lpValue Location to store pointer to the value
246 * dwValueLen Location to store pointer to value length
247 *
248 * RETURNS
249 * The value name, non NULL terminated
250 */
251 LPCWSTR UXINI_GetNextValue(PUXINI_FILE uf, DWORD *dwNameLen, LPCWSTR *lpValue, DWORD *dwValueLen)
252 {
253 LPCWSTR lpLine;
254 LPCWSTR lpLineEnd;
255 LPCWSTR name = NULL;
256 LPCWSTR value = NULL;
257 DWORD vallen = 0;
258 DWORD namelen = 0;
259 DWORD dwLen;
260 lpLine = UXINI_GetNextLine(uf, &dwLen);
261 if(!lpLine)
262 return NULL;
263 if(lpLine[0] == '[') {
264 UXINI_UnGetToLine(uf, lpLine);
265 return NULL;
266 }
267 lpLineEnd = lpLine + dwLen;
268
269 name = lpLine;
270 while(namelen < dwLen && *lpLine != '=') {
271 lpLine++;
272 namelen++;
273 }
274 if(*lpLine != '=') return NULL;
275 lpLine++;
276
277 /* Remove whitespace from end of name */
278 while(UXINI_isspace(name[namelen-1])) namelen--;
279 /* Remove whitespace from beginning of value */
280 while(UXINI_isspace(*lpLine) && lpLine < lpLineEnd) lpLine++;
281 value = lpLine;
282 vallen = dwLen-(value-name);
283
284 *dwNameLen = namelen;
285 *dwValueLen = vallen;
286 *lpValue = value;
287
288 return name;
289 }
290
291 /**********************************************************************
292 * UXINI_FindValue
293 *
294 * Locate a value by name
295 *
296 * PARAMS
297 * uf INI file to search, search starts at current location
298 * lpName Value name to locate
299 * lpValue Location to store pointer to the value
300 * dwValueLen Location to store pointer to value length
301 *
302 * RETURNS
303 * The value name, non NULL terminated
304 */
305 BOOL UXINI_FindValue(PUXINI_FILE uf, LPCWSTR lpName, LPCWSTR *lpValue, DWORD *dwValueLen)
306 {
307 LPCWSTR name;
308 DWORD namelen;
309
310 while((name = UXINI_GetNextValue(uf, &namelen, lpValue, dwValueLen))) {
311 if(CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, name, namelen, lpName, -1) == CSTR_EQUAL) {
312 return TRUE;
313 }
314 }
315 return FALSE;
316 }