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