Release 980301
[wine] / misc / registry.c
1 /*
2  *      Registry Functions
3  *
4  * Copyright 1996 Marcus Meissner
5  *
6  * December 21, 1997 - Kevin Cozens
7  * Fixed bugs in the _w95_loadreg() function. Added extra information
8  * regarding the format of the Windows '95 registry files.
9  */
10
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <ctype.h>
16 #include <errno.h>
17 #include <sys/types.h>
18 #include <sys/fcntl.h>
19 #include <sys/stat.h>
20 #include <pwd.h>
21 #include <assert.h>
22 #include <time.h>
23 #include "windows.h"
24 #include "win.h"
25 #include "winerror.h"
26 #include "file.h"
27 #include "heap.h"
28 #include "debug.h"
29 #include "xmalloc.h"
30 #include "winreg.h"
31
32 #define DEBUG_W95_LOADREG       0
33
34 /* FIXME: following defines should be configured global ... */
35
36 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
37 #define WINE_PREFIX                     "/.wine"
38 #define SAVE_USERS_DEFAULT              "/usr/local/etc/wine.userreg"
39 #define SAVE_LOCAL_MACHINE_DEFAULT      "/usr/local/etc/wine.systemreg"
40
41 /* relative in ~user/.wine/ : */
42 #define SAVE_CURRENT_USER               "user.reg"
43 #define SAVE_LOCAL_MACHINE              "system.reg"
44
45 #define KEY_REGISTRY    "Software\\The WINE team\\WINE\\Registry"
46 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
47
48 /* one value of a key */
49 typedef struct tagKEYVALUE
50 {
51     LPWSTR   name;          /* name of value (UNICODE) or NULL for win31 */
52     DWORD    type;          /* type of value */
53     DWORD    len;           /* length of data */
54     DWORD    lastmodified;  /* time of seconds since 1.1.1970 */
55     LPBYTE   data;          /* content, may be strings, binaries, etc. */
56 } KEYVALUE,*LPKEYVALUE;
57
58 /* a registry key */
59 typedef struct tagKEYSTRUCT
60 {
61     LPWSTR               keyname;       /* name of THIS key (UNICODE) */
62     DWORD                flags;         /* flags. */
63     LPWSTR               class;
64     /* values */
65     DWORD                nrofvalues;    /* nr of values in THIS key */
66     LPKEYVALUE           values;        /* values in THIS key */
67     /* key management pointers */
68     struct tagKEYSTRUCT *next;          /* next key on same hierarchy */
69     struct tagKEYSTRUCT *nextsub;       /* keys that hang below THIS key */
70 } KEYSTRUCT, *LPKEYSTRUCT;
71
72
73 static KEYSTRUCT        *key_classes_root=NULL; /* windows 3.1 global values */
74 static KEYSTRUCT        *key_current_user=NULL; /* user specific values */
75 static KEYSTRUCT        *key_local_machine=NULL;/* machine specific values */
76 static KEYSTRUCT        *key_users=NULL;        /* all users? */
77
78 /* dynamic, not saved */
79 static KEYSTRUCT        *key_performance_data=NULL;
80 static KEYSTRUCT        *key_current_config=NULL;
81 static KEYSTRUCT        *key_dyn_data=NULL;
82
83 /* what valuetypes do we need to convert? */
84 #define UNICONVMASK     ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
85
86 extern LPWSTR __cdecl CRTDLL_wcschr(LPWSTR a,WCHAR c);
87
88 static LPWSTR strdupA2W(LPCSTR src)
89 {
90         LPWSTR dest=xmalloc(2*strlen(src)+2);
91         lstrcpyAtoW(dest,src);
92         return dest;
93 }
94
95 static LPWSTR strdupW(LPCWSTR a) {
96         LPWSTR  b;
97         int     len;
98
99         len=sizeof(WCHAR)*(lstrlen32W(a)+1);
100         b=(LPWSTR)xmalloc(len);
101         memcpy(b,a,len);
102         return b;
103 }
104
105
106 static struct openhandle {
107         LPKEYSTRUCT     lpkey;
108         HKEY            hkey;
109         REGSAM          accessmask;
110 }  *openhandles=NULL;
111 static int      nrofopenhandles=0;
112 static int      currenthandle=1;
113
114 static void
115 add_handle(HKEY hkey,LPKEYSTRUCT lpkey,REGSAM accessmask) {
116         int     i;
117
118         for (i=0;i<nrofopenhandles;i++) {
119                 if (openhandles[i].lpkey==lpkey) {
120                         dprintf_warn(reg, "add_handle:Tried to add %p twice!\n",lpkey);
121                 }
122                 if (openhandles[i].hkey==hkey) {
123                         dprintf_warn(reg, "add_handle:Tried to add %lx twice!\n",(LONG)hkey);
124                 }
125         }
126         openhandles=xrealloc(   openhandles,
127                                 sizeof(struct openhandle)*(nrofopenhandles+1)
128                 );
129         openhandles[i].lpkey    = lpkey;
130         openhandles[i].hkey     = hkey;
131         openhandles[i].accessmask= accessmask;
132         nrofopenhandles++;
133 }
134
135 static LPKEYSTRUCT
136 get_handle(HKEY hkey) {
137         int     i;
138
139         for (i=0;i<nrofopenhandles;i++)
140                 if (openhandles[i].hkey==hkey)
141                         return openhandles[i].lpkey;
142         dprintf_warn(reg, "get_handle:Didn't find handle %lx?\n",(LONG)hkey);
143         return NULL;
144 }
145
146 static void
147 remove_handle(HKEY hkey) {
148         int     i;
149
150         for (i=0;i<nrofopenhandles;i++)
151                 if (openhandles[i].hkey==hkey)
152                         break;
153         if (i==nrofopenhandles) {
154                 dprintf_warn(reg, "remove_handle:Didn't find handle %08x?\n",hkey);
155                 return;
156         }
157         memcpy( openhandles+i,
158                 openhandles+i+1,
159                 sizeof(struct openhandle)*(nrofopenhandles-i-1)
160         );
161         openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
162         nrofopenhandles--;
163         return;
164 }
165
166
167 /* debug function, converts a unicode into a static memory area 
168  * (sub for using two static strings, in case we need them in a single call)
169  */
170 LPSTR
171 W2C(LPCWSTR x,int sub) {
172         static  LPSTR   unicodedebug[2]={NULL,NULL};
173         if (x==NULL)
174                 return "<NULL>";
175         if (sub!=0 && sub!=1)
176                 return "<W2C:bad sub>";
177         if (unicodedebug[sub]) HeapFree( SystemHeap, 0, unicodedebug[sub] );
178         unicodedebug[sub] = HEAP_strdupWtoA( SystemHeap, 0, x );
179         return unicodedebug[sub];
180 }
181
182 static LPKEYSTRUCT
183 lookup_hkey(HKEY hkey) {
184         switch (hkey) {
185         case 0x00000000:
186         case 0x00000001:
187         case HKEY_CLASSES_ROOT:
188                 return key_classes_root;
189         case HKEY_CURRENT_USER:
190                 return key_current_user;
191         case HKEY_LOCAL_MACHINE:
192                 return key_local_machine;
193         case HKEY_USERS:
194                 return key_users;
195         case HKEY_PERFORMANCE_DATA:
196                 return key_performance_data;
197         case HKEY_DYN_DATA:
198                 return key_dyn_data;
199         case HKEY_CURRENT_CONFIG:
200                 return key_current_config;
201         default:
202                 dprintf_warn(reg, "lookup_hkey(%lx), special key!\n",
203                         (LONG)hkey
204                 );
205                 return get_handle(hkey);
206         }
207         /*NOTREACHED*/
208 }
209
210 /* 
211  * splits the unicode string 'wp' into an array of strings.
212  * the array is allocated by this function. 
213  * the number of components will be stored in 'wpc'
214  * Free the array using FREE_KEY_PATH
215  */
216 static void
217 split_keypath(LPCWSTR wp,LPWSTR **wpv,int *wpc) {
218         int     i,j,len;
219         LPWSTR  ws;
220
221         ws      = HEAP_strdupW( SystemHeap, 0, wp );
222         *wpc    = 1;
223         for (i=0;ws[i];i++) {
224                 if (ws[i]=='\\') {
225                         ws[i]=0;
226                         (*wpc)++;
227                 }
228         }
229         len     = i;
230         *wpv    = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
231         (*wpv)[0]= ws;
232         j       = 1;
233         for (i=1;i<len;i++)
234                 if (ws[i-1]==0)
235                         (*wpv)[j++]=ws+i;
236         (*wpv)[j]=NULL;
237 }
238 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
239
240 /*
241  * Shell initialisation, allocates keys. 
242  */
243 void SHELL_StartupRegistry();
244 void
245 SHELL_Init() {
246         struct  passwd  *pwd;
247
248         HKEY    cl_r_hkey,c_u_hkey;
249 #define ADD_ROOT_KEY(xx) \
250         xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
251         memset(xx,'\0',sizeof(KEYSTRUCT));\
252         xx->keyname= strdupA2W("<should_not_appear_anywhere>");
253
254         ADD_ROOT_KEY(key_local_machine);
255         if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
256                 fprintf(stderr,"couldn't create HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes. This is impossible.\n");
257                 exit(1);
258         }
259         key_classes_root = lookup_hkey(cl_r_hkey);
260
261         ADD_ROOT_KEY(key_users);
262
263 #if 0
264         /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg 
265          *        (later, when a win32 registry editing tool becomes avail.)
266          */
267         while (pwd=getpwent()) {
268                 if (pwd->pw_name == NULL)
269                         continue;
270                 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
271                 RegCloseKey(c_u_hkey);
272         }
273 #endif
274         pwd=getpwuid(getuid());
275         if (pwd && pwd->pw_name) {
276                 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
277                 key_current_user = lookup_hkey(c_u_hkey);
278         } else {
279                 ADD_ROOT_KEY(key_current_user);
280         }
281         ADD_ROOT_KEY(key_performance_data);
282         ADD_ROOT_KEY(key_current_config);
283         ADD_ROOT_KEY(key_dyn_data);
284 #undef ADD_ROOT_KEY
285         SHELL_StartupRegistry();
286 }
287
288
289 void
290 SHELL_StartupRegistry() {
291         HKEY    hkey;
292         char    buf[200];
293
294         RegCreateKey16(HKEY_DYN_DATA,"\\PerfStats\\StatData",&hkey);
295         RegCloseKey(hkey);
296
297         RegOpenKey16(HKEY_LOCAL_MACHINE,"\\HARDWARE\\DESCRIPTION\\System",&hkey);
298         RegSetValueEx32A(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
299         RegCloseKey(hkey);
300         /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
301          *                                              CurrentVersion
302          *                                              CurrentBuildNumber
303          *                                              CurrentType
304          *                                      string  RegisteredOwner
305          *                                      string  RegisteredOrganization
306          *
307          */
308         /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
309          *                                      string  SysContact
310          *                                      string  SysLocation
311          *                                              SysServices
312          */                                             
313         if (-1!=gethostname(buf,200)) {
314                 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
315                 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
316                 RegCloseKey(hkey);
317         }
318 }
319 /************************ SAVE Registry Function ****************************/
320
321 #define REGISTRY_SAVE_VERSION   0x00000001
322
323 /* Registry saveformat:
324  * If you change it, increase above number by 1, which will flush
325  * old registry database files.
326  * 
327  * Global:
328  *      "WINE REGISTRY Version %d"
329  *      subkeys....
330  * Subkeys:
331  *      keyname
332  *              valuename=lastmodified,type,data
333  *              ...
334  *              subkeys
335  *      ...
336  * keyname,valuename,stringdata:
337  *      the usual ascii characters from 0x00-0xff (well, not 0x00)
338  *      and \uXXXX as UNICODE value XXXX with XXXX>0xff
339  *      ( "=\\\t" escaped in \uXXXX form.)
340  * type,lastmodified: 
341  *      int
342  * 
343  * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
344  *
345  * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
346  * SaveOnlyUpdatedKeys=yes
347  */
348 static int
349 _save_check_tainted(LPKEYSTRUCT lpkey) {
350         int             tainted;
351
352         if (!lpkey)
353                 return 0;
354         if (lpkey->flags & REG_OPTION_TAINTED)
355                 tainted = 1;
356         else
357                 tainted = 0;
358         while (lpkey) {
359                 if (_save_check_tainted(lpkey->nextsub)) {
360                         lpkey->flags |= REG_OPTION_TAINTED;
361                         tainted = 1;
362                 }
363                 lpkey   = lpkey->next;
364         }
365         return tainted;
366 }
367
368 static void
369 _save_USTRING(FILE *F,LPWSTR wstr,int escapeeq) {
370         LPWSTR  s;
371         int     doescape;
372
373         if (wstr==NULL)
374                 return;
375         s=wstr;
376         while (*s) {
377                 doescape=0;
378                 if (*s>0xff)
379                         doescape = 1;
380                 if (*s=='\n')
381                         doescape = 1;
382                 if (escapeeq && *s=='=')
383                         doescape = 1;
384                 if (*s=='\\')
385                         fputc(*s,F); /* if \\ then put it twice. */
386                 if (doescape)
387                         fprintf(F,"\\u%04x",*((unsigned short*)s));
388                 else
389                         fputc(*s,F);
390                 s++;
391         }
392 }
393
394 static int
395 _savesubkey(FILE *F,LPKEYSTRUCT lpkey,int level,int all) {
396         LPKEYSTRUCT     lpxkey;
397         int             i,tabs,j;
398
399         lpxkey  = lpkey;
400         while (lpxkey) {
401                 if (    !(lpxkey->flags & REG_OPTION_VOLATILE) &&
402                         (all || (lpxkey->flags & REG_OPTION_TAINTED))
403                 ) {
404                         for (tabs=level;tabs--;)
405                                 fputc('\t',F);
406                         _save_USTRING(F,lpxkey->keyname,1);
407                         fputs("\n",F);
408                         for (i=0;i<lpxkey->nrofvalues;i++) {
409                                 LPKEYVALUE      val=lpxkey->values+i;
410
411                                 for (tabs=level+1;tabs--;)
412                                         fputc('\t',F);
413                                 _save_USTRING(F,val->name,0);
414                                 fputc('=',F);
415                                 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
416                                 if ((1<<val->type) & UNICONVMASK)
417                                         _save_USTRING(F,(LPWSTR)val->data,0);
418                                 else
419                                         for (j=0;j<val->len;j++)
420                                                 fprintf(F,"%02x",*((unsigned char*)val->data+j));
421                                 fputs("\n",F);
422                         }
423                         /* descend recursively */
424                         if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
425                                 return 0;
426                 }
427                 lpxkey=lpxkey->next;
428         }
429         return 1;
430 }
431
432 static int
433 _savesubreg(FILE *F,LPKEYSTRUCT lpkey,int all) {
434         fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
435         _save_check_tainted(lpkey->nextsub);
436         return _savesubkey(F,lpkey->nextsub,0,all);
437 }
438
439 static BOOL32
440 _savereg(LPKEYSTRUCT lpkey,char *fn,int all) {
441         FILE    *F;
442
443         F=fopen(fn,"w");
444         if (F==NULL) {
445                 fprintf(stddeb,__FILE__":_savereg:Couldn't open %s for writing: %s\n",
446                         fn,strerror(errno)
447                 );
448                 return FALSE;
449         }
450         if (!_savesubreg(F,lpkey,all)) {
451                 fclose(F);
452                 unlink(fn);
453                 fprintf(stddeb,__FILE__":_savereg:Failed to save keys, perhaps no more diskspace for %s?\n",fn);
454                 return FALSE;
455         }
456         fclose(F);
457         return TRUE;
458 }
459
460 void
461 SHELL_SaveRegistry() {
462         char    *fn;
463         struct  passwd  *pwd;
464         char    buf[4];
465         HKEY    hkey;
466         int     all;
467
468         all=0;
469         if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
470                 strcpy(buf,"yes");
471         } else {
472                 DWORD len,junk,type;
473
474                 len=4;
475                 if (    (ERROR_SUCCESS!=RegQueryValueEx32A(
476                                 hkey,
477                                 VAL_SAVEUPDATED,
478                                 &junk,
479                                 &type,
480                                 buf,
481                                 &len
482                         ))|| (type!=REG_SZ)
483                 )
484                         strcpy(buf,"yes");
485                 RegCloseKey(hkey);
486         }
487         if (lstrcmpi32A(buf,"yes"))
488                 all=1;
489         pwd=getpwuid(getuid());
490         if (pwd!=NULL && pwd->pw_dir!=NULL)
491         {
492                 char *tmp;
493
494                 fn=(char*)xmalloc( strlen(pwd->pw_dir) + strlen(WINE_PREFIX) +
495                                    strlen(SAVE_CURRENT_USER) + 2 );
496                 strcpy(fn,pwd->pw_dir);
497                 strcat(fn,WINE_PREFIX);
498                 /* create the directory. don't care about errorcodes. */
499                 mkdir(fn,0755); /* drwxr-xr-x */
500                 strcat(fn,"/"SAVE_CURRENT_USER);
501                 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
502                 strcpy(tmp,fn);strcat(tmp,".tmp");
503                 if (_savereg(key_current_user,tmp,all)) {
504                         if (-1==rename(tmp,fn)) {
505                                 perror("rename tmp registry");
506                                 unlink(tmp);
507                         }
508                 }
509                 free(tmp);
510                 free(fn);
511                 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
512                 strcpy(fn,pwd->pw_dir);
513                 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
514                 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
515                 strcpy(tmp,fn);strcat(tmp,".tmp");
516                 if (_savereg(key_local_machine,tmp,all)) {
517                         if (-1==rename(tmp,fn)) {
518                                 perror("rename tmp registry");
519                                 unlink(tmp);
520                         }
521                 }
522                 free(tmp);
523                 free(fn);
524         } else
525                 fprintf(stderr,"SHELL_SaveRegistry:failed to get homedirectory of UID %d.\n",getuid());
526 }
527
528 /************************ LOAD Registry Function ****************************/
529
530 static LPKEYSTRUCT
531 _find_or_add_key(LPKEYSTRUCT lpkey,LPWSTR keyname) {
532         LPKEYSTRUCT     lpxkey,*lplpkey;
533
534         if (keyname[0]==0) {
535                 free(keyname);
536                 return lpkey;
537         }
538         lplpkey= &(lpkey->nextsub);
539         lpxkey  = *lplpkey;
540         while (lpxkey) {
541                 if (!lstrcmpi32W(lpxkey->keyname,keyname))
542                         break;
543                 lplpkey = &(lpxkey->next);
544                 lpxkey  = *lplpkey;
545         }
546         if (lpxkey==NULL) {
547                 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
548                 lpxkey  = *lplpkey;
549                 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
550                 lpxkey->keyname = keyname;
551         } else
552                 free(keyname);
553         return lpxkey;
554 }
555
556 static void
557 _find_or_add_value(
558         LPKEYSTRUCT lpkey,LPWSTR name,DWORD type,LPBYTE data,DWORD len,
559         DWORD lastmodified
560 ) {
561         LPKEYVALUE      val=NULL;
562         int             i;
563
564         if (name && !*name) {/* empty string equals default (NULL) value */
565                 free(name);
566                 name = NULL;
567         }
568
569         for (i=0;i<lpkey->nrofvalues;i++) {
570                 val=lpkey->values+i;
571                 if (name==NULL) {
572                         if (val->name==NULL)
573                                 break;
574                 } else {
575                         if (    val->name!=NULL && 
576                                 !lstrcmpi32W(val->name,name)
577                         )
578                                 break;
579                 }
580         }
581         if (i==lpkey->nrofvalues) {
582                 lpkey->values = xrealloc(
583                         lpkey->values,
584                         (++lpkey->nrofvalues)*sizeof(KEYVALUE)
585                 );
586                 val=lpkey->values+i;
587                 memset(val,'\0',sizeof(KEYVALUE));
588                 val->name = name;
589         } else {
590                 if (name)
591                         free(name);
592         }
593         if (val->lastmodified<lastmodified) {
594                 val->lastmodified=lastmodified;
595                 val->type = type;
596                 val->len  = len;
597                 if (val->data) 
598                         free(val->data);
599                 val->data = data;
600         } else
601                 free(data);
602 }
603
604
605 /* reads a line including dynamically enlarging the readbuffer and throwing
606  * away comments
607  */
608 static int 
609 _wine_read_line(FILE *F,char **buf,int *len) {
610         char    *s,*curread;
611         int     mylen,curoff;
612
613         curread = *buf;
614         mylen   = *len;
615         **buf   = '\0';
616         while (1) {
617                 while (1) {
618                         s=fgets(curread,mylen,F);
619                         if (s==NULL)
620                                 return 0; /* EOF */
621                         if (NULL==(s=strchr(curread,'\n'))) {
622                                 /* buffer wasn't large enough */
623                                 curoff  = strlen(*buf);
624                                 *buf    = xrealloc(*buf,*len*2);
625                                 curread = *buf + curoff;
626                                 mylen   = *len; /* we filled up the buffer and 
627                                                  * got new '*len' bytes to fill
628                                                  */
629                                 *len    = *len * 2;
630                         } else {
631                                 *s='\0';
632                                 break;
633                         }
634                 }
635                 /* throw away comments */
636                 if (**buf=='#' || **buf==';') {
637                         curread = *buf;
638                         mylen   = *len;
639                         continue;
640                 }
641                 if (s)  /* got end of line */
642                         break;
643         }
644         return 1;
645 }
646
647 /* converts a char* into a UNICODE string (up to a special char)
648  * and returns the position exactly after that string
649  */
650 static char*
651 _wine_read_USTRING(char *buf,LPWSTR *str) {
652         char    *s;
653         LPWSTR  ws;
654
655         /* read up to "=" or "\0" or "\n" */
656         s       = buf;
657         if (*s == '=') {
658                 /* empty string is the win3.1 default value(NULL)*/
659                 *str    = NULL;
660                 return s;
661         }
662         *str    = (LPWSTR)xmalloc(2*strlen(buf)+2);
663         ws      = *str;
664         while (*s && (*s!='\n') && (*s!='=')) {
665                 if (*s!='\\')
666                         *ws++=*((unsigned char*)s++);
667                 else {
668                         s++;
669                         if (*s=='\\') {
670                                 *ws++='\\';
671                                 s++;
672                                 continue;
673                         }
674                         if (*s!='u') {
675                                 fprintf(stderr,"_wine_read_USTRING:Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
676                                 *ws++='\\';
677                                 *ws++=*s++;
678                         } else {
679                                 char    xbuf[5];
680                                 int     wc;
681
682                                 s++;
683                                 memcpy(xbuf,s,4);xbuf[4]='\0';
684                                 if (!sscanf(xbuf,"%x",&wc))
685                                         fprintf(stderr,"_wine_read_USTRING:strange escape sequence %s found in |%s|\n",xbuf,buf);
686                                 s+=4;
687                                 *ws++   =(unsigned short)wc;
688                         }
689                 }
690         }
691         *ws     = 0;
692         ws      = *str;
693         if (*ws)
694                 *str    = strdupW(*str);
695         else
696                 *str    = NULL;
697         free(ws);
698         return s;
699 }
700
701 static int
702 _wine_loadsubkey(
703         FILE *F,LPKEYSTRUCT lpkey,int level,char **buf,int *buflen,int optflag
704 ) {
705         LPKEYSTRUCT     lpxkey;
706         int             i;
707         char            *s;
708         LPWSTR          name;
709
710         lpkey->flags |= optflag;
711
712         /* good. we already got a line here ... so parse it */
713         lpxkey  = NULL;
714         while (1) {
715                 i=0;s=*buf;
716                 while (*s=='\t') {
717                         s++;
718                         i++;
719                 }
720                 if (i>level) {
721                         if (lpxkey==NULL) {
722                                 fprintf(stderr,"_load_subkey:Got a subhierarchy without resp. key?\n");
723                                 return 0;
724                         }
725                         _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
726                         continue;
727                 }
728                 /* let the caller handle this line */
729                 if (i<level || **buf=='\0')
730                         return 1;
731
732                 /* it can be: a value or a keyname. Parse the name first */
733                 s=_wine_read_USTRING(s,&name);
734
735                 /* switch() default: hack to avoid gotos */
736                 switch (0) {
737                 default:
738                         if (*s=='\0') {
739                                 lpxkey=_find_or_add_key(lpkey,name);
740                         } else {
741                                 LPBYTE          data;
742                                 int             len,lastmodified,type;
743
744                                 if (*s!='=') {
745                                         fprintf(stderr,"_wine_load_subkey:unexpected character: %c\n",*s);
746                                         break;
747                                 }
748                                 s++;
749                                 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
750                                         fprintf(stderr,"_wine_load_subkey: haven't understood possible value in |%s|, skipping.\n",*buf);
751                                         break;
752                                 }
753                                 /* skip the 2 , */
754                                 s=strchr(s,',');s++;
755                                 s=strchr(s,',');s++;
756                                 if ((1<<type) & UNICONVMASK) {
757                                         s=_wine_read_USTRING(s,(LPWSTR*)&data);
758                                         if (data)
759                                                 len = lstrlen32W((LPWSTR)data)*2+2;
760                                         else    
761                                                 len = 0;
762                                 } else {
763                                         len=strlen(s)/2;
764                                         data = (LPBYTE)xmalloc(len+1);
765                                         for (i=0;i<len;i++) {
766                                                 data[i]=0;
767                                                 if (*s>='0' && *s<='9')
768                                                         data[i]=(*s-'0')<<4;
769                                                 if (*s>='a' && *s<='f')
770                                                         data[i]=(*s-'a')<<4;
771                                                 if (*s>='A' && *s<='F')
772                                                         data[i]=(*s-'A')<<4;
773                                                 s++;
774                                                 if (*s>='0' && *s<='9')
775                                                         data[i]|=*s-'0';
776                                                 if (*s>='a' && *s<='f')
777                                                         data[i]|=*s-'a';
778                                                 if (*s>='A' && *s<='F')
779                                                         data[i]|=*s-'A';
780                                                 s++;
781                                         }
782                                 }
783                                 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
784                         }
785                 }
786                 /* read the next line */
787                 if (!_wine_read_line(F,buf,buflen))
788                         return 1;
789         }
790         return 1;
791 }
792
793 static int
794 _wine_loadsubreg(FILE *F,LPKEYSTRUCT lpkey,int optflag) {
795         int     ver;
796         char    *buf;
797         int     buflen;
798
799         buf=xmalloc(10);buflen=10;
800         if (!_wine_read_line(F,&buf,&buflen)) {
801                 free(buf);
802                 return 0;
803         }
804         if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
805                 free(buf);
806                 return 0;
807         }
808         if (ver!=REGISTRY_SAVE_VERSION) {
809                 dprintf_info(reg,__FILE__":_wine_loadsubreg:Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
810                 free(buf);
811                 return 0;
812         }
813         if (!_wine_read_line(F,&buf,&buflen)) {
814                 free(buf);
815                 return 0;
816         }
817         if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
818                 free(buf);
819                 return 0;
820         }
821         free(buf);
822         return 1;
823 }
824
825 static void
826 _wine_loadreg(LPKEYSTRUCT lpkey,char *fn,int optflag) {
827         FILE    *F;
828
829         F=fopen(fn,"rb");
830         if (F==NULL) {
831                 dprintf_warn(reg,"Couldn't open %s for reading: %s\n",
832                        fn,strerror(errno)
833                 );
834                 return;
835         }
836         if (!_wine_loadsubreg(F,lpkey,optflag)) {
837                 fclose(F);
838                 unlink(fn);
839                 return;
840         }
841         fclose(F);
842 }
843
844 static void
845 _copy_registry(LPKEYSTRUCT from,LPKEYSTRUCT to) {
846         LPKEYSTRUCT     lpxkey;
847         int             j;
848         LPKEYVALUE      valfrom;
849
850         from=from->nextsub;
851         while (from) {
852                 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
853
854                 for (j=0;j<from->nrofvalues;j++) {
855                         LPWSTR  name;
856                         LPBYTE  data;
857
858                         valfrom = from->values+j;
859                         name=valfrom->name;
860                         if (name) name=strdupW(name);
861                         data=(LPBYTE)xmalloc(valfrom->len);
862                         memcpy(data,valfrom->data,valfrom->len);
863
864                         _find_or_add_value(
865                                 lpxkey,
866                                 name,
867                                 valfrom->type,
868                                 data,
869                                 valfrom->len,
870                                 valfrom->lastmodified
871                         );
872                 }
873                 _copy_registry(from,lpxkey);
874                 from = from->next;
875         }
876 }
877
878 /* WINDOWS 95 REGISTRY LOADER */
879 /* 
880  * Structure of a win95 registry database.
881  * main header:
882  * 0 :  "CREG"  - magic
883  * 4 :  DWORD version
884  * 8 :  DWORD offset_of_RGDB_part
885  * 0C..0F:      ? (someone fill in please)
886  * 10:  WORD    number of RGDB blocks
887  * 12:  WORD    ?
888  * 14:  WORD    always 0000?
889  * 16:  WORD    always 0001?
890  * 18..1F:      ? (someone fill in please)
891  *
892  * 20: RGKN_section:
893  *   header:
894  *      0 :             "RGKN"  - magic
895  *      4 : DWORD       offset to first RGDB section
896  *      8 : DWORD       offset to ?
897  *      C..0x1B:        ? (fill in)
898  *      0x20 ... offset_of_RGDB_part: Disk Key Entry structures
899  *
900  *   Disk Key Entry Structure:
901  *      00: DWORD       - Free entry indicator(?)
902  *      04: DWORD       - Hash = sum of bytes of keyname
903  *      08: DWORD       - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
904  *      0C: DWORD       - disk address of PreviousLevel Key.
905  *      10: DWORD       - disk address of Next Sublevel Key.
906  *      14: DWORD       - disk address of Next Key (on same level).
907  * DKEP>18: WORD        - Nr, Low Significant part.
908  *      1A: WORD        - Nr, High Significant part.
909  *
910  * The disk address always points to the nr part of the previous key entry 
911  * of the referenced key. Don't ask me why, or even if I got this correct
912  * from staring at 1kg of hexdumps. (DKEP)
913  *
914  * The High significant part of the structure seems to equal the number
915  * of the RGDB section. The low significant part is a unique ID within
916  * that RGDB section
917  *
918  * There are two minor corrections to the position of that structure.
919  * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND 
920  *    the DKE reread from there.
921  * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
922  * CPS - I have not experienced the above phenomenon in my registry files
923  *
924  * RGDB_section:
925  *      00:             "RGDB"  - magic
926  *      04: DWORD       offset to next RGDB section
927  *      08: DWORD       ?
928  *      0C: WORD        always 000d?
929  *      0E: WORD        RGDB block number
930  *      10:     DWORD   ? (equals value at offset 4 - value at offset 8)
931  *      14..1F:         ?
932  *      20.....:        disk keys
933  *
934  * disk key:
935  *      00:     DWORD   nextkeyoffset   - offset to the next disk key structure
936  *      08:     WORD    nrLS            - low significant part of NR
937  *      0A:     WORD    nrHS            - high significant part of NR
938  *      0C:     DWORD   bytesused       - bytes used in this structure.
939  *      10:     WORD    name_len        - length of name in bytes. without \0
940  *      12:     WORD    nr_of_values    - number of values.
941  *      14:     char    name[name_len]  - name string. No \0.
942  *      14+name_len: disk values
943  *      nextkeyoffset: ... next disk key
944  *
945  * disk value:
946  *      00:     DWORD   type            - value type (hmm, could be WORD too)
947  *      04:     DWORD                   - unknown, usually 0
948  *      08:     WORD    namelen         - length of Name. 0 means name=NULL
949  *      0C:     WORD    datalen         - length of Data.
950  *      10:     char    name[namelen]   - name, no \0
951  *      10+namelen: BYTE        data[datalen] - data, without \0 if string
952  *      10+namelen+datalen: next values or disk key
953  *
954  * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
955  * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
956  * structure) and reading another RGDB_section.
957  * repeat until end of file.
958  *
959  * An interesting relationship exists in RGDB_section. The value at offset
960  * 10 equals the value at offset 4 minus the value at offset 8. I have no
961  * idea at the moment what this means.  (Kevin Cozens)
962  *
963  * FIXME: this description needs some serious help, yes.
964  */
965
966 struct  _w95keyvalue {
967         unsigned long           type;
968         unsigned short          datalen;
969         char                    *name;
970         unsigned char           *data;
971         unsigned long           x1;
972         int                     lastmodified;
973 };
974
975 struct  _w95key {
976         char                    *name;
977         int                     nrofvals;
978         struct  _w95keyvalue    *values;
979         struct _w95key          *prevlvl;
980         struct _w95key          *nextsub;
981         struct _w95key          *next;
982 };
983
984
985 struct _w95_info {
986   char *rgknbuffer;
987   int  rgknsize;
988   char *rgdbbuffer;
989   int  rgdbsize;
990   int  depth;
991   int  lastmodified;
992 };
993
994 LPWSTR strcvtA2W(LPCSTR src, int nchars)
995
996 {
997    LPWSTR dest = xmalloc (2 * nchars + 2);
998
999    lstrcpynAtoW(dest,src, nchars);
1000    dest[nchars] = 0;
1001    return dest;
1002 }
1003
1004 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey, 
1005                                    int nrLS, int nrMS, struct _w95_info *info )
1006
1007 {
1008   /* Disk Key Header structure (RGDB part) */
1009         struct  dkh {
1010                 unsigned long           nextkeyoff; 
1011                 unsigned short          nrLS;
1012                 unsigned short          nrMS;
1013                 unsigned long           bytesused;
1014                 unsigned short          keynamelen;
1015                 unsigned short          values;
1016                 unsigned long           xx1;
1017                 /* keyname */
1018                 /* disk key values or nothing */
1019         };
1020         /* Disk Key Value structure */
1021         struct  dkv {
1022                 unsigned long           type;
1023                 unsigned long           x1;
1024                 unsigned short          valnamelen;
1025                 unsigned short          valdatalen;
1026                 /* valname, valdata */
1027         };
1028
1029         
1030         struct  dkh dkh;
1031         int     bytesread = 0;
1032         char    *rgdbdata = info->rgdbbuffer;
1033         int     nbytes = info->rgdbsize;
1034         char    *curdata = rgdbdata;
1035         char    *end = rgdbdata + nbytes;
1036         int     off_next_rgdb;
1037         char    *next = rgdbdata;
1038         int     nrgdb, i;
1039         LPKEYSTRUCT     lpxkey;
1040         
1041         do {
1042           curdata = next;
1043           if (strncmp(curdata, "RGDB", 4)) return (NULL);
1044             
1045           memcpy(&off_next_rgdb,curdata+4,4);
1046           next = curdata + off_next_rgdb;
1047           nrgdb = (int) *((short *)curdata + 7);
1048
1049         } while (nrgdb != nrMS && (next < end));
1050
1051         /* curdata now points to the start of the right RGDB section */
1052         curdata += 0x20;
1053
1054 #define XREAD(whereto,len) \
1055         if ((curdata + len) <end) {\
1056                 memcpy(whereto,curdata,len);\
1057                 curdata+=len;\
1058                 bytesread+=len;\
1059         }
1060
1061         do {
1062           XREAD(&dkh, sizeof (dkh));
1063           if (dkh.nrLS == nrLS) break;
1064
1065           curdata += dkh.nextkeyoff - sizeof(dkh);
1066         } while (curdata < next);
1067
1068         if (dkh.nrLS != nrLS) return (NULL);
1069
1070         if (nrgdb != dkh.nrMS) {
1071           return (NULL);
1072         }
1073
1074         assert((dkh.keynamelen<2) || curdata[0]);
1075         lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1076         curdata += dkh.keynamelen;
1077
1078         for (i=0;i< dkh.values; i++) {
1079           struct dkv dkv;
1080           LPBYTE data;
1081           int len;
1082           LPWSTR name;
1083
1084           XREAD(&dkv,sizeof(dkv));
1085
1086           name = strcvtA2W(curdata, dkv.valnamelen);
1087           curdata += dkv.valnamelen;
1088
1089           if ((1 << dkv.type) & UNICONVMASK) {
1090             data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1091             len = dkv.valdatalen + 1;
1092           } else {
1093             /* I don't think we want to NULL terminate all data */
1094             data = xmalloc(dkv.valdatalen);
1095             memcpy (data, curdata, dkv.valdatalen);
1096             len = dkv.valdatalen;
1097           }
1098
1099           curdata += dkv.valdatalen;
1100           
1101           _find_or_add_value(
1102                              lpxkey,
1103                              name,
1104                              dkv.type,
1105                              data,
1106                              len,
1107                              info->lastmodified
1108                              );
1109
1110         }
1111
1112         return (lpxkey);
1113 }
1114
1115 static void
1116 _w95_walkrgkn(LPKEYSTRUCT prevkey, char *off, struct _w95_info *info)
1117
1118 {
1119   /* Disk Key Entry structure (RGKN part) */
1120   struct        dke {
1121     unsigned long               x1;
1122     unsigned long               x2;
1123     unsigned long               x3;/*usually 0xFFFFFFFF */
1124     unsigned long               prevlvl;
1125     unsigned long               nextsub;
1126     unsigned long               next;
1127     unsigned short              nrLS;
1128     unsigned short              nrMS;
1129   } *dke = (struct dke *)off;
1130   LPKEYSTRUCT  lpxkey;
1131
1132   if (dke == NULL) {
1133     dke = (struct dke *) ((char *)info->rgknbuffer);
1134   }
1135
1136   lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1137   /* XXX <-- This is a hack*/
1138   if (!lpxkey) {
1139     lpxkey = prevkey;
1140   }
1141
1142   if (dke->nextsub != -1 && 
1143       ((dke->nextsub - 0x20) < info->rgknsize) 
1144       && (dke->nextsub > 0x20)) {
1145     
1146     _w95_walkrgkn(lpxkey, 
1147                   info->rgknbuffer + dke->nextsub - 0x20, 
1148                   info);
1149   }
1150   
1151   if (dke->next != -1 && 
1152       ((dke->next - 0x20) < info->rgknsize) && 
1153       (dke->next > 0x20)) {
1154     _w95_walkrgkn(prevkey,  
1155                   info->rgknbuffer + dke->next - 0x20,
1156                   info);
1157   }
1158
1159   return;
1160 }
1161
1162 static void
1163 _w95_loadreg(char* fn,LPKEYSTRUCT lpkey) {
1164         HFILE32         hfd;
1165         char            magic[5];
1166         unsigned long   where,version,rgdbsection,end;
1167         struct          _w95_info info;
1168         OFSTRUCT        ofs;
1169         BY_HANDLE_FILE_INFORMATION hfdinfo;
1170
1171         dprintf_info(reg,"Loading Win95 registry database '%s'\n",fn);
1172         hfd=OpenFile32(fn,&ofs,OF_READ);
1173         if (hfd==HFILE_ERROR32)
1174                 return;
1175         magic[4]=0;
1176         if (4!=_lread32(hfd,magic,4))
1177                 return;
1178         if (strcmp(magic,"CREG")) {
1179                 fprintf(stddeb,"%s is not a w95 registry.\n",fn);
1180                 return;
1181         }
1182         if (4!=_lread32(hfd,&version,4))
1183                 return;
1184         if (4!=_lread32(hfd,&rgdbsection,4))
1185                 return;
1186         if (-1==_llseek32(hfd,0x20,SEEK_SET))
1187                 return;
1188         if (4!=_lread32(hfd,magic,4))
1189                 return;
1190         if (strcmp(magic,"RGKN")) {
1191                 dprintf_warn(reg, "second IFF header not RGKN, but %s\n", magic);
1192                 return;
1193         }
1194
1195         /* STEP 1: Keylink structures */
1196         if (-1==_llseek32(hfd,0x40,SEEK_SET))
1197                 return;
1198         where   = 0x40;
1199         end     = rgdbsection;
1200
1201         info.rgknsize = end - where;
1202         info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1203         if (info.rgknsize != _lread32(hfd,info.rgknbuffer,info.rgknsize))
1204                 return;
1205
1206         if (!GetFileInformationByHandle(hfd,&hfdinfo))
1207                 return;
1208
1209         end = hfdinfo.nFileSizeLow;
1210         info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1211
1212         if (-1==_llseek32(hfd,rgdbsection,SEEK_SET))
1213                 return;
1214
1215         info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1216         info.rgdbsize = end - rgdbsection;
1217
1218         if (info.rgdbsize !=_lread32(hfd,info.rgdbbuffer,info.rgdbsize))
1219                 return;
1220         _lclose32(hfd);
1221
1222         _w95_walkrgkn(lpkey, NULL, &info);
1223
1224         free (info.rgdbbuffer);
1225         free (info.rgknbuffer);
1226 }
1227
1228 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1229
1230 /*
1231     reghack - windows 3.11 registry data format demo program.
1232
1233     The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1234     a combined hash table and tree description, and finally a text table.
1235
1236     The header is obvious from the struct header. The taboff1 and taboff2
1237     fields are always 0x20, and their usage is unknown.
1238
1239     The 8-byte entry table has various entry types.
1240
1241     tabent[0] is a root index. The second word has the index of the root of
1242             the directory.
1243     tabent[1..hashsize] is a hash table. The first word in the hash entry is
1244             the index of the key/value that has that hash. Data with the same
1245             hash value are on a circular list. The other three words in the
1246             hash entry are always zero.
1247     tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1248             entry: dirent and keyent/valent. They are identified by context.
1249     tabent[freeidx] is the first free entry. The first word in a free entry
1250             is the index of the next free entry. The last has 0 as a link.
1251             The other three words in the free list are probably irrelevant.
1252
1253     Entries in text table are preceeded by a word at offset-2. This word
1254     has the value (2*index)+1, where index is the referring keyent/valent
1255     entry in the table. I have no suggestion for the 2* and the +1.
1256     Following the word, there are N bytes of data, as per the keyent/valent
1257     entry length. The offset of the keyent/valent entry is from the start
1258     of the text table to the first data byte.
1259
1260     This information is not available from Microsoft. The data format is
1261     deduced from the reg.dat file by me. Mistakes may
1262     have been made. I claim no rights and give no guarantees for this program.
1263
1264     Tor Sjøwall, tor@sn.no
1265 */
1266
1267 /* reg.dat header format */
1268 struct _w31_header {
1269         char            cookie[8];      /* 'SHCC3.10' */
1270         unsigned long   taboff1;        /* offset of hash table (??) = 0x20 */
1271         unsigned long   taboff2;        /* offset of index table (??) = 0x20 */
1272         unsigned long   tabcnt;         /* number of entries in index table */
1273         unsigned long   textoff;        /* offset of text part */
1274         unsigned long   textsize;       /* byte size of text part */
1275         unsigned short  hashsize;       /* hash size */
1276         unsigned short  freeidx;        /* free index */
1277 };
1278
1279 /* generic format of table entries */
1280 struct _w31_tabent {
1281         unsigned short w0, w1, w2, w3;
1282 };
1283
1284 /* directory tabent: */
1285 struct _w31_dirent {
1286         unsigned short  sibling_idx;    /* table index of sibling dirent */
1287         unsigned short  child_idx;      /* table index of child dirent */
1288         unsigned short  key_idx;        /* table index of key keyent */
1289         unsigned short  value_idx;      /* table index of value valent */
1290 };
1291
1292 /* key tabent: */
1293 struct _w31_keyent {
1294         unsigned short  hash_idx;       /* hash chain index for string */
1295         unsigned short  refcnt;         /* reference count */
1296         unsigned short  length;         /* length of string */
1297         unsigned short  string_off;     /* offset of string in text table */
1298 };
1299
1300 /* value tabent: */
1301 struct _w31_valent {
1302         unsigned short  hash_idx;       /* hash chain index for string */
1303         unsigned short  refcnt;         /* reference count */
1304         unsigned short  length;         /* length of string */
1305         unsigned short  string_off;     /* offset of string in text table */
1306 };
1307
1308 /* recursive helper function to display a directory tree */
1309 void
1310 __w31_dumptree( unsigned short idx,
1311                 unsigned char *txt,
1312                 struct _w31_tabent *tab,
1313                 struct _w31_header *head,
1314                 LPKEYSTRUCT     lpkey,
1315                 time_t          lastmodified,
1316                 int             level
1317 ) {
1318         struct _w31_dirent      *dir;
1319         struct _w31_keyent      *key;
1320         struct _w31_valent      *val;
1321         LPKEYSTRUCT             xlpkey = NULL;
1322         LPWSTR                  name,value;
1323         static char             tail[400];
1324
1325         while (idx!=0) {
1326                 dir=(struct _w31_dirent*)&tab[idx];
1327
1328                 if (dir->key_idx) {
1329                         key = (struct _w31_keyent*)&tab[dir->key_idx];
1330
1331                         memcpy(tail,&txt[key->string_off],key->length);
1332                         tail[key->length]='\0';
1333                         /* all toplevel entries AND the entries in the 
1334                          * toplevel subdirectory belong to \SOFTWARE\Classes
1335                          */
1336                         if (!level && !lstrcmp32A(tail,".classes")) {
1337                                 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1338                                 idx=dir->sibling_idx;
1339                                 continue;
1340                         }
1341                         name=strdupA2W(tail);
1342
1343                         xlpkey=_find_or_add_key(lpkey,name);
1344
1345                         /* only add if leaf node or valued node */
1346                         if (dir->value_idx!=0||dir->child_idx==0) {
1347                                 if (dir->value_idx) {
1348                                         val=(struct _w31_valent*)&tab[dir->value_idx];
1349                                         memcpy(tail,&txt[val->string_off],val->length);
1350                                         tail[val->length]='\0';
1351                                         value=strdupA2W(tail);
1352                                         _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlen32W(value)*2+2,lastmodified);
1353                                 }
1354                         }
1355                 } else {
1356                         dprintf_info(reg,"__w31_dumptree:strange: no directory key name, idx=%04x\n", idx);
1357                 }
1358                 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1359                 idx=dir->sibling_idx;
1360         }
1361 }
1362
1363 void
1364 _w31_loadreg() {
1365         HFILE32                 hf;
1366         struct _w31_header      head;
1367         struct _w31_tabent      *tab;
1368         unsigned char           *txt;
1369         int                     len;
1370         OFSTRUCT                ofs;
1371         BY_HANDLE_FILE_INFORMATION hfinfo;
1372         time_t                  lastmodified;
1373         HKEY                    hkey;
1374         LPKEYSTRUCT             lpkey;
1375
1376         hf = OpenFile32("reg.dat",&ofs,OF_READ);
1377         if (hf==HFILE_ERROR32)
1378                 return;
1379
1380         /* read & dump header */
1381         if (sizeof(head)!=_lread32(hf,&head,sizeof(head))) {
1382                 dprintf_err(reg, "_w31_loadreg:reg.dat is too short.\n");
1383                 _lclose32(hf);
1384                 return;
1385         }
1386         if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1387                 dprintf_err(reg, "_w31_loadreg:reg.dat has bad signature.\n");
1388                 _lclose32(hf);
1389                 return;
1390         }
1391
1392         len = head.tabcnt * sizeof(struct _w31_tabent);
1393         /* read and dump index table */
1394         tab = xmalloc(len);
1395         if (len!=_lread32(hf,tab,len)) {
1396                 dprintf_err(reg,"_w31_loadreg:couldn't read %d bytes.\n",len); 
1397                 free(tab);
1398                 _lclose32(hf);
1399                 return;
1400         }
1401
1402         /* read text */
1403         txt = xmalloc(head.textsize);
1404         if (-1==_llseek32(hf,head.textoff,SEEK_SET)) {
1405                 dprintf_err(reg,"_w31_loadreg:couldn't seek to textblock.\n"); 
1406                 free(tab);
1407                 free(txt);
1408                 _lclose32(hf);
1409                 return;
1410         }
1411         if (head.textsize!=_lread32(hf,txt,head.textsize)) {
1412                 dprintf_err(reg,"_w31_loadreg:textblock too short (%d instead of %ld).\n",len,head.textsize); 
1413                 free(tab);
1414                 free(txt);
1415                 _lclose32(hf);
1416                 return;
1417         }
1418
1419         if (!GetFileInformationByHandle(hf,&hfinfo)) {
1420                 dprintf_err(reg,"_w31_loadreg:GetFileInformationByHandle failed?.\n"); 
1421                 free(tab);
1422                 free(txt);
1423                 _lclose32(hf);
1424                 return;
1425         }
1426         lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1427
1428         if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&hkey)!=ERROR_SUCCESS)
1429                 return;
1430         lpkey = lookup_hkey(hkey);
1431         __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1432         free(tab);
1433         free(txt);
1434         _lclose32(hf);
1435         return;
1436 }
1437
1438 void
1439 SHELL_LoadRegistry() {
1440         char    *fn;
1441         struct  passwd  *pwd;
1442         LPKEYSTRUCT     lpkey;
1443         HKEY            hkey;
1444
1445
1446         if (key_classes_root==NULL)
1447                 SHELL_Init();
1448
1449         /* Load windows 3.1 entries */
1450         _w31_loadreg();
1451         /* Load windows 95 entries */
1452         _w95_loadreg("C:\\system.1st",  key_local_machine);
1453         _w95_loadreg("system.dat",      key_local_machine);
1454         _w95_loadreg("user.dat",        key_users);
1455
1456         /* the global user default is loaded under HKEY_USERS\\.Default */
1457         RegCreateKey16(HKEY_USERS,".Default",&hkey);
1458         lpkey = lookup_hkey(hkey);
1459         _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1460
1461         /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1462         _copy_registry(lpkey,key_current_user);
1463         RegCloseKey(hkey);
1464
1465         /* the global machine defaults */
1466         _wine_loadreg(key_local_machine,SAVE_LOCAL_MACHINE_DEFAULT,0);
1467
1468         /* load the user saved registries */
1469
1470         /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1471
1472         pwd=getpwuid(getuid());
1473         if (pwd!=NULL && pwd->pw_dir!=NULL) {
1474                 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1475                 strcpy(fn,pwd->pw_dir);
1476                 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1477                 _wine_loadreg(key_current_user,fn,REG_OPTION_TAINTED);
1478                 free(fn);
1479                 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1480                 strcpy(fn,pwd->pw_dir);
1481                 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1482                 _wine_loadreg(key_local_machine,fn,REG_OPTION_TAINTED);
1483                 free(fn);
1484         } else
1485                 fprintf(stderr,"SHELL_LoadRegistry:failed to get homedirectory of UID %d.\n",getuid());
1486         if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1487                 DWORD   junk,type,len;
1488                 char    data[5];
1489
1490                 len=4;
1491                 if ((   RegQueryValueEx32A(
1492                                 hkey,
1493                                 VAL_SAVEUPDATED,
1494                                 &junk,
1495                                 &type,
1496                                 data,
1497                                 &len
1498                         )!=ERROR_SUCCESS) ||
1499                         type != REG_SZ
1500                 )
1501                         RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1502                 RegCloseKey(hkey);
1503         }
1504 }
1505
1506
1507 /********************* API FUNCTIONS ***************************************/
1508 /*
1509  * Open Keys.
1510  *
1511  * All functions are stubs to RegOpenKeyEx32W where all the
1512  * magic happens. 
1513  *
1514  * FIXME: security,options,desiredaccess,...
1515  *
1516  * Callpath:
1517  * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1518  *                                  RegOpenKey32W   -> RegOpenKeyEx32W 
1519  */
1520
1521 /* RegOpenKeyExW                [ADVAPI32.150] */
1522 DWORD WINAPI RegOpenKeyEx32W(
1523         HKEY    hkey,
1524         LPCWSTR lpszSubKey,
1525         DWORD   dwReserved,
1526         REGSAM  samDesired,
1527         LPHKEY  retkey
1528 ) {
1529         LPKEYSTRUCT     lpNextKey,lpxkey;
1530         LPWSTR          *wps;
1531         int             wpc,i;
1532         dprintf_info(reg,"RegOpenKeyEx32W(%lx,%s,%ld,%lx,%p)\n",
1533                 (LONG)hkey,W2C(lpszSubKey,0),dwReserved,samDesired,retkey
1534         );
1535
1536         lpNextKey       = lookup_hkey(hkey);
1537         if (!lpNextKey)
1538                 return SHELL_ERROR_BADKEY;
1539         if (!lpszSubKey || !*lpszSubKey) {
1540                 add_handle(++currenthandle,lpNextKey,samDesired);
1541                 *retkey=currenthandle;
1542                 return SHELL_ERROR_SUCCESS;
1543         }
1544         split_keypath(lpszSubKey,&wps,&wpc);
1545         i       = 0;
1546         while ((i<wpc) && (wps[i][0]=='\0')) i++;
1547         lpxkey  = lpNextKey;
1548         while (wps[i]) {
1549                 lpxkey=lpNextKey->nextsub;
1550                 while (lpxkey) {
1551                         if (!lstrcmpi32W(wps[i],lpxkey->keyname))
1552                                 break;
1553                         lpxkey=lpxkey->next;
1554                 }
1555                 if (!lpxkey) {
1556                         FREE_KEY_PATH;
1557                         return SHELL_ERROR_BADKEY;
1558                 }
1559                 i++;
1560                 lpNextKey       = lpxkey;
1561         }
1562         add_handle(++currenthandle,lpxkey,samDesired);
1563         *retkey = currenthandle;
1564         FREE_KEY_PATH;
1565         return  SHELL_ERROR_SUCCESS;
1566 }
1567
1568 /* RegOpenKeyW                  [ADVAPI32.151] */
1569 DWORD WINAPI RegOpenKey32W(
1570         HKEY    hkey,
1571         LPCWSTR lpszSubKey,
1572         LPHKEY  retkey
1573 ) {
1574         dprintf_info(reg,"RegOpenKey32W(%lx,%s,%p)\n",
1575                 (LONG)hkey,W2C(lpszSubKey,0),retkey
1576         );
1577         return RegOpenKeyEx32W(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1578 }
1579
1580
1581 /* RegOpenKeyExA                [ADVAPI32.149] */
1582 DWORD WINAPI RegOpenKeyEx32A(
1583         HKEY    hkey,
1584         LPCSTR  lpszSubKey,
1585         DWORD   dwReserved,
1586         REGSAM  samDesired,
1587         LPHKEY  retkey
1588 ) {
1589         LPWSTR  lpszSubKeyW;
1590         DWORD   ret;
1591
1592         dprintf_info(reg,"RegOpenKeyEx32A(%lx,%s,%ld,%lx,%p)\n",
1593                 (LONG)hkey,lpszSubKey,dwReserved,samDesired,retkey
1594         );
1595         if (lpszSubKey)
1596                 lpszSubKeyW=strdupA2W(lpszSubKey);
1597         else
1598                 lpszSubKeyW=NULL;
1599         ret=RegOpenKeyEx32W(hkey,lpszSubKeyW,dwReserved,samDesired,retkey);
1600         if (lpszSubKeyW)
1601                 free(lpszSubKeyW);
1602         return ret;
1603 }
1604
1605 /* RegOpenKeyA                  [ADVAPI32.148] */
1606 DWORD WINAPI RegOpenKey32A(
1607         HKEY    hkey,
1608         LPCSTR  lpszSubKey,
1609         LPHKEY  retkey
1610 ) {
1611         dprintf_info(reg,"RegOpenKey32A(%lx,%s,%p)\n",
1612                 (LONG)hkey,lpszSubKey,retkey
1613         );
1614         return  RegOpenKeyEx32A(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1615 }
1616
1617 /* RegOpenKey                   [SHELL.1] [KERNEL.217] */
1618 DWORD WINAPI RegOpenKey16(
1619         HKEY    hkey,
1620         LPCSTR  lpszSubKey,
1621         LPHKEY  retkey
1622 ) {
1623         dprintf_info(reg,"RegOpenKey16(%lx,%s,%p)\n",
1624                 (LONG)hkey,lpszSubKey,retkey
1625         );
1626         return RegOpenKey32A(hkey,lpszSubKey,retkey);
1627 }
1628
1629 /* 
1630  * Create keys
1631  * 
1632  * All those functions convert their respective 
1633  * arguments and call RegCreateKeyExW at the end.
1634  *
1635  * FIXME: no security,no access attrib,no optionhandling yet.
1636  *
1637  * Callpath:
1638  * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1639  *                                      RegCreateKey32W   -> RegCreateKeyEx32W
1640  */
1641
1642 /* RegCreateKeyExW              [ADVAPI32.131] */
1643 DWORD WINAPI RegCreateKeyEx32W(
1644         HKEY    hkey,
1645         LPCWSTR lpszSubKey,
1646         DWORD   dwReserved,
1647         LPWSTR  lpszClass,
1648         DWORD   fdwOptions,
1649         REGSAM  samDesired,
1650         LPSECURITY_ATTRIBUTES lpSecAttribs,
1651         LPHKEY  retkey,
1652         LPDWORD lpDispos
1653 ) {
1654         LPKEYSTRUCT     *lplpPrevKey,lpNextKey,lpxkey;
1655         LPWSTR          *wps;
1656         int             wpc,i;
1657
1658 /*FIXME: handle security/access/whatever */
1659         dprintf_info(reg,"RegCreateKeyEx32W(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1660                 (LONG)hkey,
1661                 W2C(lpszSubKey,0),
1662                 dwReserved,
1663                 W2C(lpszClass,1),
1664                 fdwOptions,
1665                 samDesired,
1666                 lpSecAttribs,
1667                 retkey,
1668                 lpDispos
1669         );
1670
1671         lpNextKey       = lookup_hkey(hkey);
1672         if (!lpNextKey)
1673                 return SHELL_ERROR_BADKEY;
1674         if (!lpszSubKey || !*lpszSubKey) {
1675                 add_handle(++currenthandle,lpNextKey,samDesired);
1676                 *retkey=currenthandle;
1677                 lpNextKey->flags|=REG_OPTION_TAINTED;
1678                 return SHELL_ERROR_SUCCESS;
1679         }
1680         split_keypath(lpszSubKey,&wps,&wpc);
1681         i       = 0;
1682         while ((i<wpc) && (wps[i][0]=='\0')) i++;
1683         lpxkey  = lpNextKey;
1684         while (wps[i]) {
1685                 lpxkey=lpNextKey->nextsub;
1686                 while (lpxkey) {
1687                         if (!lstrcmpi32W(wps[i],lpxkey->keyname))
1688                                 break;
1689                         lpxkey=lpxkey->next;
1690                 }
1691                 if (!lpxkey)
1692                         break;
1693                 i++;
1694                 lpNextKey       = lpxkey;
1695         }
1696         if (lpxkey) {
1697                 add_handle(++currenthandle,lpxkey,samDesired);
1698                 lpxkey->flags  |= REG_OPTION_TAINTED;
1699                 *retkey         = currenthandle;
1700                 if (lpDispos)
1701                         *lpDispos       = REG_OPENED_EXISTING_KEY;
1702                 FREE_KEY_PATH;
1703                 return  SHELL_ERROR_SUCCESS;
1704         }
1705         /* good. now the hard part */
1706         while (wps[i]) {
1707                 lplpPrevKey     = &(lpNextKey->nextsub);
1708                 lpxkey          = *lplpPrevKey;
1709                 while (lpxkey) {
1710                         lplpPrevKey     = &(lpxkey->next);
1711                         lpxkey          = *lplpPrevKey;
1712                 }
1713                 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
1714                 if (!*lplpPrevKey) {
1715                         FREE_KEY_PATH;
1716                         return SHELL_ERROR_OUTOFMEMORY;
1717                 }
1718                 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
1719                 (*lplpPrevKey)->keyname = strdupW(wps[i]);
1720                 (*lplpPrevKey)->next    = NULL;
1721                 (*lplpPrevKey)->nextsub = NULL;
1722                 (*lplpPrevKey)->values  = NULL;
1723                 (*lplpPrevKey)->nrofvalues = 0;
1724                 (*lplpPrevKey)->flags   = REG_OPTION_TAINTED;
1725                 if (lpszClass)
1726                         (*lplpPrevKey)->class = strdupW(lpszClass);
1727                 else
1728                         (*lplpPrevKey)->class = NULL;
1729                 lpNextKey       = *lplpPrevKey;
1730                 i++;
1731         }
1732         add_handle(++currenthandle,lpNextKey,samDesired);
1733
1734         /*FIXME: flag handling correct? */
1735         lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
1736         if (lpszClass)
1737                 lpNextKey->class = strdupW(lpszClass);
1738         else
1739                 lpNextKey->class = NULL;
1740         *retkey         = currenthandle;
1741         if (lpDispos)
1742                 *lpDispos       = REG_CREATED_NEW_KEY;
1743         FREE_KEY_PATH;
1744         return SHELL_ERROR_SUCCESS;
1745 }
1746
1747 /* RegCreateKeyW                [ADVAPI32.132] */
1748 DWORD WINAPI RegCreateKey32W(
1749         HKEY    hkey,
1750         LPCWSTR lpszSubKey,
1751         LPHKEY  retkey
1752 ) {
1753         DWORD   junk,ret;
1754
1755         dprintf_info(reg,"RegCreateKey32W(%lx,%s,%p)\n",
1756                 (LONG)hkey,W2C(lpszSubKey,0),retkey
1757         );
1758         ret=RegCreateKeyEx32W(
1759                 hkey,           /* key handle */
1760                 lpszSubKey,     /* subkey name */
1761                 0,              /* reserved = 0 */
1762                 NULL,           /* lpszClass? FIXME: ? */
1763                 REG_OPTION_NON_VOLATILE,        /* options */
1764                 KEY_ALL_ACCESS, /* desired access attribs */
1765                 NULL,           /* lpsecurity attributes */
1766                 retkey,         /* lpretkey */
1767                 &junk           /* disposition value */
1768         );
1769         return  ret;
1770 }
1771
1772 /* RegCreateKeyExA              [ADVAPI32.130] */
1773 DWORD WINAPI RegCreateKeyEx32A(
1774         HKEY    hkey,
1775         LPCSTR  lpszSubKey,
1776         DWORD   dwReserved,
1777         LPSTR   lpszClass,
1778         DWORD   fdwOptions,
1779         REGSAM  samDesired,
1780         LPSECURITY_ATTRIBUTES lpSecAttribs,
1781         LPHKEY  retkey,
1782         LPDWORD lpDispos
1783 ) {
1784         LPWSTR  lpszSubKeyW,lpszClassW;
1785         DWORD   ret;
1786
1787         dprintf_info(reg,"RegCreateKeyEx32A(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1788                 (LONG)hkey,
1789                 lpszSubKey,
1790                 dwReserved,
1791                 lpszClass,
1792                 fdwOptions,
1793                 samDesired,
1794                 lpSecAttribs,
1795                 retkey,
1796                 lpDispos
1797         );
1798         if (lpszSubKey)
1799                 lpszSubKeyW=strdupA2W(lpszSubKey);
1800         else
1801                 lpszSubKeyW=NULL;
1802         if (lpszClass)
1803                 lpszClassW=strdupA2W(lpszClass);
1804         else
1805                 lpszClassW=NULL;
1806         ret=RegCreateKeyEx32W(
1807                 hkey,
1808                 lpszSubKeyW,
1809                 dwReserved,
1810                 lpszClassW,
1811                 fdwOptions,
1812                 samDesired,
1813                 lpSecAttribs,
1814                 retkey,
1815                 lpDispos
1816         );
1817         if (lpszSubKeyW)
1818                 free(lpszSubKeyW);
1819         if (lpszClassW)
1820                 free(lpszClassW);
1821         return ret;
1822 }
1823
1824 /* RegCreateKeyA                [ADVAPI32.129] */
1825 DWORD WINAPI RegCreateKey32A(
1826         HKEY    hkey,
1827         LPCSTR  lpszSubKey,
1828         LPHKEY  retkey
1829 ) {
1830         DWORD   junk;
1831
1832         dprintf_info(reg,"RegCreateKey32A(%lx,%s,%p)\n",
1833                 (LONG)hkey,lpszSubKey,retkey
1834         );
1835         return  RegCreateKeyEx32A(
1836                 hkey,           /* key handle */
1837                 lpszSubKey,     /* subkey name */
1838                 0,              /* reserved = 0 */
1839                 NULL,           /* lpszClass? FIXME: ? */
1840                 REG_OPTION_NON_VOLATILE,/* options */
1841                 KEY_ALL_ACCESS, /* desired access attribs */
1842                 NULL,           /* lpsecurity attributes */
1843                 retkey,         /* lpretkey */
1844                 &junk           /* disposition value */
1845         );
1846 }
1847
1848 /* RegCreateKey                 [SHELL.2] [KERNEL.218] */
1849 DWORD WINAPI RegCreateKey16(
1850         HKEY    hkey,
1851         LPCSTR  lpszSubKey,
1852         LPHKEY  retkey
1853 ) {
1854         dprintf_info(reg,"RegCreateKey16(%lx,%s,%p)\n",
1855                 (LONG)hkey,lpszSubKey,retkey
1856         );
1857         return RegCreateKey32A(hkey,lpszSubKey,retkey);
1858 }
1859
1860 /* 
1861  * Query Value Functions
1862  * Win32 differs between keynames and valuenames. 
1863  * multiple values may belong to one key, the special value
1864  * with name NULL is the default value used by the win31
1865  * compat functions.
1866  *
1867  * Callpath:
1868  * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
1869  *                                          RegQueryValue32W -> RegQueryValueEx32W
1870  */
1871
1872 /* RegQueryValueExW             [ADVAPI32.158] */
1873 DWORD WINAPI RegQueryValueEx32W(
1874         HKEY    hkey,
1875         LPWSTR  lpszValueName,
1876         LPDWORD lpdwReserved,
1877         LPDWORD lpdwType,
1878         LPBYTE  lpbData,
1879         LPDWORD lpcbData
1880 ) {
1881         LPKEYSTRUCT     lpkey;
1882         int             i;
1883
1884         dprintf_info(reg,"RegQueryValueEx32W(%x,%s,%p,%p,%p,%ld)\n",
1885                 hkey,W2C(lpszValueName,0),lpdwReserved,lpdwType,lpbData,
1886                 lpcbData?*lpcbData:0
1887         );
1888
1889         lpkey   = lookup_hkey(hkey);
1890         if (!lpkey)
1891                 return SHELL_ERROR_BADKEY;
1892         if (lpszValueName && !*lpszValueName)
1893                 lpszValueName = NULL;
1894         if (lpszValueName==NULL) {
1895                 for (i=0;i<lpkey->nrofvalues;i++)
1896                         if (lpkey->values[i].name==NULL)
1897                                 break;
1898         } else {
1899                 for (i=0;i<lpkey->nrofvalues;i++)
1900                         if (    lpkey->values[i].name &&
1901                                 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
1902                         )
1903                                 break;
1904         }
1905         if (i==lpkey->nrofvalues) {
1906                 if (lpszValueName==NULL) {
1907                         if (lpbData) {
1908                                 *(WCHAR*)lpbData = 0;
1909                                 *lpcbData       = 2;
1910                         }
1911                         if (lpdwType)
1912                                 *lpdwType       = REG_SZ;
1913                         return SHELL_ERROR_SUCCESS;
1914                 }
1915                 return SHELL_ERROR_BADKEY;/*FIXME: correct return? */
1916         }
1917         if (lpdwType)
1918                 *lpdwType       = lpkey->values[i].type;
1919         if (lpbData==NULL) {
1920                 if (lpcbData==NULL)
1921                         return SHELL_ERROR_SUCCESS;
1922                 *lpcbData       = lpkey->values[i].len;
1923                 return SHELL_ERROR_SUCCESS;
1924         }
1925         if (*lpcbData<lpkey->values[i].len) {
1926                 *(WCHAR*)lpbData
1927                         = 0;
1928                 *lpcbData       = lpkey->values[i].len;
1929                 return ERROR_MORE_DATA;
1930         }
1931         memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
1932         *lpcbData       = lpkey->values[i].len;
1933         return SHELL_ERROR_SUCCESS;
1934 }
1935
1936 /* RegQueryValueW               [ADVAPI32.159] */
1937 DWORD WINAPI RegQueryValue32W(
1938         HKEY    hkey,
1939         LPWSTR  lpszSubKey,
1940         LPWSTR  lpszData,
1941         LPDWORD lpcbData
1942 ) {
1943         HKEY    xhkey;
1944         DWORD   ret,lpdwType;
1945
1946         dprintf_info(reg,"RegQueryValue32W(%x,%s,%p,%ld)\n",
1947                 hkey,W2C(lpszSubKey,0),lpszData,
1948                 lpcbData?*lpcbData:0
1949         );
1950
1951         /* only open subkey, if we really do descend */
1952         if (lpszSubKey && *lpszSubKey) {
1953                 ret     = RegOpenKey32W(hkey,lpszSubKey,&xhkey);
1954                 if (ret!=ERROR_SUCCESS)
1955                         return ret;
1956         } else
1957                 xhkey   = hkey;
1958
1959         lpdwType        = REG_SZ;
1960         ret     = RegQueryValueEx32W(
1961                 xhkey,
1962                 NULL,           /* varname NULL -> compat */
1963                 NULL,           /* lpdwReserved, must be NULL */
1964                 &lpdwType,
1965                 (LPBYTE)lpszData,
1966                 lpcbData
1967         );
1968         if (xhkey!=hkey)
1969                 RegCloseKey(xhkey);
1970         return ret;
1971 }
1972
1973 /* RegQueryValueExA             [ADVAPI32.157] */
1974 DWORD WINAPI RegQueryValueEx32A(
1975         HKEY    hkey,
1976         LPSTR   lpszValueName,
1977         LPDWORD lpdwReserved,
1978         LPDWORD lpdwType,
1979         LPBYTE  lpbData,
1980         LPDWORD lpcbData
1981 ) {
1982         LPWSTR  lpszValueNameW;
1983         LPBYTE  buf;
1984         DWORD   ret,myxlen;
1985         DWORD   *mylen;
1986         DWORD   type;
1987
1988         dprintf_info(reg,"RegQueryValueEx32A(%x,%s,%p,%p,%p,%ld)\n",
1989                 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
1990                 lpcbData?*lpcbData:0
1991         );
1992         if (lpszValueName)
1993                 lpszValueNameW=strdupA2W(lpszValueName);
1994         else 
1995                 lpszValueNameW=NULL;
1996
1997         if (lpdwType)
1998                 type=*lpdwType;
1999
2000         if (lpbData) {
2001                 myxlen  = 0;
2002                 mylen   = &myxlen;
2003                 buf     = xmalloc(4);
2004                 ret=RegQueryValueEx32W(
2005                         hkey,
2006                         lpszValueNameW,
2007                         lpdwReserved,
2008                         &type,
2009                         buf,
2010                         mylen
2011                 );
2012                 free(buf);
2013                 if (ret==ERROR_MORE_DATA) {
2014                         buf     = (LPBYTE)xmalloc(*mylen);
2015                 } else {
2016                         buf     = (LPBYTE)xmalloc(2*(*lpcbData));
2017                         myxlen  = 2*(*lpcbData);
2018                 }
2019         } else {
2020                 buf=NULL;
2021                 if (lpcbData) {
2022                         myxlen  = *lpcbData*2;
2023                         mylen   = &myxlen;
2024                 } else
2025                         mylen   = NULL;
2026         }
2027         ret=RegQueryValueEx32W(
2028                 hkey,
2029                 lpszValueNameW,
2030                 lpdwReserved,
2031                 &type,
2032                 buf,
2033                 mylen
2034         );
2035         if (lpdwType) 
2036                 *lpdwType=type;
2037         if (ret==ERROR_SUCCESS) {
2038                 if (buf) {
2039                         if (UNICONVMASK & (1<<(type))) {
2040                                 /* convert UNICODE to ASCII */
2041                                 lstrcpyWtoA(lpbData,(LPWSTR)buf);
2042                                 *lpcbData       = myxlen/2;
2043                         } else {
2044                                 if (myxlen>*lpcbData)
2045                                         ret     = ERROR_MORE_DATA;
2046                                 else
2047                                         memcpy(lpbData,buf,myxlen);
2048
2049                                 *lpcbData       = myxlen;
2050                         }
2051                 } else {
2052                         if ((UNICONVMASK & (1<<(type))) && lpcbData)
2053                                 *lpcbData       = myxlen/2;
2054                 }
2055         } else {
2056                 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2057                         *lpcbData       = myxlen/2;
2058         }
2059         if (buf)
2060                 free(buf);
2061         return ret;
2062 }
2063
2064 /* RegQueryValueEx              [KERNEL.225] */
2065 DWORD WINAPI RegQueryValueEx16(
2066         HKEY    hkey,
2067         LPSTR   lpszValueName,
2068         LPDWORD lpdwReserved,
2069         LPDWORD lpdwType,
2070         LPBYTE  lpbData,
2071         LPDWORD lpcbData
2072 ) {
2073         dprintf_info(reg,"RegQueryValueEx16(%x,%s,%p,%p,%p,%ld)\n",
2074                 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
2075                 lpcbData?*lpcbData:0
2076         );
2077         return RegQueryValueEx32A(
2078                 hkey,
2079                 lpszValueName,
2080                 lpdwReserved,
2081                 lpdwType,
2082                 lpbData,
2083                 lpcbData
2084         );
2085 }
2086
2087 /* RegQueryValueA               [ADVAPI32.156] */
2088 DWORD WINAPI RegQueryValue32A(
2089         HKEY    hkey,
2090         LPSTR   lpszSubKey,
2091         LPSTR   lpszData,
2092         LPDWORD lpcbData
2093 ) {
2094         HKEY    xhkey;
2095         DWORD   ret,lpdwType;
2096
2097         dprintf_info(reg,"RegQueryValue32A(%x,%s,%p,%ld)\n",
2098                 hkey,lpszSubKey,lpszData,
2099                 lpcbData?*lpcbData:0
2100         );
2101
2102         /* only open subkey, if we really do descend */
2103         if (lpszSubKey && *lpszSubKey) {
2104                 ret     = RegOpenKey16(hkey,lpszSubKey,&xhkey);
2105                 if (ret!=ERROR_SUCCESS)
2106                         return ret;
2107         } else
2108                 xhkey   = hkey;
2109
2110         lpdwType        = REG_SZ;
2111         ret     = RegQueryValueEx32A(
2112                 xhkey,
2113                 NULL,           /* lpszValueName NULL -> compat */
2114                 NULL,           /* lpdwReserved, must be NULL */
2115                 &lpdwType,
2116                 (LPBYTE)lpszData,
2117                 lpcbData
2118         );
2119         if (xhkey!=hkey)
2120                 RegCloseKey(xhkey);
2121         return ret;
2122 }
2123
2124 /* RegQueryValue                [SHELL.6] [KERNEL.224] */
2125 DWORD WINAPI RegQueryValue16(
2126         HKEY    hkey,
2127         LPSTR   lpszSubKey,
2128         LPSTR   lpszData,
2129         LPDWORD lpcbData
2130 ) {
2131         dprintf_info(reg,"RegQueryValue16(%x,%s,%p,%ld)\n",
2132                 hkey,lpszSubKey,lpszData,lpcbData?*lpcbData:0
2133         );
2134         /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
2135          *       anyway, so we just mask out the high 16 bit.
2136          *       (this (not so much incidently;) hopefully fixes Aldus FH4)
2137          */
2138         if (lpcbData)
2139                 *lpcbData &= 0xFFFF;
2140         return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2141 }
2142
2143 /*
2144  * Setting values of Registry keys
2145  *
2146  * Callpath:
2147  * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2148  *                                    RegSetValue32W   -> RegSetValueEx32W
2149  */
2150
2151 /* RegSetValueExW               [ADVAPI32.170] */
2152 DWORD WINAPI RegSetValueEx32W(
2153         HKEY    hkey,
2154         LPWSTR  lpszValueName,
2155         DWORD   dwReserved,
2156         DWORD   dwType,
2157         LPBYTE  lpbData,
2158         DWORD   cbData
2159 ) {
2160         LPKEYSTRUCT     lpkey;
2161         int             i;
2162
2163         dprintf_info(reg,"RegSetValueEx32W(%x,%s,%ld,%ld,%p,%ld)\n",
2164                 hkey,W2C(lpszValueName,0),dwReserved,dwType,lpbData,cbData
2165         );
2166         /* we no longer care about the lpbData type here... */
2167         lpkey   = lookup_hkey(hkey);
2168         if (!lpkey)
2169                 return SHELL_ERROR_BADKEY;
2170
2171         lpkey->flags |= REG_OPTION_TAINTED;
2172
2173         if (lpszValueName==NULL) {
2174                 for (i=0;i<lpkey->nrofvalues;i++)
2175                         if (lpkey->values[i].name==NULL)
2176                                 break;
2177         } else {
2178                 for (i=0;i<lpkey->nrofvalues;i++)
2179                         if (    lpkey->values[i].name &&
2180                                 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
2181                         )
2182                                 break;
2183         }
2184         if (i==lpkey->nrofvalues) {
2185                 lpkey->values = (LPKEYVALUE)xrealloc(
2186                                         lpkey->values,
2187                                         (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2188                                 );
2189                 lpkey->nrofvalues++;
2190                 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2191         }
2192         if (lpkey->values[i].name==NULL)
2193                 if (lpszValueName)
2194                         lpkey->values[i].name = strdupW(lpszValueName);
2195                 else
2196                         lpkey->values[i].name = NULL;
2197         lpkey->values[i].len    = cbData;
2198         lpkey->values[i].type   = dwType;
2199         if (lpkey->values[i].data !=NULL)
2200                 free(lpkey->values[i].data);
2201         lpkey->values[i].data   = (LPBYTE)xmalloc(cbData);
2202         lpkey->values[i].lastmodified = time(NULL);
2203         memcpy(lpkey->values[i].data,lpbData,cbData);
2204         return SHELL_ERROR_SUCCESS;
2205 }
2206
2207 /* RegSetValueExA               [ADVAPI32.169] */
2208 DWORD WINAPI RegSetValueEx32A(
2209         HKEY    hkey,
2210         LPSTR   lpszValueName,
2211         DWORD   dwReserved,
2212         DWORD   dwType,
2213         LPBYTE  lpbData,
2214         DWORD   cbData
2215 ) {
2216         LPBYTE  buf;
2217         LPWSTR  lpszValueNameW;
2218         DWORD   ret;
2219
2220         dprintf_info(reg,"RegSetValueEx32A(%x,%s,%ld,%ld,%p,%ld)\n",
2221                 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2222         );
2223         if ((1<<dwType) & UNICONVMASK) {
2224                 buf=(LPBYTE)strdupA2W(lpbData);
2225                 cbData=2*strlen(lpbData)+2;
2226         } else
2227                 buf=lpbData;
2228         if (lpszValueName)
2229                 lpszValueNameW = strdupA2W(lpszValueName);
2230         else
2231                 lpszValueNameW = NULL;
2232         ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2233         if (lpszValueNameW)
2234                 free(lpszValueNameW);
2235         if (buf!=lpbData)
2236                 free(buf);
2237         return ret;
2238 }
2239
2240 /* RegSetValueEx                [KERNEL.226] */
2241 DWORD WINAPI RegSetValueEx16(
2242         HKEY    hkey,
2243         LPSTR   lpszValueName,
2244         DWORD   dwReserved,
2245         DWORD   dwType,
2246         LPBYTE  lpbData,
2247         DWORD   cbData
2248 ) {
2249         dprintf_info(reg,"RegSetValueEx16(%x,%s,%ld,%ld,%p,%ld)\n",
2250                 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2251         );
2252         return RegSetValueEx32A(hkey,lpszValueName,dwReserved,dwType,lpbData,cbData);
2253 }
2254
2255 /* RegSetValueW                 [ADVAPI32.171] */
2256 DWORD WINAPI RegSetValue32W(
2257         HKEY    hkey,
2258         LPCWSTR lpszSubKey,
2259         DWORD   dwType,
2260         LPCWSTR lpszData,
2261         DWORD   cbData
2262 ) {
2263         HKEY    xhkey;
2264         DWORD   ret;
2265
2266         dprintf_info(reg,"RegSetValue32W(%x,%s,%ld,%s,%ld)\n",
2267                 hkey,W2C(lpszSubKey,0),dwType,W2C(lpszData,0),cbData
2268         );
2269         if (lpszSubKey && *lpszSubKey) {
2270                 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2271                 if (ret!=ERROR_SUCCESS)
2272                         return ret;
2273         } else
2274                 xhkey=hkey;
2275         if (dwType!=REG_SZ) {
2276                 fprintf(stddeb,"RegSetValueX called with dwType=%ld!\n",dwType);
2277                 dwType=REG_SZ;
2278         }
2279         if (cbData!=2*lstrlen32W(lpszData)+2) {
2280                 dprintf_info(reg,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2281                         cbData,W2C(lpszData,0),2*lstrlen32W(lpszData)+2
2282                 );
2283                 cbData=2*lstrlen32W(lpszData)+2;
2284         }
2285         ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2286         if (hkey!=xhkey)
2287                 RegCloseKey(xhkey);
2288         return ret;
2289
2290 }
2291 /* RegSetValueA                 [ADVAPI32.168] */
2292 DWORD WINAPI RegSetValue32A(
2293         HKEY    hkey,
2294         LPCSTR  lpszSubKey,
2295         DWORD   dwType,
2296         LPCSTR  lpszData,
2297         DWORD   cbData
2298 ) {
2299         DWORD   ret;
2300         HKEY    xhkey;
2301
2302         dprintf_info(reg,"RegSetValue32A(%x,%s,%ld,%s,%ld)\n",
2303                 hkey,lpszSubKey,dwType,lpszData,cbData
2304         );
2305         if (lpszSubKey && *lpszSubKey) {
2306                 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2307                 if (ret!=ERROR_SUCCESS)
2308                         return ret;
2309         } else
2310                 xhkey=hkey;
2311
2312         if (dwType!=REG_SZ) {
2313                 dprintf_info(reg,"RegSetValueA called with dwType=%ld!\n",dwType);
2314                 dwType=REG_SZ;
2315         }
2316         if (cbData!=strlen(lpszData)+1)
2317                 cbData=strlen(lpszData)+1;
2318         ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2319         if (xhkey!=hkey)
2320                 RegCloseKey(xhkey);
2321         return ret;
2322 }
2323
2324 /* RegSetValue                  [KERNEL.221] [SHELL.5] */
2325 DWORD WINAPI RegSetValue16(
2326         HKEY    hkey,
2327         LPCSTR  lpszSubKey,
2328         DWORD   dwType,
2329         LPCSTR  lpszData,
2330         DWORD   cbData
2331 ) {
2332         DWORD   ret;
2333         dprintf_info(reg,"RegSetValue16(%x,%s,%ld,%s,%ld)\n",
2334                 hkey,lpszSubKey,dwType,lpszData,cbData
2335         );
2336         ret=RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2337         return ret;
2338 }
2339
2340 /* 
2341  * Key Enumeration
2342  *
2343  * Callpath:
2344  * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2345  *                              RegEnumKey32W   -> RegEnumKeyEx32W
2346  */
2347
2348 /* RegEnumKeyExW                [ADVAPI32.139] */
2349 DWORD WINAPI RegEnumKeyEx32W(
2350         HKEY    hkey,
2351         DWORD   iSubkey,
2352         LPWSTR  lpszName,
2353         LPDWORD lpcchName,
2354         LPDWORD lpdwReserved,
2355         LPWSTR  lpszClass,
2356         LPDWORD lpcchClass,
2357         FILETIME        *ft
2358 ) {
2359         LPKEYSTRUCT     lpkey,lpxkey;
2360
2361         dprintf_info(reg,"RegEnumKeyEx32W(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2362                 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2363         );
2364         lpkey=lookup_hkey(hkey);
2365         if (!lpkey)
2366                 return SHELL_ERROR_BADKEY;
2367         if (!lpkey->nextsub)
2368                 return ERROR_NO_MORE_ITEMS;
2369         lpxkey=lpkey->nextsub;
2370         while (iSubkey && lpxkey) {
2371                 iSubkey--;
2372                 lpxkey=lpxkey->next;
2373         }
2374         if (iSubkey || !lpxkey)
2375                 return ERROR_NO_MORE_ITEMS;
2376         if (2*lstrlen32W(lpxkey->keyname)+2>*lpcchName)
2377                 return ERROR_MORE_DATA;
2378         memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2379         if (lpszClass) {
2380                 /* what should we write into it? */
2381                 *lpszClass              = 0;
2382                 *lpcchClass     = 2;
2383         }
2384         return ERROR_SUCCESS;
2385
2386 }
2387
2388 /* RegEnumKeyW                  [ADVAPI32.140] */
2389 DWORD WINAPI RegEnumKey32W(
2390         HKEY    hkey,
2391         DWORD   iSubkey,
2392         LPWSTR  lpszName,
2393         DWORD   lpcchName
2394 ) {
2395         FILETIME        ft;
2396
2397         dprintf_info(reg,"RegEnumKey32W(%x,%ld,%p,%ld)\n",
2398                 hkey,iSubkey,lpszName,lpcchName
2399         );
2400         return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2401 }
2402 /* RegEnumKeyExA                [ADVAPI32.138] */
2403 DWORD WINAPI RegEnumKeyEx32A(
2404         HKEY    hkey,
2405         DWORD   iSubkey,
2406         LPSTR   lpszName,
2407         LPDWORD lpcchName,
2408         LPDWORD lpdwReserved,
2409         LPSTR   lpszClass,
2410         LPDWORD lpcchClass,
2411         FILETIME        *ft
2412 ) {
2413         DWORD   ret,lpcchNameW,lpcchClassW;
2414         LPWSTR  lpszNameW,lpszClassW;
2415
2416
2417         dprintf_info(reg,"RegEnumKeyEx32A(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2418                 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2419         );
2420         if (lpszName) {
2421                 lpszNameW       = (LPWSTR)xmalloc(*lpcchName*2);
2422                 lpcchNameW      = *lpcchName*2;
2423         } else {
2424                 lpszNameW       = NULL;
2425                 lpcchNameW      = 0;
2426         }
2427         if (lpszClass) {
2428                 lpszClassW              = (LPWSTR)xmalloc(*lpcchClass*2);
2429                 lpcchClassW     = *lpcchClass*2;
2430         } else {
2431                 lpszClassW      =0;
2432                 lpcchClassW=0;
2433         }
2434         ret=RegEnumKeyEx32W(
2435                 hkey,
2436                 iSubkey,
2437                 lpszNameW,
2438                 &lpcchNameW,
2439                 lpdwReserved,
2440                 lpszClassW,
2441                 &lpcchClassW,
2442                 ft
2443         );
2444         if (ret==ERROR_SUCCESS) {
2445                 lstrcpyWtoA(lpszName,lpszNameW);
2446                 *lpcchName=strlen(lpszName);
2447                 if (lpszClassW) {
2448                         lstrcpyWtoA(lpszClass,lpszClassW);
2449                         *lpcchClass=strlen(lpszClass);
2450                 }
2451         }
2452         if (lpszNameW)
2453                 free(lpszNameW);
2454         if (lpszClassW)
2455                 free(lpszClassW);
2456         return ret;
2457 }
2458
2459 /* RegEnumKeyA                  [ADVAPI32.137] */
2460 DWORD WINAPI RegEnumKey32A(
2461         HKEY    hkey,
2462         DWORD   iSubkey,
2463         LPSTR   lpszName,
2464         DWORD   lpcchName
2465 ) {
2466         FILETIME        ft;
2467
2468         dprintf_info(reg,"RegEnumKey32A(%x,%ld,%p,%ld)\n",
2469                 hkey,iSubkey,lpszName,lpcchName
2470         );
2471         return  RegEnumKeyEx32A(
2472                 hkey,
2473                 iSubkey,
2474                 lpszName,
2475                 &lpcchName,
2476                 NULL,
2477                 NULL,
2478                 NULL,
2479                 &ft
2480         );
2481 }
2482
2483 /* RegEnumKey                   [SHELL.7] [KERNEL.216] */
2484 DWORD WINAPI RegEnumKey16(
2485         HKEY    hkey,
2486         DWORD   iSubkey,
2487         LPSTR   lpszName,
2488         DWORD   lpcchName
2489 ) {
2490         dprintf_info(reg,"RegEnumKey16(%x,%ld,%p,%ld)\n",
2491                 hkey,iSubkey,lpszName,lpcchName
2492         );
2493         return RegEnumKey32A(hkey,iSubkey,lpszName,lpcchName);
2494 }
2495
2496 /* 
2497  * Enumerate Registry Values
2498  *
2499  * Callpath:
2500  * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2501  */
2502
2503 /* RegEnumValueW                [ADVAPI32.142] */
2504 DWORD WINAPI RegEnumValue32W(
2505         HKEY    hkey,
2506         DWORD   iValue,
2507         LPWSTR  lpszValue,
2508         LPDWORD lpcchValue,
2509         LPDWORD lpdReserved,
2510         LPDWORD lpdwType,
2511         LPBYTE  lpbData,
2512         LPDWORD lpcbData
2513 ) {
2514         LPKEYSTRUCT     lpkey;
2515         LPKEYVALUE      val;
2516
2517         dprintf_info(reg,"RegEnumValue32W(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2518                 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2519         );
2520         lpkey = lookup_hkey(hkey);
2521         if (!lpkey)
2522                 return SHELL_ERROR_BADKEY;
2523         if (lpkey->nrofvalues<=iValue)
2524                 return ERROR_NO_MORE_ITEMS;
2525         val     = lpkey->values+iValue;
2526
2527         if (val->name) {
2528                 if (lstrlen32W(val->name)*2+2>*lpcchValue) {
2529                         *lpcchValue = lstrlen32W(val->name)*2+2;
2530                         return ERROR_MORE_DATA;
2531                 }
2532                 memcpy(lpszValue,val->name,2*lstrlen32W(val->name)+2);
2533                 *lpcchValue=lstrlen32W(val->name)*2+2;
2534         } else {
2535                 *lpszValue      = 0;
2536                 *lpcchValue     = 0;
2537         }
2538         if (lpdwType)
2539                 *lpdwType=val->type;
2540         if (lpbData) {
2541                 if (val->len>*lpcbData)
2542                         return ERROR_MORE_DATA;
2543                 memcpy(lpbData,val->data,val->len);
2544                 *lpcbData = val->len;
2545         }
2546         return SHELL_ERROR_SUCCESS;
2547 }
2548
2549 /* RegEnumValueA                [ADVAPI32.141] */
2550 DWORD WINAPI RegEnumValue32A(
2551         HKEY    hkey,
2552         DWORD   iValue,
2553         LPSTR   lpszValue,
2554         LPDWORD lpcchValue,
2555         LPDWORD lpdReserved,
2556         LPDWORD lpdwType,
2557         LPBYTE  lpbData,
2558         LPDWORD lpcbData
2559 ) {
2560         LPWSTR  lpszValueW;
2561         LPBYTE  lpbDataW;
2562         DWORD   ret,lpcbDataW;
2563
2564         dprintf_info(reg,"RegEnumValue32A(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2565                 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2566         );
2567
2568         lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2569         if (lpbData) {
2570                 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2571                 lpcbDataW = *lpcbData*2;
2572         } else
2573                 lpbDataW = NULL;
2574         ret=RegEnumValue32W(
2575                 hkey,
2576                 iValue,
2577                 lpszValueW,
2578                 lpcchValue,
2579                 lpdReserved,
2580                 lpdwType,
2581                 lpbDataW,
2582                 &lpcbDataW
2583         );
2584
2585         if (ret==ERROR_SUCCESS) {
2586                 lstrcpyWtoA(lpszValue,lpszValueW);
2587                 if (lpbData) {
2588                         if ((1<<*lpdwType) & UNICONVMASK) {
2589                                 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
2590                         } else {
2591                                 if (lpcbDataW > *lpcbData)
2592                                         ret     = ERROR_MORE_DATA;
2593                                 else
2594                                         memcpy(lpbData,lpbDataW,lpcbDataW);
2595                         }
2596                         *lpcbData = lpcbDataW;
2597                 }
2598         }
2599         if (lpbDataW)
2600                 free(lpbDataW);
2601         if (lpszValueW)
2602                 free(lpszValueW);
2603         return ret;
2604 }
2605
2606 /* RegEnumValue                 [KERNEL.223] */
2607 DWORD WINAPI RegEnumValue16(
2608         HKEY    hkey,
2609         DWORD   iValue,
2610         LPSTR   lpszValue,
2611         LPDWORD lpcchValue,
2612         LPDWORD lpdReserved,
2613         LPDWORD lpdwType,
2614         LPBYTE  lpbData,
2615         LPDWORD lpcbData
2616 ) {
2617         dprintf_info(reg,"RegEnumValue(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2618                 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2619         );
2620         return RegEnumValue32A(
2621                 hkey,
2622                 iValue,
2623                 lpszValue,
2624                 lpcchValue,
2625                 lpdReserved,
2626                 lpdwType,
2627                 lpbData,
2628                 lpcbData
2629         );
2630 }
2631
2632 /* 
2633  *  Close registry key
2634  */
2635 /* RegCloseKey                  [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2636 DWORD WINAPI RegCloseKey(HKEY hkey) {
2637         dprintf_info(reg,"RegCloseKey(%x)\n",hkey);
2638         remove_handle(hkey);
2639         return ERROR_SUCCESS;
2640 }
2641 /* 
2642  * Delete registry key
2643  *
2644  * Callpath:
2645  * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2646  */
2647 /* RegDeleteKeyW                [ADVAPI32.134] */
2648 DWORD WINAPI RegDeleteKey32W(HKEY hkey,LPWSTR lpszSubKey) {
2649         LPKEYSTRUCT     *lplpPrevKey,lpNextKey,lpxkey;
2650         LPWSTR          *wps;
2651         int             wpc,i;
2652
2653         dprintf_info(reg,"RegDeleteKey32W(%x,%s)\n",
2654                 hkey,W2C(lpszSubKey,0)
2655         );
2656         lpNextKey       = lookup_hkey(hkey);
2657         if (!lpNextKey) {
2658                 dprintf_info(reg, "  Badkey[1].\n");
2659                 return SHELL_ERROR_BADKEY;
2660         }
2661         /* we need to know the previous key in the hier. */
2662         if (!lpszSubKey || !*lpszSubKey) {
2663                 dprintf_info(reg, "  Badkey[2].\n");
2664                 return SHELL_ERROR_BADKEY;
2665         }
2666         split_keypath(lpszSubKey,&wps,&wpc);
2667         i       = 0;
2668         lpxkey  = lpNextKey;
2669         while (i<wpc-1) {
2670                 lpxkey=lpNextKey->nextsub;
2671                 while (lpxkey) {
2672                         dprintf_info(reg, "  Scanning [%s]\n",
2673                                      W2C (lpxkey->keyname, 0));
2674                         if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2675                                 break;
2676                         lpxkey=lpxkey->next;
2677                 }
2678                 if (!lpxkey) {
2679                         FREE_KEY_PATH;
2680                         dprintf_info(reg, "  Not found.\n");
2681                         /* not found is success */
2682                         return SHELL_ERROR_SUCCESS;
2683                 }
2684                 i++;
2685                 lpNextKey       = lpxkey;
2686         }
2687         lpxkey  = lpNextKey->nextsub;
2688         lplpPrevKey = &(lpNextKey->nextsub);
2689         while (lpxkey) {
2690                 dprintf_info(reg, "  Scanning [%s]\n",
2691                              W2C (lpxkey->keyname, 0));
2692                 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2693                         break;
2694                 lplpPrevKey     = &(lpxkey->next);
2695                 lpxkey          = lpxkey->next;
2696         }
2697         if (!lpxkey) {
2698                 FREE_KEY_PATH;
2699                 dprintf_warn(reg , "  Not found.\n");
2700                 return SHELL_ERROR_BADKEY;
2701         }
2702         if (lpxkey->nextsub) {
2703                 FREE_KEY_PATH;
2704                 dprintf_warn(reg , "  Not empty.\n");
2705                 return SHELL_ERROR_CANTWRITE;
2706         }
2707         *lplpPrevKey    = lpxkey->next;
2708         free(lpxkey->keyname);
2709         if (lpxkey->class)
2710                 free(lpxkey->class);
2711         if (lpxkey->values)
2712                 free(lpxkey->values);
2713         free(lpxkey);
2714         FREE_KEY_PATH;
2715         dprintf_info(reg, "  Done.\n");
2716         return  SHELL_ERROR_SUCCESS;
2717 }
2718
2719 /* RegDeleteKeyA                [ADVAPI32.133] */
2720 DWORD WINAPI RegDeleteKey32A(HKEY hkey,LPCSTR lpszSubKey) {
2721         LPWSTR  lpszSubKeyW;
2722         DWORD   ret;
2723
2724         dprintf_info(reg,"RegDeleteKey32A(%x,%s)\n",
2725                 hkey,lpszSubKey
2726         );
2727         lpszSubKeyW=HEAP_strdupAtoW(GetProcessHeap(),0,lpszSubKey);
2728         ret=RegDeleteKey32W(hkey,lpszSubKeyW);
2729         HeapFree(GetProcessHeap(),0,lpszSubKeyW);
2730         return ret;
2731 }
2732
2733 /* RegDeleteKey                 [SHELL.4] [KERNEL.219] */
2734 DWORD WINAPI RegDeleteKey16(HKEY hkey,LPCSTR lpszSubKey) {
2735         dprintf_info(reg,"RegDeleteKey16(%x,%s)\n",
2736                 hkey,lpszSubKey
2737         );
2738         return RegDeleteKey32A(hkey,lpszSubKey);
2739 }
2740
2741 /* 
2742  * Delete registry value
2743  *
2744  * Callpath:
2745  * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2746  */
2747 /* RegDeleteValueW              [ADVAPI32.136] */
2748 DWORD WINAPI RegDeleteValue32W(HKEY hkey,LPWSTR lpszValue)
2749 {
2750         DWORD           i;
2751         LPKEYSTRUCT     lpkey;
2752         LPKEYVALUE      val;
2753
2754         dprintf_info(reg,"RegDeleteValue32W(%x,%s)\n",
2755                 hkey,W2C(lpszValue,0)
2756         );
2757         lpkey=lookup_hkey(hkey);
2758         if (!lpkey)
2759                 return SHELL_ERROR_BADKEY;
2760         if (lpszValue) {
2761                 for (i=0;i<lpkey->nrofvalues;i++)
2762                         if (    lpkey->values[i].name &&
2763                                 !lstrcmpi32W(lpkey->values[i].name,lpszValue)
2764                         )
2765                                 break;
2766         } else {
2767                 for (i=0;i<lpkey->nrofvalues;i++)
2768                         if (lpkey->values[i].name==NULL)
2769                                 break;
2770         }
2771         if (i==lpkey->nrofvalues)
2772                 return SHELL_ERROR_BADKEY;/*FIXME: correct errorcode? */
2773         val     = lpkey->values+i;
2774         if (val->name) free(val->name);
2775         if (val->data) free(val->data);
2776         memcpy( 
2777                 lpkey->values+i,
2778                 lpkey->values+i+1,
2779                 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
2780         );
2781         lpkey->values   = (LPKEYVALUE)xrealloc(
2782                                 lpkey->values,
2783                                 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
2784                         );
2785         lpkey->nrofvalues--;
2786         return SHELL_ERROR_SUCCESS;
2787 }
2788
2789 /* RegDeleteValueA              [ADVAPI32.135] */
2790 DWORD WINAPI RegDeleteValue32A(HKEY hkey,LPSTR lpszValue)
2791 {
2792         LPWSTR  lpszValueW;
2793         DWORD   ret;
2794
2795         dprintf_info(reg, "RegDeleteValue32A(%x,%s)\n", hkey,lpszValue );
2796         lpszValueW=HEAP_strdupAtoW(GetProcessHeap(),0,lpszValue);
2797         ret=RegDeleteValue32W(hkey,lpszValueW);
2798         HeapFree(GetProcessHeap(),0,lpszValueW);
2799         return ret;
2800 }
2801
2802 /* RegDeleteValue               [KERNEL.222] */
2803 DWORD WINAPI RegDeleteValue16(HKEY hkey,LPSTR lpszValue)
2804 {
2805         dprintf_info(reg,"RegDeleteValue16(%x,%s)\n", hkey,lpszValue );
2806         return RegDeleteValue32A(hkey,lpszValue);
2807 }
2808
2809 /* RegFlushKey                  [ADVAPI32.143] [KERNEL.227] */
2810 DWORD WINAPI RegFlushKey(HKEY hkey)
2811 {
2812         dprintf_fixme(reg, "RegFlushKey(%x), STUB.\n", hkey);
2813         return SHELL_ERROR_SUCCESS;
2814 }
2815
2816 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2817
2818 /* RegQueryInfoKeyW             [ADVAPI32.153] */
2819 DWORD WINAPI RegQueryInfoKey32W(
2820         HKEY    hkey,
2821         LPWSTR  lpszClass,
2822         LPDWORD lpcchClass,
2823         LPDWORD lpdwReserved,
2824         LPDWORD lpcSubKeys,
2825         LPDWORD lpcchMaxSubkey,
2826         LPDWORD lpcchMaxClass,
2827         LPDWORD lpcValues,
2828         LPDWORD lpcchMaxValueName,
2829         LPDWORD lpccbMaxValueData,
2830         LPDWORD lpcbSecurityDescriptor,
2831         FILETIME        *ft
2832 ) {
2833         LPKEYSTRUCT     lpkey,lpxkey;
2834         int             nrofkeys,maxsubkey,maxclass,maxvalues,maxvname,maxvdata;
2835         int             i;
2836
2837         dprintf_info(reg,"RegQueryInfoKey32W(%x,......)\n",hkey);
2838         lpkey=lookup_hkey(hkey);
2839         if (!lpkey)
2840                 return SHELL_ERROR_BADKEY;
2841         if (lpszClass) {
2842                 if (lpkey->class) {
2843                         if (lstrlen32W(lpkey->class)*2+2>*lpcchClass) {
2844                                 *lpcchClass=lstrlen32W(lpkey->class)*2;
2845                                 return ERROR_MORE_DATA;
2846                         }
2847                         *lpcchClass=lstrlen32W(lpkey->class)*2;
2848                         memcpy(lpszClass,lpkey->class,lstrlen32W(lpkey->class));
2849                 } else {
2850                         *lpszClass      = 0;
2851                         *lpcchClass     = 0;
2852                 }
2853         } else {
2854                 if (lpcchClass)
2855                         *lpcchClass     = lstrlen32W(lpkey->class)*2;
2856         }
2857         lpxkey=lpkey->nextsub;
2858         nrofkeys=maxsubkey=maxclass=maxvalues=maxvname=maxvdata=0;
2859         while (lpxkey) {
2860                 nrofkeys++;
2861                 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
2862                         maxsubkey=lstrlen32W(lpxkey->keyname);
2863                 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
2864                         maxclass=lstrlen32W(lpxkey->class);
2865                 if (lpxkey->nrofvalues>maxvalues)
2866                         maxvalues=lpxkey->nrofvalues;
2867                 for (i=0;i<lpxkey->nrofvalues;i++) {
2868                         LPKEYVALUE      val=lpxkey->values+i;
2869
2870                         if (val->name && lstrlen32W(val->name)>maxvname)
2871                                 maxvname=lstrlen32W(val->name);
2872                         if (val->len>maxvdata)
2873                                 maxvdata=val->len;
2874                 }
2875                 lpxkey=lpxkey->next;
2876         }
2877         if (!maxclass) maxclass = 1;
2878         if (!maxvname) maxvname = 1;
2879         if (lpcSubKeys)
2880                 *lpcSubKeys     = nrofkeys;
2881         if (lpcchMaxSubkey)
2882                 *lpcchMaxSubkey = maxsubkey*2;
2883         if (lpcchMaxClass)
2884                 *lpcchMaxClass  = maxclass*2;
2885         if (lpcValues)
2886                 *lpcValues      = maxvalues;
2887         if (lpcchMaxValueName)
2888                 *lpcchMaxValueName= maxvname;
2889         if (lpccbMaxValueData)
2890                 *lpccbMaxValueData= maxvdata;
2891         return SHELL_ERROR_SUCCESS;
2892 }
2893
2894 /* RegQueryInfoKeyA             [ADVAPI32.152] */
2895 DWORD WINAPI RegQueryInfoKey32A(
2896         HKEY    hkey,
2897         LPSTR   lpszClass,
2898         LPDWORD lpcchClass,
2899         LPDWORD lpdwReserved,
2900         LPDWORD lpcSubKeys,
2901         LPDWORD lpcchMaxSubkey,
2902         LPDWORD lpcchMaxClass,
2903         LPDWORD lpcValues,
2904         LPDWORD lpcchMaxValueName,
2905         LPDWORD lpccbMaxValueData,
2906         LPDWORD lpcbSecurityDescriptor,
2907         FILETIME        *ft
2908 ) {
2909         LPWSTR          lpszClassW;
2910         DWORD           ret;
2911
2912         dprintf_info(reg,"RegQueryInfoKey32A(%x,......)\n",hkey);
2913         if (lpszClass) {
2914                 *lpcchClass*= 2;
2915                 lpszClassW  = (LPWSTR)xmalloc(*lpcchClass);
2916
2917         } else
2918                 lpszClassW  = NULL;
2919         ret=RegQueryInfoKey32W(
2920                 hkey,
2921                 lpszClassW,
2922                 lpcchClass,
2923                 lpdwReserved,
2924                 lpcSubKeys,
2925                 lpcchMaxSubkey,
2926                 lpcchMaxClass,
2927                 lpcValues,
2928                 lpcchMaxValueName,
2929                 lpccbMaxValueData,
2930                 lpcbSecurityDescriptor,
2931                 ft
2932         );
2933         if (ret==ERROR_SUCCESS && lpszClass)
2934                 lstrcpyWtoA(lpszClass,lpszClassW);
2935         if (lpcchClass)
2936                 *lpcchClass/=2;
2937         if (lpcchMaxSubkey)
2938                 *lpcchMaxSubkey/=2;
2939         if (lpcchMaxClass)
2940                 *lpcchMaxClass/=2;
2941         if (lpcchMaxValueName)
2942                 *lpcchMaxValueName/=2;
2943         if (lpszClassW)
2944                 free(lpszClassW);
2945         return ret;
2946 }
2947 /* RegConnectRegistryA          [ADVAPI32.127] */
2948 DWORD WINAPI RegConnectRegistry32A(LPCSTR machine,HKEY hkey,LPHKEY reskey)
2949 {
2950         fprintf(stderr,"RegConnectRegistry32A(%s,%08x,%p), STUB.\n",
2951                 machine,hkey,reskey
2952         );
2953         return ERROR_FILE_NOT_FOUND; /* FIXME */
2954 }