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