2 * PROJECT: ReactOS Applications Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/rapps/parser.c
5 * PURPOSE: Parser functions
6 * PROGRAMMERS: Dmitry Chapyshev (dmitry@reactos.org)
11 typedef LONG NTSTATUS
;
13 typedef struct _UNICODE_STRING
{
17 } UNICODE_STRING
, *PUNICODE_STRING
;
19 void WINAPI
RtlInitUnicodeString(PUNICODE_STRING
,PCWSTR
);
20 NTSTATUS WINAPI
RtlUnicodeStringToInteger(const UNICODE_STRING
*,ULONG
,ULONG
*);
21 BOOLEAN WINAPI
RtlIsTextUnicode(LPCVOID
,INT
,INT
*);
23 static const char bom_utf8
[] = {0xEF,0xBB,0xBF};
32 typedef struct tagSECTIONKEY
35 struct tagSECTIONKEY
*next
;
39 typedef struct tagSECTION
41 struct tagSECTIONKEY
*key
;
42 struct tagSECTION
*next
;
55 #define N_CACHED_ITEMS 10
56 static ITEMS
*ItemsArray
[N_CACHED_ITEMS
] = {NULL
};
57 #define CurProfile (ItemsArray[0])
58 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
59 #define ParserIsSpace(c) (iswspace(c) || c == 0x1a)
64 memchrW(const WCHAR
*ptr
, WCHAR ch
, size_t n
)
67 for (end
= ptr
+ n
; ptr
< end
; ptr
++)
69 return (WCHAR
*)(ULONG_PTR
)ptr
;
75 *memrchrW(const WCHAR
*ptr
, WCHAR ch
, size_t n
)
79 for (end
= ptr
+ n
; ptr
< end
; ptr
++)
81 ret
= (WCHAR
*)(ULONG_PTR
)ptr
;
87 ParserCopyEntry(LPWSTR buffer
, LPCWSTR value
, int len
, BOOL strip_quote
)
93 if (strip_quote
&& ((*value
== '\'') || (*value
== '\"')))
95 if (value
[1] && (value
[wcslen(value
)-1] == *value
))
99 lstrcpynW(buffer
, value
, len
);
100 if (quote
&& (len
>= (int)wcslen(value
))) buffer
[wcslen(buffer
)-1] = '\0';
105 ParserByteSwapShortBuffer(WCHAR
* buffer
, int len
)
108 USHORT
* shortbuffer
= buffer
;
109 for (i
= 0; i
< len
; i
++)
110 shortbuffer
[i
] = (shortbuffer
[i
] >> 8) | (shortbuffer
[i
] << 8);
115 ParserWriteMarker(HANDLE hFile
, ENCODING encoding
)
117 DWORD dwBytesWritten
;
123 WriteFile(hFile
, bom_utf8
, sizeof(bom_utf8
), &dwBytesWritten
, NULL
);
126 case ENCODING_UTF16LE
:
128 WriteFile(hFile
, &bom
, sizeof(bom
), &dwBytesWritten
, NULL
);
131 case ENCODING_UTF16BE
:
133 WriteFile(hFile
, &bom
, sizeof(bom
), &dwBytesWritten
, NULL
);
140 ParserWriteLine(HANDLE hFile
, WCHAR
* szLine
, int len
, ENCODING encoding
)
143 int write_buffer_len
;
144 DWORD dwBytesWritten
;
149 write_buffer_len
= WideCharToMultiByte(CP_UTF8
, 0, szLine
, len
, NULL
, 0, NULL
, NULL
);
150 write_buffer
= HeapAlloc(GetProcessHeap(), 0, write_buffer_len
);
151 if (!write_buffer
) return;
152 len
= WideCharToMultiByte(CP_UTF8
, 0, szLine
, len
, write_buffer
, write_buffer_len
, NULL
, NULL
);
153 WriteFile(hFile
, write_buffer
, len
, &dwBytesWritten
, NULL
);
154 HeapFree(GetProcessHeap(), 0, write_buffer
);
157 case ENCODING_UTF16LE
:
158 WriteFile(hFile
, szLine
, len
* sizeof(WCHAR
), &dwBytesWritten
, NULL
);
161 case ENCODING_UTF16BE
:
162 ParserByteSwapShortBuffer(szLine
, len
);
163 WriteFile(hFile
, szLine
, len
* sizeof(WCHAR
), &dwBytesWritten
, NULL
);
170 ParserSave(HANDLE hFile
, const SECTION
*section
, ENCODING encoding
)
175 ParserWriteMarker(hFile
, encoding
);
177 for ( ; section
; section
= section
->next
)
181 if (section
->name
[0]) len
+= wcslen(section
->name
) + 4;
183 for (key
= section
->key
; key
; key
= key
->next
)
185 len
+= wcslen(key
->name
) + 2;
186 if (key
->value
) len
+= wcslen(key
->value
) + 1;
189 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
193 if (section
->name
[0])
196 wcscpy(p
, section
->name
);
203 for (key
= section
->key
; key
; key
= key
->next
)
205 wcscpy(p
, key
->name
);
210 wcscpy(p
, key
->value
);
216 ParserWriteLine(hFile
, buffer
, len
, encoding
);
217 HeapFree(GetProcessHeap(), 0, buffer
);
223 ParserFree(SECTION
*section
)
225 SECTION
*next_section
;
226 SECTIONKEY
*key
, *next_key
;
228 for ( ; section
; section
= next_section
)
230 for (key
= section
->key
; key
; key
= next_key
)
232 next_key
= key
->next
;
233 HeapFree(GetProcessHeap(), 0, key
->value
);
234 HeapFree(GetProcessHeap(), 0, key
);
236 next_section
= section
->next
;
237 HeapFree(GetProcessHeap(), 0, section
);
243 ParserDetectTextEncoding(const void * buffer
, int * len
)
245 INT flags
= IS_TEXT_UNICODE_SIGNATURE
|
246 IS_TEXT_UNICODE_REVERSE_SIGNATURE
|
247 IS_TEXT_UNICODE_ODD_LENGTH
;
249 if (*len
>= sizeof(bom_utf8
) && !memcmp(buffer
, bom_utf8
, sizeof(bom_utf8
)))
251 *len
= sizeof(bom_utf8
);
252 return ENCODING_UTF8
;
255 RtlIsTextUnicode((void *)buffer
, *len
, &flags
);
257 if (flags
& IS_TEXT_UNICODE_SIGNATURE
)
259 *len
= sizeof(WCHAR
);
260 return ENCODING_UTF16LE
;
263 if (flags
& IS_TEXT_UNICODE_REVERSE_SIGNATURE
)
265 *len
= sizeof(WCHAR
);
266 return ENCODING_UTF16BE
;
271 return ENCODING_UTF8
;
276 *ParserLoad(HANDLE hFile
, ENCODING
* pEncoding
)
278 void *buffer_base
, *pBuffer
;
280 const WCHAR
*szLineStart
, *szLineEnd
;
281 const WCHAR
*szValueStart
, *szEnd
, *next_line
;
283 SECTION
*section
, *first_section
;
284 SECTION
**next_section
;
285 SECTIONKEY
*key
, *prev_key
, **next_key
;
288 dwFileSize
= GetFileSize(hFile
, NULL
);
289 if (dwFileSize
== INVALID_FILE_SIZE
|| dwFileSize
== 0)
292 buffer_base
= HeapAlloc(GetProcessHeap(), 0 , dwFileSize
);
296 if (!ReadFile(hFile
, buffer_base
, dwFileSize
, &dwFileSize
, NULL
))
298 HeapFree(GetProcessHeap(), 0, buffer_base
);
303 *pEncoding
= ParserDetectTextEncoding(buffer_base
, &len
);
305 pBuffer
= (char *)buffer_base
+ len
;
311 len
= MultiByteToWideChar(CP_UTF8
, 0, pBuffer
, dwFileSize
, NULL
, 0);
312 szFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
315 HeapFree(GetProcessHeap(), 0, buffer_base
);
318 MultiByteToWideChar(CP_UTF8
, 0, pBuffer
, dwFileSize
, szFile
, len
);
319 szEnd
= szFile
+ len
;
322 case ENCODING_UTF16LE
:
324 szEnd
= (WCHAR
*)((char *)pBuffer
+ dwFileSize
);
327 case ENCODING_UTF16BE
:
329 szEnd
= (WCHAR
*)((char *)pBuffer
+ dwFileSize
);
330 ParserByteSwapShortBuffer(szFile
, dwFileSize
/ sizeof(WCHAR
));
334 HeapFree(GetProcessHeap(), 0, buffer_base
);
338 first_section
= HeapAlloc(GetProcessHeap(), 0, sizeof(*section
));
339 if (first_section
== NULL
)
341 if (szFile
!= pBuffer
)
342 HeapFree(GetProcessHeap(), 0, szFile
);
343 HeapFree(GetProcessHeap(), 0, buffer_base
);
347 first_section
->name
[0] = 0;
348 first_section
->key
= NULL
;
349 first_section
->next
= NULL
;
350 next_section
= &first_section
->next
;
351 next_key
= &first_section
->key
;
355 while (next_line
< szEnd
)
357 szLineStart
= next_line
;
358 next_line
= memchrW(szLineStart
, '\n', szEnd
- szLineStart
);
359 if (!next_line
) next_line
= memchrW(szLineStart
, '\r', szEnd
- szLineStart
);
360 if (!next_line
) next_line
= szEnd
;
362 szLineEnd
= next_line
;
366 while (szLineStart
< szLineEnd
&& ParserIsSpace(*szLineStart
)) szLineStart
++;
367 while ((szLineEnd
> szLineStart
) && ParserIsSpace(szLineEnd
[-1])) szLineEnd
--;
369 if (szLineStart
>= szLineEnd
)
372 if (*szLineStart
== '[')
374 const WCHAR
* szSectionEnd
;
375 if ((szSectionEnd
= memrchrW(szLineStart
, ']', szLineEnd
- szLineStart
)))
378 len
= (int)(szSectionEnd
- szLineStart
);
379 if (!(section
= HeapAlloc(GetProcessHeap(), 0, sizeof(*section
) + len
* sizeof(WCHAR
))))
381 memcpy(section
->name
, szLineStart
, len
* sizeof(WCHAR
));
382 section
->name
[len
] = '\0';
384 section
->next
= NULL
;
385 *next_section
= section
;
386 next_section
= §ion
->next
;
387 next_key
= §ion
->key
;
394 len
= szLineEnd
- szLineStart
;
395 if ((szValueStart
= memchrW(szLineStart
, '=', szLineEnd
- szLineStart
)) != NULL
)
397 const WCHAR
*szNameEnd
= szValueStart
;
398 while ((szNameEnd
> szLineStart
) && ParserIsSpace(szNameEnd
[-1])) szNameEnd
--;
399 len
= szNameEnd
- szLineStart
;
401 while (szValueStart
< szLineEnd
&& ParserIsSpace(*szValueStart
)) szValueStart
++;
404 if (len
|| !prev_key
|| *prev_key
->name
)
406 if (!(key
= HeapAlloc(GetProcessHeap(), 0, sizeof(*key
) + len
* sizeof(WCHAR
)))) break;
407 memcpy(key
->name
, szLineStart
, len
* sizeof(WCHAR
));
408 key
->name
[len
] = '\0';
411 len
= (int)(szLineEnd
- szValueStart
);
412 key
->value
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
413 memcpy(key
->value
, szValueStart
, len
* sizeof(WCHAR
));
414 key
->value
[len
] = '\0';
416 else key
->value
= NULL
;
420 next_key
= &key
->next
;
425 if (szFile
!= pBuffer
)
426 HeapFree(GetProcessHeap(), 0, szFile
);
427 HeapFree(GetProcessHeap(), 0, buffer_base
);
429 return first_section
;
434 *ParserFind(SECTION
**section
, LPCWSTR section_name
, LPCWSTR key_name
, BOOL create
, BOOL create_always
)
439 while (ParserIsSpace(*section_name
)) section_name
++;
441 p
= section_name
+ wcslen(section_name
) - 1;
445 while ((p
> section_name
) && ParserIsSpace(*p
)) p
--;
446 seclen
= p
- section_name
+ 1;
448 while (ParserIsSpace(*key_name
)) key_name
++;
450 p
= key_name
+ wcslen(key_name
) - 1;
454 while ((p
> key_name
) && ParserIsSpace(*p
)) p
--;
455 keylen
= p
- key_name
+ 1;
459 if (((*section
)->name
[0])
460 && (!(_wcsnicmp((*section
)->name
, section_name
, seclen
)))
461 && (((*section
)->name
)[seclen
] == '\0'))
463 SECTIONKEY
**key
= &(*section
)->key
;
469 if ((!(_wcsnicmp((*key
)->name
, key_name
, keylen
)))
470 && (((*key
)->name
)[keylen
] == '\0'))
477 if (!(*key
= HeapAlloc(GetProcessHeap(), 0, sizeof(SECTIONKEY
) + wcslen(key_name
) * sizeof(WCHAR
))))
479 wcscpy((*key
)->name
, key_name
);
480 (*key
)->value
= NULL
;
484 section
= &(*section
)->next
;
486 if (!create
) return NULL
;
487 *section
= HeapAlloc(GetProcessHeap(), 0, sizeof(SECTION
) + wcslen(section_name
) * sizeof(WCHAR
));
488 if(*section
== NULL
) return NULL
;
489 wcscpy((*section
)->name
, section_name
);
490 (*section
)->next
= NULL
;
491 if (!((*section
)->key
= HeapAlloc(GetProcessHeap(), 0,
492 sizeof(SECTIONKEY
) + wcslen(key_name
) * sizeof(WCHAR
))))
494 HeapFree(GetProcessHeap(), 0, *section
);
497 wcscpy((*section
)->key
->name
, key_name
);
498 (*section
)->key
->value
= NULL
;
499 (*section
)->key
->next
= NULL
;
500 return (*section
)->key
;
505 ParserFlushFile(void)
509 if (!CurProfile
) return FALSE
;
511 if (!CurProfile
->changed
) return TRUE
;
513 hFile
= CreateFileW(CurProfile
->filename
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
514 NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
516 if (hFile
== INVALID_HANDLE_VALUE
) return FALSE
;
518 ParserSave(hFile
, CurProfile
->section
, CurProfile
->encoding
);
521 CurProfile
->changed
= FALSE
;
527 ParserReleaseFile(void)
530 ParserFree(CurProfile
->section
);
531 HeapFree(GetProcessHeap(), 0, CurProfile
->filename
);
532 CurProfile
->changed
= FALSE
;
533 CurProfile
->section
= NULL
;
534 CurProfile
->filename
= NULL
;
535 CurProfile
->encoding
= ENCODING_UTF8
;
540 ParserOpen(LPCWSTR filename
, BOOL write_access
)
542 WCHAR szDir
[MAX_PATH
];
543 WCHAR buffer
[MAX_PATH
];
544 HANDLE hFile
= INVALID_HANDLE_VALUE
;
547 static const WCHAR wszSeparator
[] = L
"\\rapps\\";
550 for (i
= 0; i
< N_CACHED_ITEMS
; i
++)
552 ItemsArray
[i
] = HeapAlloc(GetProcessHeap(), 0, sizeof(ITEMS
));
553 if (ItemsArray
[i
] == NULL
) break;
554 ItemsArray
[i
]->changed
= FALSE
;
555 ItemsArray
[i
]->section
= NULL
;
556 ItemsArray
[i
]->filename
= NULL
;
557 ItemsArray
[i
]->encoding
= ENCODING_UTF8
;
560 GetCurrentDirectoryW(MAX_PATH
, szDir
);
562 wcscpy(buffer
, szDir
);
563 wcscat(buffer
, wszSeparator
);
564 wcscat(buffer
, filename
);
566 hFile
= CreateFileW(buffer
, GENERIC_READ
| (write_access
? GENERIC_WRITE
: 0),
567 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, NULL
,
568 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
570 if ((hFile
== INVALID_HANDLE_VALUE
) && (GetLastError() != ERROR_FILE_NOT_FOUND
))
575 for (i
= 0; i
< N_CACHED_ITEMS
; i
++)
577 if ((ItemsArray
[i
]->filename
&& !wcscmp(buffer
, ItemsArray
[i
]->filename
)))
582 tempProfile
= ItemsArray
[i
];
583 for (j
= i
; j
> 0; j
--)
584 ItemsArray
[j
] = ItemsArray
[j
- 1];
585 CurProfile
= tempProfile
;
587 if (hFile
!= INVALID_HANDLE_VALUE
)
598 if (i
== N_CACHED_ITEMS
)
600 tempProfile
= ItemsArray
[N_CACHED_ITEMS
- 1];
601 for (i
= N_CACHED_ITEMS
- 1; i
> 0; i
--)
602 ItemsArray
[i
] = ItemsArray
[i
- 1];
603 CurProfile
= tempProfile
;
606 if (CurProfile
->filename
) ParserReleaseFile();
608 CurProfile
->filename
= HeapAlloc(GetProcessHeap(), 0, (wcslen(buffer
) + 1) * sizeof(WCHAR
));
609 if (CurProfile
->filename
== NULL
)
612 wcscpy(CurProfile
->filename
, buffer
);
614 if (hFile
!= INVALID_HANDLE_VALUE
)
616 CurProfile
->section
= ParserLoad(hFile
, &CurProfile
->encoding
);
624 ParserGetSection(SECTION
*section
, LPCWSTR section_name
, LPWSTR buffer
, UINT len
, BOOL return_values
)
633 if (section
->name
[0] && !_wcsicmp(section
->name
, section_name
))
636 for (key
= section
->key
; key
; key
= key
->next
)
639 if (!*key
->name
) continue; /* Skip empty lines */
640 if (IS_ENTRY_COMMENT(key
->name
)) continue; /* Skip comments */
641 if (!return_values
&& !key
->value
) continue; /* Skip lines w.o. '=' */
643 ParserCopyEntry(buffer
, key
->name
, len
- 1, 0);
644 len
-= wcslen(buffer
) + 1;
645 buffer
+= wcslen(buffer
) + 1;
648 if (return_values
&& key
->value
)
651 ParserCopyEntry(buffer
, key
->value
, len
- 1, 0);
652 len
-= wcslen(buffer
) + 1;
653 buffer
+= wcslen(buffer
) + 1;
664 section
= section
->next
;
666 buffer
[0] = buffer
[1] = '\0';
672 ParserInternalGetString(LPCWSTR section
, LPCWSTR key_name
, LPWSTR buffer
, UINT len
)
674 SECTIONKEY
*key
= NULL
;
675 static const WCHAR empty_strW
[] = { 0 };
677 if (!buffer
|| !len
) return 0;
683 ParserCopyEntry(buffer
, empty_strW
, len
, TRUE
);
684 return wcslen(buffer
);
686 key
= ParserFind(&CurProfile
->section
, section
, key_name
, FALSE
, FALSE
);
687 ParserCopyEntry(buffer
, (key
&& key
->value
) ? key
->value
: empty_strW
,
689 return wcslen(buffer
);
692 if (section
&& section
[0])
694 INT ret
= ParserGetSection(CurProfile
->section
, section
, buffer
, len
, FALSE
);
697 ParserCopyEntry(buffer
, empty_strW
, len
, TRUE
);
698 ret
= wcslen(buffer
);
708 ParserGetString(LPCWSTR Section
, LPCWSTR ValueName
, LPWSTR Buffer
, UINT Len
, LPCWSTR FileName
)
710 if (Section
== NULL
) return 0;
712 if (ParserOpen(FileName
, FALSE
))
713 return ParserInternalGetString(Section
, ValueName
, Buffer
, Len
);
719 ParserGetInt(LPCWSTR Section
, LPCWSTR ValueName
, LPCWSTR FileName
)
722 UNICODE_STRING BufferW
;
725 if (!ParserGetString(Section
,
728 sizeof(Buffer
) / sizeof(WCHAR
),
732 if (!Buffer
[0]) return -1;
734 RtlInitUnicodeString(&BufferW
, Buffer
);
735 RtlUnicodeStringToInteger(&BufferW
, 0, &Result
);