[CMAKE]
[reactos.git] / base / applications / rapps / parser.c
1 /*
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)
7 */
8
9 #include "rapps.h"
10
11 typedef LONG NTSTATUS;
12
13 typedef struct _UNICODE_STRING {
14 USHORT Length;
15 USHORT MaximumLength;
16 PWSTR Buffer;
17 } UNICODE_STRING, *PUNICODE_STRING;
18
19 void WINAPI RtlInitUnicodeString(PUNICODE_STRING,PCWSTR);
20 NTSTATUS WINAPI RtlUnicodeStringToInteger(const UNICODE_STRING*,ULONG,ULONG*);
21 BOOLEAN WINAPI RtlIsTextUnicode(LPCVOID,INT,INT*);
22
23 static const char bom_utf8[] = {0xEF,0xBB,0xBF};
24
25 typedef enum
26 {
27 ENCODING_UTF8 = 1,
28 ENCODING_UTF16LE,
29 ENCODING_UTF16BE
30 } ENCODING;
31
32 typedef struct tagSECTIONKEY
33 {
34 WCHAR *value;
35 struct tagSECTIONKEY *next;
36 WCHAR name[1];
37 } SECTIONKEY;
38
39 typedef struct tagSECTION
40 {
41 struct tagSECTIONKEY *key;
42 struct tagSECTION *next;
43 WCHAR name[1];
44 } SECTION;
45
46 typedef struct
47 {
48 BOOL changed;
49 SECTION *section;
50 WCHAR *filename;
51 ENCODING encoding;
52 } ITEMS;
53
54
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)
60
61
62 static
63 WCHAR*
64 memchrW(const WCHAR *ptr, WCHAR ch, size_t n)
65 {
66 const WCHAR *end;
67 for (end = ptr + n; ptr < end; ptr++)
68 if (*ptr == ch)
69 return (WCHAR *)(ULONG_PTR)ptr;
70 return NULL;
71 }
72
73 static
74 WCHAR
75 *memrchrW(const WCHAR *ptr, WCHAR ch, size_t n)
76 {
77 const WCHAR *end;
78 WCHAR *ret = NULL;
79 for (end = ptr + n; ptr < end; ptr++)
80 if (*ptr == ch)
81 ret = (WCHAR *)(ULONG_PTR)ptr;
82 return ret;
83 }
84
85 static
86 void
87 ParserCopyEntry(LPWSTR buffer, LPCWSTR value, int len, BOOL strip_quote)
88 {
89 WCHAR quote = '\0';
90
91 if (!buffer) return;
92
93 if (strip_quote && ((*value == '\'') || (*value == '\"')))
94 {
95 if (value[1] && (value[wcslen(value)-1] == *value))
96 quote = *value++;
97 }
98
99 lstrcpynW(buffer, value, len);
100 if (quote && (len >= (int)wcslen(value))) buffer[wcslen(buffer)-1] = '\0';
101 }
102
103 static
104 void
105 ParserByteSwapShortBuffer(WCHAR * buffer, int len)
106 {
107 int i;
108 USHORT * shortbuffer = buffer;
109 for (i = 0; i < len; i++)
110 shortbuffer[i] = (shortbuffer[i] >> 8) | (shortbuffer[i] << 8);
111 }
112
113 static
114 void
115 ParserWriteMarker(HANDLE hFile, ENCODING encoding)
116 {
117 DWORD dwBytesWritten;
118 WCHAR bom;
119
120 switch (encoding)
121 {
122 case ENCODING_UTF8:
123 WriteFile(hFile, bom_utf8, sizeof(bom_utf8), &dwBytesWritten, NULL);
124 break;
125
126 case ENCODING_UTF16LE:
127 bom = 0xFEFF;
128 WriteFile(hFile, &bom, sizeof(bom), &dwBytesWritten, NULL);
129 break;
130
131 case ENCODING_UTF16BE:
132 bom = 0xFFFE;
133 WriteFile(hFile, &bom, sizeof(bom), &dwBytesWritten, NULL);
134 break;
135 }
136 }
137
138 static
139 void
140 ParserWriteLine(HANDLE hFile, WCHAR * szLine, int len, ENCODING encoding)
141 {
142 char * write_buffer;
143 int write_buffer_len;
144 DWORD dwBytesWritten;
145
146 switch (encoding)
147 {
148 case ENCODING_UTF8:
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);
155 break;
156
157 case ENCODING_UTF16LE:
158 WriteFile(hFile, szLine, len * sizeof(WCHAR), &dwBytesWritten, NULL);
159 break;
160
161 case ENCODING_UTF16BE:
162 ParserByteSwapShortBuffer(szLine, len);
163 WriteFile(hFile, szLine, len * sizeof(WCHAR), &dwBytesWritten, NULL);
164 break;
165 }
166 }
167
168 static
169 void
170 ParserSave(HANDLE hFile, const SECTION *section, ENCODING encoding)
171 {
172 SECTIONKEY *key;
173 WCHAR *buffer, *p;
174
175 ParserWriteMarker(hFile, encoding);
176
177 for ( ; section; section = section->next)
178 {
179 int len = 0;
180
181 if (section->name[0]) len += wcslen(section->name) + 4;
182
183 for (key = section->key; key; key = key->next)
184 {
185 len += wcslen(key->name) + 2;
186 if (key->value) len += wcslen(key->value) + 1;
187 }
188
189 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
190 if (!buffer) return;
191
192 p = buffer;
193 if (section->name[0])
194 {
195 *p++ = '[';
196 wcscpy(p, section->name);
197 p += wcslen(p);
198 *p++ = ']';
199 *p++ = '\r';
200 *p++ = '\n';
201 }
202
203 for (key = section->key; key; key = key->next)
204 {
205 wcscpy(p, key->name);
206 p += wcslen(p);
207 if (key->value)
208 {
209 *p++ = '=';
210 wcscpy(p, key->value);
211 p += wcslen(p);
212 }
213 *p++ = '\r';
214 *p++ = '\n';
215 }
216 ParserWriteLine(hFile, buffer, len, encoding);
217 HeapFree(GetProcessHeap(), 0, buffer);
218 }
219 }
220
221 static
222 void
223 ParserFree(SECTION *section)
224 {
225 SECTION *next_section;
226 SECTIONKEY *key, *next_key;
227
228 for ( ; section; section = next_section)
229 {
230 for (key = section->key; key; key = next_key)
231 {
232 next_key = key->next;
233 HeapFree(GetProcessHeap(), 0, key->value);
234 HeapFree(GetProcessHeap(), 0, key);
235 }
236 next_section = section->next;
237 HeapFree(GetProcessHeap(), 0, section);
238 }
239 }
240
241 static
242 ENCODING
243 ParserDetectTextEncoding(const void * buffer, int * len)
244 {
245 INT flags = IS_TEXT_UNICODE_SIGNATURE |
246 IS_TEXT_UNICODE_REVERSE_SIGNATURE |
247 IS_TEXT_UNICODE_ODD_LENGTH;
248
249 if (*len >= sizeof(bom_utf8) && !memcmp(buffer, bom_utf8, sizeof(bom_utf8)))
250 {
251 *len = sizeof(bom_utf8);
252 return ENCODING_UTF8;
253 }
254
255 RtlIsTextUnicode((void *)buffer, *len, &flags);
256
257 if (flags & IS_TEXT_UNICODE_SIGNATURE)
258 {
259 *len = sizeof(WCHAR);
260 return ENCODING_UTF16LE;
261 }
262
263 if (flags & IS_TEXT_UNICODE_REVERSE_SIGNATURE)
264 {
265 *len = sizeof(WCHAR);
266 return ENCODING_UTF16BE;
267 }
268
269 *len = 0;
270
271 return ENCODING_UTF8;
272 }
273
274 static
275 SECTION
276 *ParserLoad(HANDLE hFile, ENCODING * pEncoding)
277 {
278 void *buffer_base, *pBuffer;
279 WCHAR * szFile;
280 const WCHAR *szLineStart, *szLineEnd;
281 const WCHAR *szValueStart, *szEnd, *next_line;
282 int line = 0, len;
283 SECTION *section, *first_section;
284 SECTION **next_section;
285 SECTIONKEY *key, *prev_key, **next_key;
286 DWORD dwFileSize;
287
288 dwFileSize = GetFileSize(hFile, NULL);
289 if (dwFileSize == INVALID_FILE_SIZE || dwFileSize == 0)
290 return NULL;
291
292 buffer_base = HeapAlloc(GetProcessHeap(), 0 , dwFileSize);
293 if (!buffer_base)
294 return NULL;
295
296 if (!ReadFile(hFile, buffer_base, dwFileSize, &dwFileSize, NULL))
297 {
298 HeapFree(GetProcessHeap(), 0, buffer_base);
299 return NULL;
300 }
301
302 len = dwFileSize;
303 *pEncoding = ParserDetectTextEncoding(buffer_base, &len);
304
305 pBuffer = (char *)buffer_base + len;
306 dwFileSize -= len;
307
308 switch (*pEncoding)
309 {
310 case ENCODING_UTF8:
311 len = MultiByteToWideChar(CP_UTF8, 0, pBuffer, dwFileSize, NULL, 0);
312 szFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
313 if (!szFile)
314 {
315 HeapFree(GetProcessHeap(), 0, buffer_base);
316 return NULL;
317 }
318 MultiByteToWideChar(CP_UTF8, 0, pBuffer, dwFileSize, szFile, len);
319 szEnd = szFile + len;
320 break;
321
322 case ENCODING_UTF16LE:
323 szFile = pBuffer;
324 szEnd = (WCHAR *)((char *)pBuffer + dwFileSize);
325 break;
326
327 case ENCODING_UTF16BE:
328 szFile = pBuffer;
329 szEnd = (WCHAR *)((char *)pBuffer + dwFileSize);
330 ParserByteSwapShortBuffer(szFile, dwFileSize / sizeof(WCHAR));
331 break;
332
333 default:
334 HeapFree(GetProcessHeap(), 0, buffer_base);
335 return NULL;
336 }
337
338 first_section = HeapAlloc(GetProcessHeap(), 0, sizeof(*section));
339 if (first_section == NULL)
340 {
341 if (szFile != pBuffer)
342 HeapFree(GetProcessHeap(), 0, szFile);
343 HeapFree(GetProcessHeap(), 0, buffer_base);
344 return NULL;
345 }
346
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;
352 prev_key = NULL;
353 next_line = szFile;
354
355 while (next_line < szEnd)
356 {
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;
361 else next_line++;
362 szLineEnd = next_line;
363
364 line++;
365
366 while (szLineStart < szLineEnd && ParserIsSpace(*szLineStart)) szLineStart++;
367 while ((szLineEnd > szLineStart) && ParserIsSpace(szLineEnd[-1])) szLineEnd--;
368
369 if (szLineStart >= szLineEnd)
370 continue;
371
372 if (*szLineStart == '[')
373 {
374 const WCHAR * szSectionEnd;
375 if ((szSectionEnd = memrchrW(szLineStart, ']', szLineEnd - szLineStart)))
376 {
377 szLineStart++;
378 len = (int)(szSectionEnd - szLineStart);
379 if (!(section = HeapAlloc(GetProcessHeap(), 0, sizeof(*section) + len * sizeof(WCHAR))))
380 break;
381 memcpy(section->name, szLineStart, len * sizeof(WCHAR));
382 section->name[len] = '\0';
383 section->key = NULL;
384 section->next = NULL;
385 *next_section = section;
386 next_section = &section->next;
387 next_key = &section->key;
388 prev_key = NULL;
389
390 continue;
391 }
392 }
393
394 len = szLineEnd - szLineStart;
395 if ((szValueStart = memchrW(szLineStart, '=', szLineEnd - szLineStart)) != NULL)
396 {
397 const WCHAR *szNameEnd = szValueStart;
398 while ((szNameEnd > szLineStart) && ParserIsSpace(szNameEnd[-1])) szNameEnd--;
399 len = szNameEnd - szLineStart;
400 szValueStart++;
401 while (szValueStart < szLineEnd && ParserIsSpace(*szValueStart)) szValueStart++;
402 }
403
404 if (len || !prev_key || *prev_key->name)
405 {
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';
409 if (szValueStart)
410 {
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';
415 }
416 else key->value = NULL;
417
418 key->next = NULL;
419 *next_key = key;
420 next_key = &key->next;
421 prev_key = key;
422 }
423 }
424
425 if (szFile != pBuffer)
426 HeapFree(GetProcessHeap(), 0, szFile);
427 HeapFree(GetProcessHeap(), 0, buffer_base);
428
429 return first_section;
430 }
431
432 static
433 SECTIONKEY
434 *ParserFind(SECTION **section, LPCWSTR section_name, LPCWSTR key_name, BOOL create, BOOL create_always)
435 {
436 LPCWSTR p;
437 int seclen, keylen;
438
439 while (ParserIsSpace(*section_name)) section_name++;
440 if (*section_name)
441 p = section_name + wcslen(section_name) - 1;
442 else
443 p = section_name;
444
445 while ((p > section_name) && ParserIsSpace(*p)) p--;
446 seclen = p - section_name + 1;
447
448 while (ParserIsSpace(*key_name)) key_name++;
449 if (*key_name)
450 p = key_name + wcslen(key_name) - 1;
451 else
452 p = key_name;
453
454 while ((p > key_name) && ParserIsSpace(*p)) p--;
455 keylen = p - key_name + 1;
456
457 while (*section)
458 {
459 if (((*section)->name[0])
460 && (!(_wcsnicmp((*section)->name, section_name, seclen)))
461 && (((*section)->name)[seclen] == '\0'))
462 {
463 SECTIONKEY **key = &(*section)->key;
464
465 while (*key)
466 {
467 if(!create_always)
468 {
469 if ((!(_wcsnicmp((*key)->name, key_name, keylen)))
470 && (((*key)->name)[keylen] == '\0'))
471 return *key;
472 }
473 key = &(*key)->next;
474 }
475 if (!create)
476 return NULL;
477 if (!(*key = HeapAlloc(GetProcessHeap(), 0, sizeof(SECTIONKEY) + wcslen(key_name) * sizeof(WCHAR))))
478 return NULL;
479 wcscpy((*key)->name, key_name);
480 (*key)->value = NULL;
481 (*key)->next = NULL;
482 return *key;
483 }
484 section = &(*section)->next;
485 }
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))))
493 {
494 HeapFree(GetProcessHeap(), 0, *section);
495 return NULL;
496 }
497 wcscpy((*section)->key->name, key_name);
498 (*section)->key->value = NULL;
499 (*section)->key->next = NULL;
500 return (*section)->key;
501 }
502
503 static
504 BOOL
505 ParserFlushFile(void)
506 {
507 HANDLE hFile = NULL;
508
509 if (!CurProfile) return FALSE;
510
511 if (!CurProfile->changed) return TRUE;
512
513 hFile = CreateFileW(CurProfile->filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
514 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
515
516 if (hFile == INVALID_HANDLE_VALUE) return FALSE;
517
518 ParserSave(hFile, CurProfile->section, CurProfile->encoding);
519
520 CloseHandle(hFile);
521 CurProfile->changed = FALSE;
522 return TRUE;
523 }
524
525 static
526 void
527 ParserReleaseFile(void)
528 {
529 ParserFlushFile();
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;
536 }
537
538 static
539 BOOL
540 ParserOpen(LPCWSTR filename, BOOL write_access)
541 {
542 WCHAR szDir[MAX_PATH];
543 WCHAR buffer[MAX_PATH];
544 HANDLE hFile = INVALID_HANDLE_VALUE;
545 int i, j;
546 ITEMS *tempProfile;
547 static const WCHAR wszSeparator[] = L"\\rapps\\";
548
549 if (!CurProfile)
550 for (i = 0; i < N_CACHED_ITEMS; i++)
551 {
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;
558 }
559
560 GetCurrentDirectoryW(MAX_PATH, szDir);
561
562 wcscpy(buffer, szDir);
563 wcscat(buffer, wszSeparator);
564 wcscat(buffer, filename);
565
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);
569
570 if ((hFile == INVALID_HANDLE_VALUE) && (GetLastError() != ERROR_FILE_NOT_FOUND))
571 {
572 return FALSE;
573 }
574
575 for (i = 0; i < N_CACHED_ITEMS; i++)
576 {
577 if ((ItemsArray[i]->filename && !wcscmp(buffer, ItemsArray[i]->filename)))
578 {
579 if (i)
580 {
581 ParserFlushFile();
582 tempProfile = ItemsArray[i];
583 for (j = i; j > 0; j--)
584 ItemsArray[j] = ItemsArray[j - 1];
585 CurProfile = tempProfile;
586 }
587 if (hFile != INVALID_HANDLE_VALUE)
588 {
589 CloseHandle(hFile);
590 }
591
592 return TRUE;
593 }
594 }
595
596 ParserFlushFile();
597
598 if (i == N_CACHED_ITEMS)
599 {
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;
604 }
605
606 if (CurProfile->filename) ParserReleaseFile();
607
608 CurProfile->filename = HeapAlloc(GetProcessHeap(), 0, (wcslen(buffer) + 1) * sizeof(WCHAR));
609 if (CurProfile->filename == NULL)
610 return FALSE;
611
612 wcscpy(CurProfile->filename, buffer);
613
614 if (hFile != INVALID_HANDLE_VALUE)
615 {
616 CurProfile->section = ParserLoad(hFile, &CurProfile->encoding);
617 CloseHandle(hFile);
618 }
619 return TRUE;
620 }
621
622 static
623 INT
624 ParserGetSection(SECTION *section, LPCWSTR section_name, LPWSTR buffer, UINT len, BOOL return_values)
625 {
626 SECTIONKEY *key;
627
628 if (!buffer)
629 return 0;
630
631 while (section)
632 {
633 if (section->name[0] && !_wcsicmp(section->name, section_name))
634 {
635 UINT oldlen = len;
636 for (key = section->key; key; key = key->next)
637 {
638 if (len <= 2) break;
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. '=' */
642
643 ParserCopyEntry(buffer, key->name, len - 1, 0);
644 len -= wcslen(buffer) + 1;
645 buffer += wcslen(buffer) + 1;
646
647 if (len < 2) break;
648 if (return_values && key->value)
649 {
650 buffer[-1] = '=';
651 ParserCopyEntry(buffer, key->value, len - 1, 0);
652 len -= wcslen(buffer) + 1;
653 buffer += wcslen(buffer) + 1;
654 }
655 }
656 *buffer = '\0';
657 if (len <= 1)
658 {
659 buffer[-1] = '\0';
660 return oldlen - 2;
661 }
662 return oldlen - len;
663 }
664 section = section->next;
665 }
666 buffer[0] = buffer[1] = '\0';
667 return 0;
668 }
669
670 static
671 INT
672 ParserInternalGetString(LPCWSTR section, LPCWSTR key_name, LPWSTR buffer, UINT len)
673 {
674 SECTIONKEY *key = NULL;
675 static const WCHAR empty_strW[] = { 0 };
676
677 if (!buffer || !len) return 0;
678
679 if (key_name)
680 {
681 if (!key_name[0])
682 {
683 ParserCopyEntry(buffer, empty_strW, len, TRUE);
684 return wcslen(buffer);
685 }
686 key = ParserFind(&CurProfile->section, section, key_name, FALSE, FALSE);
687 ParserCopyEntry(buffer, (key && key->value) ? key->value : empty_strW,
688 len, TRUE);
689 return wcslen(buffer);
690 }
691
692 if (section && section[0])
693 {
694 INT ret = ParserGetSection(CurProfile->section, section, buffer, len, FALSE);
695 if (!buffer[0])
696 {
697 ParserCopyEntry(buffer, empty_strW, len, TRUE);
698 ret = wcslen(buffer);
699 }
700 return ret;
701 }
702
703 buffer[0] = '\0';
704 return 0;
705 }
706
707 INT
708 ParserGetString(LPCWSTR Section, LPCWSTR ValueName, LPWSTR Buffer, UINT Len, LPCWSTR FileName)
709 {
710 if (Section == NULL) return 0;
711
712 if (ParserOpen(FileName, FALSE))
713 return ParserInternalGetString(Section, ValueName, Buffer, Len);
714
715 return 0;
716 }
717
718 UINT
719 ParserGetInt(LPCWSTR Section, LPCWSTR ValueName, LPCWSTR FileName)
720 {
721 WCHAR Buffer[30];
722 UNICODE_STRING BufferW;
723 ULONG Result;
724
725 if (!ParserGetString(Section,
726 ValueName,
727 Buffer,
728 sizeof(Buffer) / sizeof(WCHAR),
729 FileName))
730 return -1;
731
732 if (!Buffer[0]) return -1;
733
734 RtlInitUnicodeString(&BufferW, Buffer);
735 RtlUnicodeStringToInteger(&BufferW, 0, &Result);
736 return Result;
737 }