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