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