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