Adding rostests as part of the tree restructure
[reactos.git] / rosapps / tests / regdump / regproc.c
1 /*
2 * Registry processing routines. Routines, common for registry
3 * processing frontends.
4 *
5 * Copyright 1999 Sylvain St-Germain
6 * Copyright 2002 Andriy Palamarchuk
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23 #ifdef WIN32_REGDBG
24 #include <windows.h>
25 #include <tchar.h>
26 #ifndef __GNUC__
27 #include <ntsecapi.h>
28 #else
29 #include <ctype.h>
30 #endif
31 #include <limits.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <assert.h>
35 //#include <winreg.h>
36 #include "regdump.h"
37 #else
38
39 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
40 #include <windows.h>
41 #include <commctrl.h>
42 #include <stdlib.h>
43 #include <tchar.h>
44 #include <process.h>
45 #include <stdio.h>
46 #include <wchar.h>
47
48 #include <ctype.h>
49 #include <limits.h>
50 #include <winnt.h>
51 #include <winreg.h>
52 #include <assert.h>
53
54 #endif
55
56 #include "regproc.h"
57
58
59 #define REG_VAL_BUF_SIZE 4096
60
61 /* Delimiters used to parse the "value" to query queryValue*/
62 #define QUERY_VALUE_MAX_ARGS 1
63
64 /* maximal number of characters in hexadecimal data line,
65 not including '\' character */
66 #define REG_FILE_HEX_LINE_LEN 76
67
68 /* Globals used by the api setValue, queryValue */
69 static LPTSTR currentKeyName = NULL;
70 static HKEY currentKeyClass = 0;
71 static HKEY currentKeyHandle = 0;
72 static BOOL bTheKeyIsOpen = FALSE;
73
74 static TCHAR *reg_class_names[] = {
75 _T("HKEY_LOCAL_MACHINE"),
76 _T("HKEY_USERS"),
77 _T("HKEY_CLASSES_ROOT"),
78 _T("HKEY_CURRENT_CONFIG"),
79 _T("HKEY_CURRENT_USER")
80 };
81
82 #define REG_CLASS_NUMBER (sizeof(reg_class_names) / sizeof(reg_class_names[0]))
83
84 static HKEY reg_class_keys[REG_CLASS_NUMBER] = {
85 HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT,
86 HKEY_CURRENT_CONFIG, HKEY_CURRENT_USER
87 };
88
89 /* return values */
90 #define NOT_ENOUGH_MEMORY 1
91 #define IO_ERROR 2
92
93 /* processing macros */
94
95 /* common check of memory allocation results */
96 #ifdef UNICODE
97 #define CHECK_ENOUGH_MEMORY(p) \
98 if (!(p)) \
99 { \
100 _tprintf(_T("file %S, line %d: Not enough memory"), __FILE__, __LINE__); \
101 assert(0);\
102 exit(NOT_ENOUGH_MEMORY); \
103 }
104 #else
105 #define CHECK_ENOUGH_MEMORY(p) \
106 if (!(p)) \
107 { \
108 _tprintf(_T("file %s, line %d: Not enough memory"), __FILE__, __LINE__); \
109 assert(0);\
110 exit(NOT_ENOUGH_MEMORY); \
111 }
112 #endif
113
114 #ifdef UNICODE
115 #define _TEOF WEOF
116 #else
117 #define _TEOF EOF
118 #endif
119
120 /******************************************************************************
121 * This is a replacement for strsep which is not portable (missing on Solaris).
122 */
123 #if 0
124 /* DISABLED */
125 char* getToken(char** str, const char* delims)
126 {
127 char* token;
128
129 if (*str==NULL) {
130 /* No more tokens */
131 return NULL;
132 }
133
134 token=*str;
135 while (**str!='\0') {
136 if (strchr(delims,**str)!=NULL) {
137 **str='\0';
138 (*str)++;
139 return token;
140 }
141 (*str)++;
142 }
143 /* There is no other token */
144 *str=NULL;
145 return token;
146 }
147 #endif
148
149 /******************************************************************************
150 * Copies file name from command line string to the buffer.
151 * Rewinds the command line string pointer to the next non-spece character
152 * after the file name.
153 * Buffer contains an empty string if no filename was found;
154 *
155 * params:
156 * command_line - command line current position pointer
157 * where *s[0] is the first symbol of the file name.
158 * file_name - buffer to write the file name to.
159 */
160 void get_file_nameA(CHAR **command_line, CHAR *file_name, int max_filename)
161 {
162 CHAR *s = *command_line;
163 int pos = 0; /* position of pointer "s" in *command_line */
164 file_name[0] = 0;
165
166 if (!s[0]) {
167 return;
168 }
169 if (s[0] == '"') {
170 s++;
171 (*command_line)++;
172 while (s[0] != '"') {
173 if (!s[0]) {
174 _tprintf(_T("Unexpected end of file name!\n"));
175 assert(0);
176 //exit(1);
177 }
178 s++;
179 pos++;
180 }
181 } else {
182 while (s[0] && !isspace(s[0])) {
183 s++;
184 pos++;
185 }
186 }
187 memcpy(file_name, *command_line, pos * sizeof((*command_line)[0]));
188 /* remove the last backslash */
189 if (file_name[pos - 1] == '\\') {
190 file_name[pos - 1] = '\0';
191 } else {
192 file_name[pos] = '\0';
193 }
194 if (s[0]) {
195 s++;
196 pos++;
197 }
198 while (s[0] && isspace(s[0])) {
199 s++;
200 pos++;
201 }
202 (*command_line) += pos;
203 }
204
205 void get_file_nameW(CHAR** command_line, WCHAR* filename, int max_filename)
206 {
207 CHAR filenameA[_MAX_PATH];
208 int len;
209
210 get_file_nameA(command_line, filenameA, _MAX_PATH);
211 len = strlen(filenameA);
212 OemToCharBuffW(filenameA, filename, max_filename);
213 filename[len] = _T('\0');
214 /*
215 UNICODE_STRING UnicodeString;
216 ANSI_STRING AnsiString;
217 CHAR filenameA[_MAX_PATH];
218
219 get_file_nameA(command_line, filenameA, _MAX_PATH);
220
221 //RtlInitAnsiString(&AnsiString, filenameA);
222 UnicodeString.Buffer = filename;
223 UnicodeString.MaximumLength = max_filename;//MAX_PATH;
224 RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE);
225 */
226 }
227
228 /******************************************************************************
229 * Converts a hex representation of a DWORD into a DWORD.
230 */
231 DWORD convertHexToDWord(TCHAR* str, BYTE* buf)
232 {
233 DWORD dw;
234 TCHAR xbuf[9];
235
236 memcpy(xbuf, str, 8 * sizeof(TCHAR));
237 xbuf[88 * sizeof(TCHAR)] = '\0';
238 _stscanf(xbuf, _T("%08lx"), &dw);
239 memcpy(buf, &dw, sizeof(DWORD));
240 return sizeof(DWORD);
241 }
242
243 /******************************************************************************
244 * Converts a hex buffer into a hex comma separated values
245 */
246 TCHAR* convertHexToHexCSV(BYTE* buf, ULONG bufLen)
247 {
248 TCHAR* str;
249 TCHAR* ptrStr;
250 BYTE* ptrBuf;
251
252 ULONG current = 0;
253 str = HeapAlloc(GetProcessHeap(), 0, (bufLen+1)*2*sizeof(TCHAR));
254 memset(str, 0, (bufLen+1)*2);
255 ptrStr = str; /* Pointer to result */
256 ptrBuf = buf; /* Pointer to current */
257 while (current < bufLen) {
258 BYTE bCur = ptrBuf[current++];
259 TCHAR res[3];
260 _stprintf(res, _T("%02x"), (unsigned int)*&bCur);
261 _tcscat(str, res);
262 _tcscat(str, _T(","));
263 }
264 /* Get rid of the last comma */
265 str[_tcslen(str)-1] = _T('\0');
266 return str;
267 }
268
269 /******************************************************************************
270 * Converts a hex buffer into a DWORD string
271 */
272 TCHAR* convertHexToDWORDStr(BYTE* buf, ULONG bufLen)
273 {
274 TCHAR* str;
275 DWORD dw;
276
277 if (bufLen != sizeof(DWORD)) return NULL;
278 str = HeapAlloc(GetProcessHeap(), 0, ((bufLen*2)+1)*sizeof(TCHAR));
279 memcpy(&dw, buf, sizeof(DWORD));
280 _stprintf(str, _T("%08lx"), dw);
281 /* Get rid of the last comma */
282 return str;
283 }
284
285 /******************************************************************************
286 * Converts a hex comma separated values list into a hex list.
287 * The Hex input string must be in exactly the correct form.
288 */
289 DWORD convertHexCSVToHex(TCHAR* str, BYTE* buf, ULONG bufLen)
290 {
291 TCHAR* s = str; /* Pointer to current */
292 CHAR* b = buf; /* Pointer to result */
293 ULONG strLen = _tcslen(str);
294 ULONG strPos = 0;
295 DWORD byteCount = 0;
296
297 memset(buf, 0, bufLen);
298 /*
299 * warn the user if we are here with a string longer than 2 bytes that does
300 * not contains ",". It is more likely because the data is invalid.
301 */
302 if ((strLen > 2) && (_tcschr(str, _T(',')) == NULL)) {
303 _tprintf(_T("WARNING converting CSV hex stream with no comma, ") \
304 _T("input data seems invalid.\n"));
305 }
306 if (strLen > 3*bufLen) {
307 _tprintf(_T("ERROR converting CSV hex stream. Too long\n"));
308 }
309 while (strPos < strLen) {
310 TCHAR xbuf[3];
311 TCHAR wc;
312 memcpy(xbuf, s, 2);
313 xbuf[3] = _T('\0');
314 _stscanf(xbuf, _T("%02x"), (UINT*)&wc);
315 if (byteCount < bufLen)
316 *b++ = (unsigned char)wc;
317 s += 3;
318 strPos += 3;
319 ++byteCount;
320 }
321 return byteCount;
322 }
323
324 /******************************************************************************
325 * This function returns the HKEY associated with the data type encoded in the
326 * value. It modifies the input parameter (key value) in order to skip this
327 * "now useless" data type information.
328 *
329 * Note: Updated based on the algorithm used in 'server/registry.c'
330 */
331 DWORD getDataType(LPTSTR* lpValue, DWORD* parse_type)
332 {
333 struct data_type { const TCHAR *tag; int len; int type; int parse_type; };
334
335 static const struct data_type data_types[] =
336 { /* actual type */ /* type to assume for parsing */
337 { _T("\""), 1, REG_SZ, REG_SZ },
338 { _T("str:\""), 5, REG_SZ, REG_SZ },
339 // { _T("str(2):\""), 8, REG_EXPAND_SZ, REG_SZ },
340 { _T("expand:\""), 8, REG_EXPAND_SZ, REG_EXPAND_SZ },
341 { _T("hex:"), 4, REG_BINARY, REG_BINARY },
342 { _T("dword:"), 6, REG_DWORD, REG_DWORD },
343 { _T("hex("), 4, -1, REG_BINARY },
344 { NULL, 0, 0, 0 }
345 };
346
347 const struct data_type *ptr;
348 int type;
349
350 for (ptr = data_types; ptr->tag; ptr++) {
351 if (memcmp(ptr->tag, *lpValue, ptr->len))
352 continue;
353
354 /* Found! */
355 *parse_type = ptr->parse_type;
356 type = ptr->type;
357 *lpValue += ptr->len;
358 if (type == -1) {
359 TCHAR* end;
360 /* "hex(xx):" is special */
361 type = (int)_tcstoul(*lpValue , &end, 16);
362 if (**lpValue == _T('\0') || *end != _T(')') || *(end+1) != _T(':')) {
363 type = REG_NONE;
364 } else {
365 *lpValue = end + 2;
366 }
367 }
368 return type;
369 }
370 return (**lpValue == _T('\0') ? REG_SZ : REG_NONE);
371 }
372
373 /******************************************************************************
374 * Returns an allocated buffer with a cleaned copy (removed the surrounding
375 * dbl quotes) of the passed value.
376 */
377 LPTSTR getArg(LPTSTR arg)
378 {
379 LPTSTR tmp = NULL;
380 ULONG len;
381
382 if (arg == NULL) return NULL;
383
384 // Get rid of surrounding quotes
385 len = _tcslen(arg);
386 if (arg[len-1] == _T('\"')) arg[len-1] = _T('\0');
387 if (arg[0] == _T('\"')) arg++;
388 tmp = HeapAlloc(GetProcessHeap(), 0, (_tcslen(arg)+1) * sizeof(TCHAR));
389 _tcscpy(tmp, arg);
390 return tmp;
391 }
392
393 /******************************************************************************
394 * Replaces escape sequences with the characters.
395 */
396 void REGPROC_unescape_string(LPTSTR str)
397 {
398 int str_idx = 0; /* current character under analysis */
399 int val_idx = 0; /* the last character of the unescaped string */
400 int len = _tcslen(str);
401 for (str_idx = 0; str_idx < len; str_idx++, val_idx++) {
402 if (str[str_idx] == _T('\\')) {
403 str_idx++;
404 switch (str[str_idx]) {
405 case _T('n'):
406 str[val_idx] = _T('\n');
407 break;
408 case _T('\\'):
409 case _T('"'):
410 str[val_idx] = str[str_idx];
411 break;
412 default:
413 _tprintf(_T("Warning! Unrecognized escape sequence: \\%c'\n"), str[str_idx]);
414 str[val_idx] = str[str_idx];
415 break;
416 }
417 } else {
418 str[val_idx] = str[str_idx];
419 }
420 }
421 str[val_idx] = _T('\0');
422 }
423
424 /******************************************************************************
425 * Sets the value with name val_name to the data in val_data for the currently
426 * opened key.
427 *
428 * Parameters:
429 * val_name - name of the registry value
430 * val_data - registry value data
431 */
432 HRESULT setValue(LPTSTR val_name, LPTSTR val_data)
433 {
434 HRESULT hRes;
435 DWORD dwDataType, dwParseType;
436 LPBYTE lpbData;
437 BYTE convert[KEY_MAX_LEN];
438 BYTE *bBigBuffer = 0;
439 DWORD dwLen;
440
441 if ((val_name == NULL) || (val_data == NULL))
442 return ERROR_INVALID_PARAMETER;
443
444 /* Get the data type stored into the value field */
445 dwDataType = getDataType(&val_data, &dwParseType);
446
447 // if (dwParseType == REG_EXPAND_SZ) {
448 // }
449 // if (dwParseType == REG_SZ || dwParseType == REG_EXPAND_SZ) { /* no conversion for string */
450
451 if (dwParseType == REG_SZ) { /* no conversion for string */
452 dwLen = _tcslen(val_data);
453 if (dwLen > 0 && val_data[dwLen-1] == _T('"')) {
454 dwLen--;
455 val_data[dwLen] = _T('\0');
456 }
457 dwLen++;
458 dwLen *= sizeof(TCHAR);
459 REGPROC_unescape_string(val_data);
460 lpbData = val_data;
461 } else if (dwParseType == REG_DWORD) { /* Convert the dword types */
462 dwLen = convertHexToDWord(val_data, convert);
463 lpbData = convert;
464 } else { /* Convert the hexadecimal types */
465 int b_len = _tcslen(val_data)+2/3;
466 if (b_len > KEY_MAX_LEN) {
467 bBigBuffer = HeapAlloc (GetProcessHeap(), 0, b_len * sizeof(TCHAR));
468 if (bBigBuffer == NULL) {
469 return ERROR_REGISTRY_IO_FAILED;
470 }
471 CHECK_ENOUGH_MEMORY(bBigBuffer);
472 dwLen = convertHexCSVToHex(val_data, bBigBuffer, b_len);
473 lpbData = bBigBuffer;
474 } else {
475 dwLen = convertHexCSVToHex(val_data, convert, KEY_MAX_LEN);
476 lpbData = convert;
477 }
478 }
479 hRes = RegSetValueEx(currentKeyHandle, val_name,
480 0, /* Reserved */dwDataType, lpbData, dwLen);
481
482 _tprintf(_T(" Value: %s, Data: %s\n"), val_name, lpbData);
483
484
485 if (bBigBuffer)
486 HeapFree(GetProcessHeap(), 0, bBigBuffer);
487 return hRes;
488 }
489
490
491 /******************************************************************************
492 * Open the key
493 */
494 HRESULT openKey(LPTSTR stdInput)
495 {
496 DWORD dwDisp;
497 HRESULT hRes;
498
499 /* Sanity checks */
500 if (stdInput == NULL)
501 return ERROR_INVALID_PARAMETER;
502
503 /* Get the registry class */
504 currentKeyClass = getRegClass(stdInput); /* Sets global variable */
505 if (currentKeyClass == (HKEY)ERROR_INVALID_PARAMETER)
506 return (HRESULT)ERROR_INVALID_PARAMETER;
507
508 /* Get the key name */
509 currentKeyName = getRegKeyName(stdInput); /* Sets global variable */
510 if (currentKeyName == NULL)
511 return ERROR_INVALID_PARAMETER;
512
513 hRes = RegCreateKeyEx(
514 currentKeyClass, /* Class */
515 currentKeyName, /* Sub Key */
516 0, /* MUST BE 0 */
517 NULL, /* object type */
518 REG_OPTION_NON_VOLATILE, /* option, REG_OPTION_NON_VOLATILE ... */
519 KEY_ALL_ACCESS, /* access mask, KEY_ALL_ACCESS */
520 NULL, /* security attribute */
521 &currentKeyHandle, /* result */
522 &dwDisp); /* disposition, REG_CREATED_NEW_KEY or
523 REG_OPENED_EXISTING_KEY */
524
525 if (hRes == ERROR_SUCCESS)
526 bTheKeyIsOpen = TRUE;
527
528 return hRes;
529
530 }
531
532 /******************************************************************************
533 * Extracts from [HKEY\some\key\path] or HKEY\some\key\path types of line
534 * the key name (what starts after the first '\')
535 */
536 LPTSTR getRegKeyName(LPTSTR lpLine)
537 {
538 LPTSTR keyNameBeg;
539 TCHAR lpLineCopy[KEY_MAX_LEN];
540
541 if (lpLine == NULL)
542 return NULL;
543
544 _tcscpy(lpLineCopy, lpLine);
545 keyNameBeg = _tcschr(lpLineCopy, _T('\\')); /* The key name start by '\' */
546 if (keyNameBeg) {
547 LPTSTR keyNameEnd;
548
549 keyNameBeg++; /* is not part of the name */
550 keyNameEnd = _tcschr(lpLineCopy, _T(']'));
551 if (keyNameEnd) {
552 *keyNameEnd = _T('\0'); /* remove ']' from the key name */
553 }
554 } else {
555 keyNameBeg = lpLineCopy + _tcslen(lpLineCopy); /* branch - empty string */
556 }
557 currentKeyName = HeapAlloc(GetProcessHeap(), 0, (_tcslen(keyNameBeg)+1)*sizeof(TCHAR));
558 CHECK_ENOUGH_MEMORY(currentKeyName);
559 _tcscpy(currentKeyName, keyNameBeg);
560 return currentKeyName;
561 }
562
563 /******************************************************************************
564 * Extracts from [HKEY\some\key\path] or HKEY\some\key\path types of line
565 * the key class (what ends before the first '\')
566 */
567 HKEY getRegClass(LPTSTR lpClass)
568 {
569 LPTSTR classNameEnd;
570 LPTSTR classNameBeg;
571 int i;
572
573 TCHAR lpClassCopy[KEY_MAX_LEN];
574
575 if (lpClass == NULL)
576 return (HKEY)ERROR_INVALID_PARAMETER;
577
578 _tcsncpy(lpClassCopy, lpClass, KEY_MAX_LEN);
579
580 classNameEnd = _tcschr(lpClassCopy, _T('\\')); /* The class name ends by '\' */
581 if (!classNameEnd) { /* or the whole string */
582 classNameEnd = lpClassCopy + _tcslen(lpClassCopy);
583 if (classNameEnd[-1] == _T(']')) {
584 classNameEnd--;
585 }
586 }
587 *classNameEnd = _T('\0'); /* Isolate the class name */
588 if (lpClassCopy[0] == _T('[')) {
589 classNameBeg = lpClassCopy + 1;
590 } else {
591 classNameBeg = lpClassCopy;
592 }
593 for (i = 0; i < REG_CLASS_NUMBER; i++) {
594 if (!_tcscmp(classNameBeg, reg_class_names[i])) {
595 return reg_class_keys[i];
596 }
597 }
598 return (HKEY)ERROR_INVALID_PARAMETER;
599 }
600
601 /******************************************************************************
602 * Close the currently opened key.
603 */
604 void closeKey(VOID)
605 {
606 RegCloseKey(currentKeyHandle);
607 HeapFree(GetProcessHeap(), 0, currentKeyName); /* Allocated by getKeyName */
608 bTheKeyIsOpen = FALSE;
609 currentKeyName = NULL;
610 currentKeyClass = 0;
611 currentKeyHandle = 0;
612 }
613
614 /******************************************************************************
615 * This function is the main entry point to the setValue type of action. It
616 * receives the currently read line and dispatch the work depending on the
617 * context.
618 */
619 void doSetValue(LPTSTR stdInput)
620 {
621 /*
622 * We encountered the end of the file, make sure we
623 * close the opened key and exit
624 */
625 if (stdInput == NULL) {
626 if (bTheKeyIsOpen != FALSE)
627 closeKey();
628 return;
629 }
630
631 if (stdInput[0] == _T('[')) { /* We are reading a new key */
632 if (bTheKeyIsOpen != FALSE) {
633 closeKey(); /* Close the previous key before */
634 }
635 if (openKey(stdInput) != ERROR_SUCCESS) {
636 _tprintf(_T("doSetValue failed to open key %s\n"), stdInput);
637 }
638 } else if ((bTheKeyIsOpen) &&
639 ((stdInput[0] == _T('@')) || /* reading a default @=data pair */
640 (stdInput[0] == _T('\"')))) { /* reading a new value=data pair */
641 processSetValue(stdInput);
642 } else { /* since we are assuming that the file format is */
643 if (bTheKeyIsOpen) /* valid we must be reading a blank line which */
644 closeKey(); /* indicate end of this key processing */
645 }
646 }
647
648 /******************************************************************************
649 * This funtion is the main entry point to the queryValue type of action. It
650 * receives the currently read line and dispatch the work depending on the
651 * context.
652 */
653 void doQueryValue(LPTSTR stdInput) {
654 /*
655 * We encoutered the end of the file, make sure we
656 * close the opened key and exit
657 */
658 if (stdInput == NULL) {
659 if (bTheKeyIsOpen != FALSE)
660 closeKey();
661 return;
662 }
663
664 if (stdInput[0] == _T('[')) { /* We are reading a new key */
665 if (bTheKeyIsOpen != FALSE)
666 closeKey(); /* Close the previous key before */
667 if (openKey(stdInput) != ERROR_SUCCESS ) {
668 _tprintf(_T("doQueryValue failed to open key %s\n"), stdInput);
669 }
670 }
671 else if( (bTheKeyIsOpen) &&
672 ((stdInput[0] == _T('@')) || /* reading a default @=data pair */
673 (stdInput[0] == _T('\"')))) { /* reading a new value=data pair */
674 processQueryValue(stdInput);
675 } else { /* since we are assuming that the file format is */
676 if (bTheKeyIsOpen) /* valid we must be reading a blank line which */
677 closeKey(); /* indicate end of this key processing */
678 }
679 }
680
681 /******************************************************************************
682 * This funtion is the main entry point to the deletetValue type of action. It
683 * receives the currently read line and dispatch the work depending on the
684 * context.
685 */
686 void doDeleteValue(LPTSTR line) {
687 _tprintf(_T("deleteValue not yet implemented\n"));
688 }
689
690 /******************************************************************************
691 * This funtion is the main entry point to the deleteKey type of action. It
692 * receives the currently read line and dispatch the work depending on the
693 * context.
694 */
695 void doDeleteKey(LPTSTR line) {
696 _tprintf(_T("deleteKey not yet implemented\n"));
697 }
698
699 /******************************************************************************
700 * This funtion is the main entry point to the createKey type of action. It
701 * receives the currently read line and dispatch the work depending on the
702 * context.
703 */
704 void doCreateKey(LPTSTR line) {
705 _tprintf(_T("createKey not yet implemented\n"));
706 }
707
708 /******************************************************************************
709 * This function is a wrapper for the setValue function. It prepares the
710 * land and clean the area once completed.
711 * Note: this function modifies the line parameter.
712 *
713 * line - registry file unwrapped line. Should have the registry value name and
714 * complete registry value data.
715 */
716 void processSetValue(LPTSTR line)
717 {
718 LPTSTR val_name; /* registry value name */
719 LPTSTR val_data; /* registry value data */
720
721 int line_idx = 0; /* current character under analysis */
722 HRESULT hRes = 0;
723
724 /* get value name */
725 if (line[line_idx] == _T('@') && line[line_idx + 1] == _T('=')) {
726 line[line_idx] = _T('\0');
727 val_name = line;
728 line_idx++;
729 } else if (line[line_idx] == _T('\"')) {
730 line_idx++;
731 val_name = line + line_idx;
732 while (TRUE) {
733 if (line[line_idx] == _T('\\')) { /* skip escaped character */
734 line_idx += 2;
735 } else {
736 if (line[line_idx] == _T('\"')) {
737 line[line_idx] = _T('\0');
738 line_idx++;
739 break;
740 } else {
741 line_idx++;
742 }
743 }
744 }
745 if (line[line_idx] != _T('=')) {
746 line[line_idx] = _T('\"');
747 _tprintf(_T("Warning! uncrecognized line:\n%s\n"), line);
748 return;
749 }
750 } else {
751 _tprintf(_T("Warning! unrecognized line:\n%s\n"), line);
752 return;
753 }
754 line_idx++; /* skip the '=' character */
755 val_data = line + line_idx;
756 REGPROC_unescape_string(val_name);
757
758 _tprintf(_T("Key: %s, Value: %s, Data: %s\n"), currentKeyName, val_name, val_data);
759
760 hRes = setValue(val_name, val_data);
761 if (hRes != ERROR_SUCCESS) {
762 _tprintf(_T("ERROR Key %s not created. Value: %s, Data: %s\n"), currentKeyName, val_name, val_data);
763 }
764 }
765
766 /******************************************************************************
767 * This function is a wrapper for the queryValue function. It prepares the
768 * land and clean the area once completed.
769 */
770 void processQueryValue(LPTSTR cmdline)
771 {
772 _tprintf(_T("ERROR!!! - temporary disabled"));
773 //exit(1);
774 return;
775 #if 0
776 LPSTR argv[QUERY_VALUE_MAX_ARGS];/* args storage */
777 LPSTR token = NULL; /* current token analized */
778 ULONG argCounter = 0; /* counter of args */
779 INT counter;
780 HRESULT hRes = 0;
781 LPSTR keyValue = NULL;
782 LPSTR lpsRes = NULL;
783
784 /*
785 * Init storage and parse the line
786 */
787 for (counter = 0; counter < QUERY_VALUE_MAX_ARGS; counter++)
788 argv[counter] = NULL;
789
790 while ((token = getToken(&cmdline, queryValueDelim[argCounter])) != NULL) {
791 argv[argCounter++] = getArg(token);
792 if (argCounter == QUERY_VALUE_MAX_ARGS)
793 break; /* Stop processing args no matter what */
794 }
795
796 /* The value we look for is the first token on the line */
797 if (argv[0] == NULL)
798 return; /* SHOULD NOT HAPPEN */
799 else
800 keyValue = argv[0];
801
802 if ((keyValue[0] == '@') && (_tcslen(keyValue) == 1)) {
803 LONG lLen = KEY_MAX_LEN;
804 TCHAR* lpsData = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,KEY_MAX_LEN);
805 /*
806 * We need to query the key default value
807 */
808 hRes = RegQueryValue(currentKeyHandle, currentKeyName, (LPBYTE)lpsData, &lLen);
809 if (hRes == ERROR_MORE_DATA) {
810 lpsData = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpsData, lLen);
811 hRes = RegQueryValue(currentKeyHandle, currentKeyName, (LPBYTE)lpsData, &lLen);
812 }
813 if (hRes == ERROR_SUCCESS) {
814 lpsRes = HeapAlloc(GetProcessHeap(), 0, lLen);
815 strncpy(lpsRes, lpsData, lLen);
816 lpsRes[lLen-1]='\0';
817 }
818 } else {
819 DWORD dwLen = KEY_MAX_LEN;
820 BYTE* lpbData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, KEY_MAX_LEN);
821 DWORD dwType;
822 /*
823 * We need to query a specific value for the key
824 */
825 hRes = RegQueryValueEx(
826 currentKeyHandle,
827 keyValue,
828 0,
829 &dwType,
830 (LPBYTE)lpbData,
831 &dwLen);
832
833 if (hRes == ERROR_MORE_DATA) {
834 lpbData = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpbData, dwLen * sizeof(TCHAR));
835 hRes = RegQueryValueEx(currentKeyHandle, keyValue, NULL, &dwType, (LPBYTE)lpbData, &dwLen);
836 }
837
838 if (hRes == ERROR_SUCCESS) {
839 /*
840 * Convert the returned data to a displayable format
841 */
842 switch (dwType) {
843 case REG_SZ:
844 case REG_EXPAND_SZ:
845 lpsRes = HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(TCHAR));
846 strncpy(lpsRes, lpbData, dwLen);
847 lpsRes[dwLen-1] = '\0';
848 break;
849 case REG_DWORD:
850 lpsRes = convertHexToDWORDStr(lpbData, dwLen);
851 break;
852 default:
853 lpsRes = convertHexToHexCSV(lpbData, dwLen);
854 break;
855 }
856 }
857
858 HeapFree(GetProcessHeap(), 0, lpbData);
859 }
860 if (hRes == ERROR_SUCCESS) {
861 _tprintf(_T("Value \"%s\" = \"%s\" in key [%s]\n"), keyValue, lpsRes, currentKeyName);
862
863 } else {
864 _tprintf(_T("ERROR Value \"%s\" not found. for key \"%s\"\n"), keyValue, currentKeyName);
865 }
866
867 /*
868 * Do some cleanup
869 */
870 for (counter=0; counter<argCounter; counter++)
871 if (argv[counter] != NULL)
872 HeapFree(GetProcessHeap(), 0, argv[counter]);
873
874 if (lpsRes != NULL)
875 HeapFree(GetProcessHeap(), 0, lpsRes);
876 #endif
877 }
878
879 /******************************************************************************
880 * Calls command for each line of a registry file.
881 * Correctly processes comments (in # form), line continuation.
882 *
883 * Parameters:
884 * in - input stream to read from
885 * command - command to be called for each line
886 */
887 void processRegLines(FILE *in, CommandAPI command)
888 {
889 LPTSTR line = NULL; /* line read from input stream */
890 ULONG lineSize = REG_VAL_BUF_SIZE;
891
892 line = HeapAlloc(GetProcessHeap(), 0, lineSize * sizeof(TCHAR));
893 CHECK_ENOUGH_MEMORY(line);
894
895 while (!feof(in)) {
896 LPTSTR s; /* The pointer into line for where the current fgets should read */
897 s = line;
898 for (;;) {
899 size_t size_remaining;
900 int size_to_get;
901 TCHAR *s_eol; /* various local uses */
902
903 /* Do we need to expand the buffer ? */
904 assert (s >= line && s <= line + lineSize);
905 size_remaining = lineSize - (s-line);
906 if (size_remaining < 2) { /* room for 1 character and the \0 */
907 TCHAR *new_buffer;
908 size_t new_size = lineSize + REG_VAL_BUF_SIZE;
909 if (new_size > lineSize) /* no arithmetic overflow */
910 new_buffer = HeapReAlloc (GetProcessHeap(), 0, line, new_size * sizeof(TCHAR));
911 else
912 new_buffer = NULL;
913 CHECK_ENOUGH_MEMORY(new_buffer);
914 line = new_buffer;
915 s = line + lineSize - size_remaining;
916 lineSize = new_size;
917 size_remaining = lineSize - (s-line);
918 }
919
920 /* Get as much as possible into the buffer, terminated either by
921 * eof, error, eol or getting the maximum amount. Abort on error.
922 */
923 //
924 // This line is surely foobar, don't want to read INT_MAX in buffer at s, it's never going to be that big...
925 // size_to_get = (size_remaining > INT_MAX ? INT_MAX : size_remaining);
926 //
927 // Looks as if 'lineSize' contains the number of characters of buffer size
928 //
929 size_to_get = (size_remaining > lineSize ? lineSize : size_remaining);
930
931 if (NULL == _fgetts(s, size_to_get, in)) {
932 if (ferror(in)) {
933 //_tperror(_T("While reading input"));
934 perror ("While reading input");
935 //exit(IO_ERROR);
936 return;
937 } else {
938 assert (feof(in));
939 *s = _T('\0');
940 /* It is not clear to me from the definition that the
941 * contents of the buffer are well defined on detecting
942 * an eof without managing to read anything.
943 */
944 }
945 }
946
947 /* If we didn't read the eol nor the eof go around for the rest */
948 s_eol = _tcschr (s, _T('\n'));
949 if (!feof (in) && !s_eol) {
950 s = _tcschr (s, _T('\0'));
951 /* It should be s + size_to_get - 1 but this is safer */
952 continue;
953 }
954
955 /* If it is a comment line then discard it and go around again */
956 if (line [0] == _T('#')) {
957 s = line;
958 continue;
959 }
960
961 /* Remove any line feed. Leave s_eol on the \0 */
962 if (s_eol) {
963 *s_eol = _T('\0');
964 if (s_eol > line && *(s_eol-1) == _T('\r'))
965 *--s_eol = _T('\0');
966 } else {
967 s_eol = _tcschr (s, _T('\0'));
968 }
969 /* If there is a concatenating \\ then go around again */
970 if (s_eol > line && *(s_eol-1) == _T('\\')) {
971 int c;
972 s = s_eol-1;
973 /* The following error protection could be made more self-
974 * correcting but I thought it not worth trying.
975 */
976
977 if ((c = _fgettc(in)) == _TEOF || c != _T(' ') ||
978 (c = _fgettc(in)) == _TEOF || c != _T(' '))
979 _tprintf(_T("ERROR - invalid continuation.\n"));
980 continue;
981 }
982 break; /* That is the full virtual line */
983 }
984 command(line);
985 }
986 command(NULL);
987 HeapFree(GetProcessHeap(), 0, line);
988 }
989
990 /******************************************************************************
991 * This funtion is the main entry point to the registerDLL action. It
992 * receives the currently read line, then loads and registers the requested DLLs
993 */
994 void doRegisterDLL(LPTSTR stdInput)
995 {
996 HMODULE theLib = 0;
997 UINT retVal = 0;
998
999 /* Check for valid input */
1000 if (stdInput == NULL) return;
1001
1002 /* Load and register the library, then free it */
1003 theLib = LoadLibrary(stdInput);
1004 if (theLib) {
1005 FARPROC lpfnDLLRegProc = GetProcAddress(theLib, "DllRegisterServer");
1006 if (lpfnDLLRegProc) {
1007 retVal = (*lpfnDLLRegProc)();
1008 } else {
1009 _tprintf(_T("Couldn't find DllRegisterServer proc in '%s'.\n"), stdInput);
1010 }
1011 if (retVal != S_OK) {
1012 _tprintf(_T("Couldn't find DllRegisterServer proc in '%s'.\n"), stdInput);
1013 }
1014 FreeLibrary(theLib);
1015 } else {
1016 _tprintf(_T("Could not load DLL '%s'.\n"), stdInput);
1017 }
1018 }
1019
1020 /******************************************************************************
1021 * This funtion is the main entry point to the unregisterDLL action. It
1022 * receives the currently read line, then loads and unregisters the requested DLLs
1023 */
1024 void doUnregisterDLL(LPTSTR stdInput)
1025 {
1026 HMODULE theLib = 0;
1027 UINT retVal = 0;
1028
1029 /* Check for valid input */
1030 if (stdInput == NULL) return;
1031
1032 /* Load and unregister the library, then free it */
1033 theLib = LoadLibrary(stdInput);
1034 if (theLib) {
1035 FARPROC lpfnDLLRegProc = GetProcAddress(theLib, "DllUnregisterServer");
1036 if (lpfnDLLRegProc) {
1037 retVal = (*lpfnDLLRegProc)();
1038 } else {
1039 _tprintf(_T("Couldn't find DllUnregisterServer proc in '%s'.\n"), stdInput);
1040 }
1041 if (retVal != S_OK) {
1042 _tprintf(_T("DLLUnregisterServer error 0x%x in '%s'.\n"), retVal, stdInput);
1043 }
1044 FreeLibrary(theLib);
1045 } else {
1046 _tprintf(_T("Could not load DLL '%s'.\n"), stdInput);
1047 }
1048 }
1049
1050 /****************************************************************************
1051 * REGPROC_print_error
1052 *
1053 * Print the message for GetLastError
1054 */
1055
1056 void REGPROC_print_error(VOID)
1057 {
1058 LPVOID lpMsgBuf;
1059 DWORD error_code;
1060 int status;
1061
1062 error_code = GetLastError ();
1063 status = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
1064 NULL, error_code, 0, (LPTSTR) &lpMsgBuf, 0, NULL);
1065 if (!status) {
1066 _tprintf(_T("Cannot display message for error %ld, status %ld\n"), error_code, GetLastError());
1067 } else {
1068 _tprintf(_T("REGPROC_print_error() - "));
1069 puts(lpMsgBuf);
1070 LocalFree((HLOCAL)lpMsgBuf);
1071 }
1072 //exit(1);
1073 }
1074
1075 /******************************************************************************
1076 * Checks whether the buffer has enough room for the string or required size.
1077 * Resizes the buffer if necessary.
1078 *
1079 * Parameters:
1080 * buffer - pointer to a buffer for string
1081 * len - current length of the buffer in characters.
1082 * required_len - length of the string to place to the buffer in characters.
1083 * The length does not include the terminating null character.
1084 */
1085 void REGPROC_resize_char_buffer(TCHAR **buffer, DWORD *len, DWORD required_len)
1086 {
1087 required_len++;
1088 if (required_len > *len) {
1089 *len = required_len;
1090 *buffer = HeapReAlloc(GetProcessHeap(), 0, *buffer, *len * sizeof(**buffer));
1091 CHECK_ENOUGH_MEMORY(*buffer);
1092 }
1093 }
1094
1095 /******************************************************************************
1096 * Prints string str to file
1097 */
1098 void REGPROC_export_string(FILE *file, TCHAR *str)
1099 {
1100 size_t len = _tcslen(str);
1101 size_t i;
1102
1103 /* escaping characters */
1104 for (i = 0; i < len; i++) {
1105 TCHAR c = str[i];
1106 switch (c) {
1107 //case _T('\\'): _fputts(_T("\\\\"), file); break;
1108 case _T('\"'): _fputts(_T("\\\""), file); break;
1109 case _T('\n'): _fputts(_T("\\\n"), file); break;
1110 default: _fputtc(c, file); break;
1111 }
1112 }
1113 }
1114
1115 /******************************************************************************
1116 * Writes contents of the registry key to the specified file stream.
1117 *
1118 * Parameters:
1119 * file - writable file stream to export registry branch to.
1120 * key - registry branch to export.
1121 * reg_key_name_buf - name of the key with registry class.
1122 * Is resized if necessary.
1123 * reg_key_name_len - length of the buffer for the registry class in characters.
1124 * val_name_buf - buffer for storing value name.
1125 * Is resized if necessary.
1126 * val_name_len - length of the buffer for storing value names in characters.
1127 * val_buf - buffer for storing values while extracting.
1128 * Is resized if necessary.
1129 * val_size - size of the buffer for storing values in bytes.
1130 */
1131 void export_hkey(FILE *file, HKEY key,
1132 TCHAR **reg_key_name_buf, DWORD *reg_key_name_len,
1133 TCHAR **val_name_buf, DWORD *val_name_len,
1134 BYTE **val_buf, DWORD *val_size)
1135 {
1136 DWORD max_sub_key_len;
1137 DWORD max_val_name_len;
1138 DWORD max_val_size;
1139 DWORD curr_len;
1140 DWORD i;
1141 BOOL more_data;
1142 LONG ret;
1143
1144 /* get size information and resize the buffers if necessary */
1145 if (RegQueryInfoKey(key, NULL, NULL, NULL, NULL, &max_sub_key_len, NULL,
1146 NULL, &max_val_name_len, &max_val_size, NULL, NULL) != ERROR_SUCCESS) {
1147 REGPROC_print_error();
1148 }
1149 curr_len = _tcslen(*reg_key_name_buf);
1150 REGPROC_resize_char_buffer(reg_key_name_buf, reg_key_name_len, max_sub_key_len + curr_len + 1);
1151 REGPROC_resize_char_buffer(val_name_buf, val_name_len, max_val_name_len);
1152 if (max_val_size > *val_size) {
1153 *val_size = max_val_size;
1154 *val_buf = HeapReAlloc(GetProcessHeap(), 0, *val_buf, *val_size * sizeof(TCHAR));
1155 CHECK_ENOUGH_MEMORY(val_buf);
1156 }
1157 /* output data for the current key */
1158 _fputts(_T("\n["), file);
1159 _fputts(*reg_key_name_buf, file);
1160 _fputts(_T("]\n"), file);
1161 /* print all the values */
1162 i = 0;
1163 more_data = TRUE;
1164 while (more_data) {
1165 DWORD value_type;
1166 DWORD val_name_len1 = *val_name_len;
1167 DWORD val_size1 = *val_size;
1168 ret = RegEnumValue(key, i, *val_name_buf, &val_name_len1, NULL, &value_type, *val_buf, &val_size1);
1169 if (ret != ERROR_SUCCESS) {
1170 more_data = FALSE;
1171 if (ret != ERROR_NO_MORE_ITEMS) {
1172 REGPROC_print_error();
1173 }
1174 } else {
1175 i++;
1176 if ((*val_name_buf)[0]) {
1177 _fputts(_T("\""), file);
1178 REGPROC_export_string(file, *val_name_buf);
1179 _fputts(_T("\"="), file);
1180 } else {
1181 _fputts(_T("@="), file);
1182 }
1183 switch (value_type) {
1184 case REG_EXPAND_SZ:
1185 _fputts(_T("expand:"), file);
1186 case REG_SZ:
1187 _fputts(_T("\""), file);
1188 REGPROC_export_string(file, *val_buf);
1189 _fputts(_T("\"\n"), file);
1190 break;
1191 case REG_DWORD:
1192 _ftprintf(file, _T("dword:%08lx\n"), *((DWORD *)*val_buf));
1193 break;
1194 default:
1195 /*
1196 _tprintf(_T("warning - unsupported registry format '%ld', ") \
1197 _T("treating as binary\n"), value_type);
1198 _tprintf(_T("key name: \"%s\"\n"), *reg_key_name_buf);
1199 _tprintf(_T("value name:\"%s\"\n\n"), *val_name_buf);
1200 */
1201 /* falls through */
1202 case REG_MULTI_SZ:
1203 /* falls through */
1204 case REG_BINARY:
1205 {
1206 DWORD i1;
1207 TCHAR *hex_prefix;
1208 TCHAR buf[20];
1209 int cur_pos;
1210
1211 if (value_type == REG_BINARY) {
1212 hex_prefix = _T("hex:");
1213 } else {
1214 hex_prefix = buf;
1215 _stprintf(buf, _T("hex(%ld):"), value_type);
1216 }
1217 /* position of where the next character will be printed */
1218 /* NOTE: yes, _tcslen("hex:") is used even for hex(x): */
1219 cur_pos = _tcslen(_T("\"\"=")) + _tcslen(_T("hex:")) +
1220 _tcslen(*val_name_buf);
1221 _fputts(hex_prefix, file);
1222 for (i1 = 0; i1 < val_size1; i1++) {
1223 _ftprintf(file, _T("%02x"), (unsigned int)(*val_buf)[i1]);
1224 if (i1 + 1 < val_size1) {
1225 _fputts(_T(","), file);
1226 }
1227 cur_pos += 3;
1228 /* wrap the line */
1229 if (cur_pos > REG_FILE_HEX_LINE_LEN) {
1230 _fputts(_T("\\\n "), file);
1231 cur_pos = 2;
1232 }
1233 }
1234 _fputts(_T("\n"), file);
1235 break;
1236 }
1237 }
1238 }
1239 }
1240 i = 0;
1241 more_data = TRUE;
1242 (*reg_key_name_buf)[curr_len] = _T('\\');
1243 while (more_data) {
1244 DWORD buf_len = *reg_key_name_len - curr_len;
1245 ret = RegEnumKeyEx(key, i, *reg_key_name_buf + curr_len + 1, &buf_len, NULL, NULL, NULL, NULL);
1246 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1247 more_data = FALSE;
1248 if (ret != ERROR_NO_MORE_ITEMS) {
1249 REGPROC_print_error();
1250 }
1251 } else {
1252 HKEY subkey;
1253
1254 i++;
1255 if (RegOpenKey(key, *reg_key_name_buf + curr_len + 1, &subkey) == ERROR_SUCCESS) {
1256 export_hkey(file, subkey, reg_key_name_buf, reg_key_name_len, val_name_buf, val_name_len, val_buf, val_size);
1257 RegCloseKey(subkey);
1258 } else {
1259 REGPROC_print_error();
1260 }
1261 }
1262 }
1263 (*reg_key_name_buf)[curr_len] = _T('\0');
1264 }
1265 /*
1266 #define REG_NONE ( 0 ) // No value type
1267 #define REG_SZ ( 1 ) // Unicode nul terminated string
1268 #define REG_EXPAND_SZ ( 2 ) // Unicode nul terminated string
1269 // (with environment variable references)
1270 #define REG_BINARY ( 3 ) // Free form binary
1271 #define REG_DWORD ( 4 ) // 32-bit number
1272 #define REG_DWORD_LITTLE_ENDIAN ( 4 ) // 32-bit number (same as REG_DWORD)
1273 #define REG_DWORD_BIG_ENDIAN ( 5 ) // 32-bit number
1274 #define REG_LINK ( 6 ) // Symbolic Link (unicode)
1275 #define REG_MULTI_SZ ( 7 ) // Multiple Unicode strings
1276 #define REG_RESOURCE_LIST ( 8 ) // Resource list in the resource map
1277 #define REG_FULL_RESOURCE_DESCRIPTOR ( 9 ) // Resource list in the hardware description
1278 #define REG_RESOURCE_REQUIREMENTS_LIST ( 10 )
1279
1280 */
1281 /******************************************************************************
1282 * Open file for export.
1283 */
1284 FILE *REGPROC_open_export_file(TCHAR *file_name)
1285 {
1286 //_CRTIMP FILE * __cdecl _wfopen(const wchar_t *, const wchar_t *);
1287
1288 //FILE* fopen (const char* szFileName, const char* szMode);
1289 //FILE* _wfopen(const wchar_t *file, const wchar_t *mode);
1290
1291 FILE *file = _tfopen(file_name, _T("w"));
1292 if (!file) {
1293 perror("");
1294 _tprintf(_T("REGPROC_open_export_file(%s) - Can't open file.\n"), file_name);
1295 //exit(1);
1296 return NULL;
1297 }
1298 _fputts(_T("REGEDIT4\n"), file);
1299 return file;
1300 }
1301
1302 /******************************************************************************
1303 * Writes contents of the registry key to the specified file stream.
1304 *
1305 * Parameters:
1306 * file_name - name of a file to export registry branch to.
1307 * reg_key_name - registry branch to export. The whole registry is exported if
1308 * reg_key_name is NULL or contains an empty string.
1309 */
1310 BOOL export_registry_key(TCHAR* file_name, TCHAR* reg_key_name)
1311 {
1312 HKEY reg_key_class;
1313
1314 TCHAR *reg_key_name_buf;
1315 TCHAR *val_name_buf;
1316 BYTE *val_buf;
1317 DWORD reg_key_name_len = KEY_MAX_LEN;
1318 DWORD val_name_len = KEY_MAX_LEN;
1319 DWORD val_size = REG_VAL_BUF_SIZE;
1320 FILE *file = NULL;
1321
1322 //_tprintf(_T("export_registry_key(%s, %s)\n"), reg_key_name, file_name);
1323
1324 reg_key_name_buf = HeapAlloc(GetProcessHeap(), 0, reg_key_name_len * sizeof(*reg_key_name_buf));
1325 val_name_buf = HeapAlloc(GetProcessHeap(), 0, val_name_len * sizeof(*val_name_buf));
1326 val_buf = HeapAlloc(GetProcessHeap(), 0, val_size);
1327 CHECK_ENOUGH_MEMORY(reg_key_name_buf && val_name_buf && val_buf);
1328
1329 if (reg_key_name && reg_key_name[0]) {
1330 TCHAR *branch_name;
1331 HKEY key;
1332
1333 REGPROC_resize_char_buffer(&reg_key_name_buf, &reg_key_name_len,
1334 _tcslen(reg_key_name));
1335 _tcscpy(reg_key_name_buf, reg_key_name);
1336
1337 /* open the specified key */
1338 reg_key_class = getRegClass(reg_key_name);
1339 if (reg_key_class == (HKEY)ERROR_INVALID_PARAMETER) {
1340 _tprintf(_T("Incorrect registry class specification in '%s\n"), reg_key_name);
1341 //exit(1);
1342 return FALSE;
1343 }
1344 branch_name = getRegKeyName(reg_key_name);
1345 CHECK_ENOUGH_MEMORY(branch_name);
1346 if (!branch_name[0]) {
1347 /* no branch - registry class is specified */
1348 file = REGPROC_open_export_file(file_name);
1349 export_hkey(file, reg_key_class,
1350 &reg_key_name_buf, &reg_key_name_len,
1351 &val_name_buf, &val_name_len,
1352 &val_buf, &val_size);
1353 } else if (RegOpenKey(reg_key_class, branch_name, &key) == ERROR_SUCCESS) {
1354 file = REGPROC_open_export_file(file_name);
1355 export_hkey(file, key,
1356 &reg_key_name_buf, &reg_key_name_len,
1357 &val_name_buf, &val_name_len,
1358 &val_buf, &val_size);
1359 RegCloseKey(key);
1360 } else {
1361 _tprintf(_T("Can't export. Registry key '%s does not exist!\n"), reg_key_name);
1362 REGPROC_print_error();
1363 }
1364 HeapFree(GetProcessHeap(), 0, branch_name);
1365 } else {
1366 int i;
1367
1368 /* export all registry classes */
1369 file = REGPROC_open_export_file(file_name);
1370 for (i = 0; i < REG_CLASS_NUMBER; i++) {
1371 /* do not export HKEY_CLASSES_ROOT */
1372 if (reg_class_keys[i] != HKEY_CLASSES_ROOT &&
1373 reg_class_keys[i] != HKEY_CURRENT_USER &&
1374 reg_class_keys[i] != HKEY_CURRENT_CONFIG) {
1375 _tcscpy(reg_key_name_buf, reg_class_names[i]);
1376 export_hkey(file, reg_class_keys[i],
1377 &reg_key_name_buf, &reg_key_name_len,
1378 &val_name_buf, &val_name_len,
1379 &val_buf, &val_size);
1380 }
1381 }
1382 }
1383 if (file) {
1384 fclose(file);
1385 }
1386 // HeapFree(GetProcessHeap(), 0, reg_key_name);
1387 HeapFree(GetProcessHeap(), 0, val_buf);
1388 HeapFree(GetProcessHeap(), 0, val_name_buf);
1389 HeapFree(GetProcessHeap(), 0, reg_key_name_buf);
1390 return TRUE;
1391 }
1392
1393 /******************************************************************************
1394 * Reads contents of the specified file into the registry.
1395 */
1396 BOOL import_registry_file(LPTSTR filename)
1397 {
1398 FILE* reg_file = _tfopen(filename, _T("r"));
1399
1400 if (reg_file) {
1401 processRegLines(reg_file, doSetValue);
1402 return TRUE;
1403 }
1404 return FALSE;
1405 }
1406
1407 /******************************************************************************
1408 * Recursive function which removes the registry key with all subkeys.
1409 */
1410 BOOL delete_branch(HKEY key, TCHAR** reg_key_name_buf, DWORD* reg_key_name_len)
1411 {
1412 HKEY branch_key;
1413 DWORD max_sub_key_len;
1414 DWORD subkeys;
1415 DWORD curr_len;
1416 LONG ret;
1417 long int i;
1418
1419 if (RegOpenKey(key, *reg_key_name_buf, &branch_key) != ERROR_SUCCESS) {
1420 REGPROC_print_error();
1421 return FALSE;
1422 }
1423
1424 /* get size information and resize the buffers if necessary */
1425 if (RegQueryInfoKey(branch_key, NULL, NULL, NULL, &subkeys, &max_sub_key_len,
1426 NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
1427 REGPROC_print_error();
1428 RegCloseKey(branch_key);
1429 return FALSE;
1430 }
1431 curr_len = _tcslen(*reg_key_name_buf);
1432 REGPROC_resize_char_buffer(reg_key_name_buf, reg_key_name_len, max_sub_key_len + curr_len + 1);
1433
1434 (*reg_key_name_buf)[curr_len] = '\\';
1435 for (i = subkeys - 1; i >= 0; i--) {
1436 DWORD buf_len = *reg_key_name_len - curr_len;
1437 ret = RegEnumKeyEx(branch_key, i, *reg_key_name_buf + curr_len + 1, &buf_len, NULL, NULL, NULL, NULL);
1438 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA && ret != ERROR_NO_MORE_ITEMS) {
1439 REGPROC_print_error();
1440 RegCloseKey(branch_key);
1441 return FALSE;
1442 } else {
1443 delete_branch(key, reg_key_name_buf, reg_key_name_len);
1444 }
1445 }
1446 (*reg_key_name_buf)[curr_len] = '\0';
1447 RegCloseKey(branch_key);
1448 RegDeleteKey(key, *reg_key_name_buf);
1449 return TRUE;
1450 }
1451
1452 /******************************************************************************
1453 * Removes the registry key with all subkeys. Parses full key name.
1454 *
1455 * Parameters:
1456 * reg_key_name - full name of registry branch to delete. Ignored if is NULL,
1457 * empty, points to register key class, does not exist.
1458 */
1459 void delete_registry_key(TCHAR* reg_key_name)
1460 {
1461 TCHAR* branch_name;
1462 DWORD branch_name_len;
1463 HKEY reg_key_class;
1464 HKEY branch_key;
1465
1466 if (!reg_key_name || !reg_key_name[0]) {
1467 return;
1468 }
1469 /* open the specified key */
1470 reg_key_class = getRegClass(reg_key_name);
1471 if (reg_key_class == (HKEY)ERROR_INVALID_PARAMETER) {
1472 _tprintf(_T("Incorrect registry class specification in '%s'\n"), reg_key_name);
1473 //exit(1);
1474 return;
1475 }
1476 branch_name = getRegKeyName(reg_key_name);
1477 CHECK_ENOUGH_MEMORY(branch_name);
1478 branch_name_len = _tcslen(branch_name);
1479 if (!branch_name[0]) {
1480 _tprintf(_T("Can't delete registry class '%s'\n"), reg_key_name);
1481 //exit(1);
1482 return;
1483 }
1484 if (RegOpenKey(reg_key_class, branch_name, &branch_key) == ERROR_SUCCESS) {
1485 /* check whether the key exists */
1486 RegCloseKey(branch_key);
1487 delete_branch(reg_key_class, &branch_name, &branch_name_len);
1488 }
1489 HeapFree(GetProcessHeap(), 0, branch_name);
1490 }
1491