xref: /reactos/dll/win32/uxtheme/uxini.c (revision c2c66aff)
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, *PUXINI_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  */
UXINI_LoadINI(HMODULE hTheme,LPCWSTR lpName)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  */
UXINI_CloseINI(PUXINI_FILE uf)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  */
UXINI_eof(PUXINI_FILE uf)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  */
UXINI_isspace(WCHAR c)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  */
UXINI_GetNextLine(PUXINI_FILE uf,DWORD * dwLen)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 
UXINI_UnGetToLine(PUXINI_FILE uf,LPCWSTR lpLine)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  */
UXINI_GetNextSection(PUXINI_FILE uf,DWORD * dwLen)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  */
UXINI_FindSection(PUXINI_FILE uf,LPCWSTR lpName)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  */
UXINI_GetNextValue(PUXINI_FILE uf,DWORD * dwNameLen,LPCWSTR * lpValue,DWORD * dwValueLen)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  */
UXINI_FindValue(PUXINI_FILE uf,LPCWSTR lpName,LPCWSTR * lpValue,DWORD * dwValueLen)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 }
292