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
)
182 if (section
->name
[0]) len
+= wcslen(section
->name
) + 4;
184 for (key
= section
->key
; key
; key
= key
->next
)
186 len
+= wcslen(key
->name
) + 2;
187 if (key
->value
) len
+= wcslen(key
->value
) + 1;
190 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
195 if (section
->name
[0])
197 StringCchPrintfExW(p
, remaining
, &p
, &remaining
, 0,
202 for (key
= section
->key
; key
; key
= key
->next
)
206 StringCchPrintfExW(p
, remaining
, &p
, &remaining
, 0,
208 key
->name
, key
->value
);
212 StringCchPrintfExW(p
, remaining
, &p
, &remaining
, 0,
217 ParserWriteLine(hFile
, buffer
, len
, encoding
);
218 HeapFree(GetProcessHeap(), 0, buffer
);
224 ParserFree(SECTION
*section
)
226 SECTION
*next_section
;
227 SECTIONKEY
*key
, *next_key
;
229 for ( ; section
; section
= next_section
)
231 for (key
= section
->key
; key
; key
= next_key
)
233 next_key
= key
->next
;
234 HeapFree(GetProcessHeap(), 0, key
->value
);
235 HeapFree(GetProcessHeap(), 0, key
);
237 next_section
= section
->next
;
238 HeapFree(GetProcessHeap(), 0, section
);
244 ParserDetectTextEncoding(const void * buffer
, int * len
)
246 INT flags
= IS_TEXT_UNICODE_SIGNATURE
|
247 IS_TEXT_UNICODE_REVERSE_SIGNATURE
|
248 IS_TEXT_UNICODE_ODD_LENGTH
;
250 if (*len
>= sizeof(bom_utf8
) && !memcmp(buffer
, bom_utf8
, sizeof(bom_utf8
)))
252 *len
= sizeof(bom_utf8
);
253 return ENCODING_UTF8
;
256 RtlIsTextUnicode((void *)buffer
, *len
, &flags
);
258 if (flags
& IS_TEXT_UNICODE_SIGNATURE
)
260 *len
= sizeof(WCHAR
);
261 return ENCODING_UTF16LE
;
264 if (flags
& IS_TEXT_UNICODE_REVERSE_SIGNATURE
)
266 *len
= sizeof(WCHAR
);
267 return ENCODING_UTF16BE
;
272 return ENCODING_UTF8
;
277 *ParserLoad(HANDLE hFile
, ENCODING
* pEncoding
)
279 void *buffer_base
, *pBuffer
;
281 const WCHAR
*szLineStart
, *szLineEnd
;
282 const WCHAR
*szValueStart
, *szEnd
, *next_line
;
284 SECTION
*section
, *first_section
;
285 SECTION
**next_section
;
286 SECTIONKEY
*key
, *prev_key
, **next_key
;
289 dwFileSize
= GetFileSize(hFile
, NULL
);
290 if (dwFileSize
== INVALID_FILE_SIZE
|| dwFileSize
== 0)
293 buffer_base
= HeapAlloc(GetProcessHeap(), 0 , dwFileSize
);
297 if (!ReadFile(hFile
, buffer_base
, dwFileSize
, &dwFileSize
, NULL
))
299 HeapFree(GetProcessHeap(), 0, buffer_base
);
304 *pEncoding
= ParserDetectTextEncoding(buffer_base
, &len
);
306 pBuffer
= (char *)buffer_base
+ len
;
312 len
= MultiByteToWideChar(CP_UTF8
, 0, pBuffer
, dwFileSize
, NULL
, 0);
313 szFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
316 HeapFree(GetProcessHeap(), 0, buffer_base
);
319 MultiByteToWideChar(CP_UTF8
, 0, pBuffer
, dwFileSize
, szFile
, len
);
320 szEnd
= szFile
+ len
;
323 case ENCODING_UTF16LE
:
325 szEnd
= (WCHAR
*)((char *)pBuffer
+ dwFileSize
);
328 case ENCODING_UTF16BE
:
330 szEnd
= (WCHAR
*)((char *)pBuffer
+ dwFileSize
);
331 ParserByteSwapShortBuffer(szFile
, dwFileSize
/ sizeof(WCHAR
));
335 HeapFree(GetProcessHeap(), 0, buffer_base
);
339 first_section
= HeapAlloc(GetProcessHeap(), 0, sizeof(*section
));
340 if (first_section
== NULL
)
342 if (szFile
!= pBuffer
)
343 HeapFree(GetProcessHeap(), 0, szFile
);
344 HeapFree(GetProcessHeap(), 0, buffer_base
);
348 first_section
->name
[0] = 0;
349 first_section
->key
= NULL
;
350 first_section
->next
= NULL
;
351 next_section
= &first_section
->next
;
352 next_key
= &first_section
->key
;
356 while (next_line
< szEnd
)
358 szLineStart
= next_line
;
359 next_line
= memchrW(szLineStart
, '\n', szEnd
- szLineStart
);
360 if (!next_line
) next_line
= memchrW(szLineStart
, '\r', szEnd
- szLineStart
);
361 if (!next_line
) next_line
= szEnd
;
363 szLineEnd
= next_line
;
367 while (szLineStart
< szLineEnd
&& ParserIsSpace(*szLineStart
)) szLineStart
++;
368 while ((szLineEnd
> szLineStart
) && ParserIsSpace(szLineEnd
[-1])) szLineEnd
--;
370 if (szLineStart
>= szLineEnd
)
373 if (*szLineStart
== '[')
375 const WCHAR
* szSectionEnd
;
376 if ((szSectionEnd
= memrchrW(szLineStart
, ']', szLineEnd
- szLineStart
)))
379 len
= (int)(szSectionEnd
- szLineStart
);
380 if (!(section
= HeapAlloc(GetProcessHeap(), 0, sizeof(*section
) + len
* sizeof(WCHAR
))))
382 memcpy(section
->name
, szLineStart
, len
* sizeof(WCHAR
));
383 section
->name
[len
] = '\0';
385 section
->next
= NULL
;
386 *next_section
= section
;
387 next_section
= §ion
->next
;
388 next_key
= §ion
->key
;
395 len
= szLineEnd
- szLineStart
;
396 if ((szValueStart
= memchrW(szLineStart
, '=', szLineEnd
- szLineStart
)) != NULL
)
398 const WCHAR
*szNameEnd
= szValueStart
;
399 while ((szNameEnd
> szLineStart
) && ParserIsSpace(szNameEnd
[-1])) szNameEnd
--;
400 len
= szNameEnd
- szLineStart
;
402 while (szValueStart
< szLineEnd
&& ParserIsSpace(*szValueStart
)) szValueStart
++;
405 if (len
|| !prev_key
|| *prev_key
->name
)
407 if (!(key
= HeapAlloc(GetProcessHeap(), 0, sizeof(*key
) + len
* sizeof(WCHAR
)))) break;
408 memcpy(key
->name
, szLineStart
, len
* sizeof(WCHAR
));
409 key
->name
[len
] = '\0';
412 len
= (int)(szLineEnd
- szValueStart
);
413 key
->value
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
414 memcpy(key
->value
, szValueStart
, len
* sizeof(WCHAR
));
415 key
->value
[len
] = '\0';
417 else key
->value
= NULL
;
421 next_key
= &key
->next
;
426 if (szFile
!= pBuffer
)
427 HeapFree(GetProcessHeap(), 0, szFile
);
428 HeapFree(GetProcessHeap(), 0, buffer_base
);
430 return first_section
;
435 *ParserFind(SECTION
**section
, LPCWSTR section_name
, LPCWSTR key_name
, BOOL create
, BOOL create_always
)
441 while (ParserIsSpace(*section_name
)) section_name
++;
443 p
= section_name
+ wcslen(section_name
) - 1;
447 while ((p
> section_name
) && ParserIsSpace(*p
)) p
--;
448 seclen
= p
- section_name
+ 1;
450 while (ParserIsSpace(*key_name
)) key_name
++;
452 p
= key_name
+ wcslen(key_name
) - 1;
456 while ((p
> key_name
) && ParserIsSpace(*p
)) p
--;
457 keylen
= p
- key_name
+ 1;
461 if (((*section
)->name
[0])
462 && (!(_wcsnicmp((*section
)->name
, section_name
, seclen
)))
463 && (((*section
)->name
)[seclen
] == '\0'))
465 SECTIONKEY
**key
= &(*section
)->key
;
471 if ((!(_wcsnicmp((*key
)->name
, key_name
, keylen
)))
472 && (((*key
)->name
)[keylen
] == '\0'))
479 cch
= wcslen(key_name
) + 1;
480 if (!(*key
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(SECTIONKEY
, name
) + cch
* sizeof(WCHAR
))))
482 StringCchCopyW((*key
)->name
, cch
, key_name
);
483 (*key
)->value
= NULL
;
487 section
= &(*section
)->next
;
489 if (!create
) return NULL
;
490 cch
= wcslen(section_name
) + 1;
491 *section
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(SECTION
, name
) + cch
* sizeof(WCHAR
));
492 if (*section
== NULL
) return NULL
;
493 StringCchCopyW((*section
)->name
, cch
, section_name
);
494 (*section
)->next
= NULL
;
495 cch
= wcslen(key_name
) + 1;
496 if (!((*section
)->key
= HeapAlloc(GetProcessHeap(), 0,
497 FIELD_OFFSET(SECTIONKEY
, name
) + cch
* sizeof(WCHAR
))))
499 HeapFree(GetProcessHeap(), 0, *section
);
502 StringCchCopyW((*section
)->key
->name
, cch
, key_name
);
503 (*section
)->key
->value
= NULL
;
504 (*section
)->key
->next
= NULL
;
505 return (*section
)->key
;
510 ParserFlushFile(void)
514 if (!CurProfile
) return FALSE
;
516 if (!CurProfile
->changed
) return TRUE
;
518 hFile
= CreateFileW(CurProfile
->filename
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
519 NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
521 if (hFile
== INVALID_HANDLE_VALUE
) return FALSE
;
523 ParserSave(hFile
, CurProfile
->section
, CurProfile
->encoding
);
526 CurProfile
->changed
= FALSE
;
532 ParserReleaseFile(void)
535 ParserFree(CurProfile
->section
);
536 HeapFree(GetProcessHeap(), 0, CurProfile
->filename
);
537 CurProfile
->changed
= FALSE
;
538 CurProfile
->section
= NULL
;
539 CurProfile
->filename
= NULL
;
540 CurProfile
->encoding
= ENCODING_UTF8
;
545 ParserOpen(LPCWSTR filename
, BOOL write_access
)
547 WCHAR szDir
[MAX_PATH
];
548 WCHAR buffer
[MAX_PATH
];
550 HANDLE hFile
= INVALID_HANDLE_VALUE
;
555 for (i
= 0; i
< N_CACHED_ITEMS
; i
++)
557 ItemsArray
[i
] = HeapAlloc(GetProcessHeap(), 0, sizeof(ITEMS
));
558 if (ItemsArray
[i
] == NULL
) break;
559 ItemsArray
[i
]->changed
= FALSE
;
560 ItemsArray
[i
]->section
= NULL
;
561 ItemsArray
[i
]->filename
= NULL
;
562 ItemsArray
[i
]->encoding
= ENCODING_UTF8
;
565 if (!GetStorageDirectory(szDir
, sizeof(szDir
) / sizeof(szDir
[0])))
568 if (FAILED(StringCbPrintfW(buffer
, sizeof(buffer
),
575 hFile
= CreateFileW(buffer
, GENERIC_READ
| (write_access
? GENERIC_WRITE
: 0),
576 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, NULL
,
577 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
579 if ((hFile
== INVALID_HANDLE_VALUE
) && (GetLastError() != ERROR_FILE_NOT_FOUND
))
584 for (i
= 0; i
< N_CACHED_ITEMS
; i
++)
586 if ((ItemsArray
[i
]->filename
&& !wcscmp(buffer
, ItemsArray
[i
]->filename
)))
591 tempProfile
= ItemsArray
[i
];
592 for (j
= i
; j
> 0; j
--)
593 ItemsArray
[j
] = ItemsArray
[j
- 1];
594 CurProfile
= tempProfile
;
596 if (hFile
!= INVALID_HANDLE_VALUE
)
607 if (i
== N_CACHED_ITEMS
)
609 tempProfile
= ItemsArray
[N_CACHED_ITEMS
- 1];
610 for (i
= N_CACHED_ITEMS
- 1; i
> 0; i
--)
611 ItemsArray
[i
] = ItemsArray
[i
- 1];
612 CurProfile
= tempProfile
;
615 if (CurProfile
->filename
) ParserReleaseFile();
617 cch
= wcslen(buffer
) + 1;
618 CurProfile
->filename
= HeapAlloc(GetProcessHeap(), 0, cch
* sizeof(WCHAR
));
619 if (CurProfile
->filename
== NULL
)
621 if (hFile
!= INVALID_HANDLE_VALUE
) CloseHandle(hFile
);
625 StringCchCopyW(CurProfile
->filename
, cch
, buffer
);
627 if (hFile
!= INVALID_HANDLE_VALUE
)
629 CurProfile
->section
= ParserLoad(hFile
, &CurProfile
->encoding
);
637 ParserGetSection(SECTION
*section
, LPCWSTR section_name
, LPWSTR buffer
, UINT len
, BOOL return_values
)
646 if (section
->name
[0] && !_wcsicmp(section
->name
, section_name
))
649 for (key
= section
->key
; key
; key
= key
->next
)
652 if (!*key
->name
) continue; /* Skip empty lines */
653 if (IS_ENTRY_COMMENT(key
->name
)) continue; /* Skip comments */
654 if (!return_values
&& !key
->value
) continue; /* Skip lines w.o. '=' */
656 ParserCopyEntry(buffer
, key
->name
, len
- 1, 0);
657 len
-= wcslen(buffer
) + 1;
658 buffer
+= wcslen(buffer
) + 1;
661 if (return_values
&& key
->value
)
664 ParserCopyEntry(buffer
, key
->value
, len
- 1, 0);
665 len
-= wcslen(buffer
) + 1;
666 buffer
+= wcslen(buffer
) + 1;
677 section
= section
->next
;
679 buffer
[0] = buffer
[1] = '\0';
685 ParserInternalGetString(LPCWSTR section
, LPCWSTR key_name
, LPWSTR buffer
, UINT len
)
687 SECTIONKEY
*key
= NULL
;
688 static const WCHAR empty_strW
[] = { 0 };
690 if (!buffer
|| !len
) return 0;
696 ParserCopyEntry(buffer
, empty_strW
, len
, TRUE
);
697 return wcslen(buffer
);
699 key
= ParserFind(&CurProfile
->section
, section
, key_name
, FALSE
, FALSE
);
700 ParserCopyEntry(buffer
, (key
&& key
->value
) ? key
->value
: empty_strW
,
702 return wcslen(buffer
);
705 if (section
&& section
[0])
707 INT ret
= ParserGetSection(CurProfile
->section
, section
, buffer
, len
, FALSE
);
710 ParserCopyEntry(buffer
, empty_strW
, len
, TRUE
);
711 ret
= wcslen(buffer
);
721 ParserGetString(LPCWSTR Section
, LPCWSTR ValueName
, LPWSTR Buffer
, UINT Len
, LPCWSTR FileName
)
723 if (Section
== NULL
) return 0;
725 if (ParserOpen(FileName
, FALSE
))
726 return ParserInternalGetString(Section
, ValueName
, Buffer
, Len
);
732 ParserGetInt(LPCWSTR Section
, LPCWSTR ValueName
, LPCWSTR FileName
)
735 UNICODE_STRING BufferW
;
738 if (!ParserGetString(Section
,
741 sizeof(Buffer
) / sizeof(WCHAR
),
745 if (!Buffer
[0]) return -1;
747 RtlInitUnicodeString(&BufferW
, Buffer
);
748 RtlUnicodeStringToInteger(&BufferW
, 0, &Result
);