registry.c 12 KB
Newer Older
1
/*
2 3 4 5 6 7
 * $Id$
 *
 * Copyright (C) 1999 Alexandre Julliard
 *
 * Originally distributed under LPGL 2.1 (or later) by the Wine project.
 *
8 9
 * Modified for use with MPlayer, detailed CVS changelog at
 * http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * File now distributed as part of VLC media player with no modifications.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <pwd.h>
#include <sys/types.h>

#include "wine/winbase.h"
#include "wine/winreg.h"
#include "wine/winnt.h"
#include "wine/winerror.h"

#include "ext.h"
#include "registry.h"

//#undef TRACE
//#define TRACE printf

extern char *get_path ( char * );

// ...can be set before init_registry() call
char* regpathname = NULL;

static char* localregpathname = NULL;

typedef struct reg_handle_s
{
57 58 59 60
	int handle;
	char* name;
	struct reg_handle_s* next;
	struct reg_handle_s* prev;
61 62 63 64
} reg_handle_t;

struct reg_value
{
65 66 67 68
	int type;
	char* name;
	int len;
	char* value;
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
};

static struct reg_value* regs = NULL;
static int reg_size;
static reg_handle_t* head = NULL;

#define DIR -25

static void create_registry(void);
static void open_registry(void);
static void save_registry(void);
static void init_registry(void);


static void create_registry(void){
    if(regs)
    {
86 87 88
	printf("Logic error: create_registry() called with existing registry\n");
	save_registry();
	return;
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
    }
    regs=(struct reg_value*)malloc(3*sizeof(struct reg_value));
    regs[0].type=regs[1].type=DIR;
    regs[0].name=(char*)malloc(5);
    strcpy(regs[0].name, "HKLM");
    regs[1].name=(char*)malloc(5);
    strcpy(regs[1].name, "HKCU");
    regs[0].value=regs[1].value=NULL;
    regs[0].len=regs[1].len=0;
    reg_size=2;
    head = 0;
    save_registry();
}

static void open_registry(void)
{
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
	int fd;
	int i;
	unsigned int len;
	if(regs)
	{
		printf("Multiple open_registry(>\n");
		return;
	}
	fd = open(localregpathname, O_RDONLY);
	if (fd == -1)
	{
	    printf("Creating new registry\n");
	    create_registry();
	    return;
	}
	read(fd, &reg_size, 4);
	regs=(struct reg_value*)malloc(reg_size*sizeof(struct reg_value));
	head = 0;
	for(i=0; i<reg_size; i++)
	{
		read(fd,&regs[i].type,4);
		read(fd,&len,4);
		regs[i].name=(char*)malloc(len+1);
		if(regs[i].name==0)
		{
			reg_size=i+1;
			goto error;
		}
		read(fd, regs[i].name, len);
		regs[i].name[len]=0;
		read(fd,&regs[i].len,4);
		regs[i].value=(char*)malloc(regs[i].len+1);
		if(regs[i].value==0)
		{
		        free(regs[i].name);
			reg_size=i+1;
			goto error;
		}
		read(fd, regs[i].value, regs[i].len);
		regs[i].value[regs[i].len]=0;
	}
146
error:
147 148
	close(fd);
	return;
149 150 151 152
}

static void save_registry(void)
{
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
	int fd, i;
	if (!regs)
		init_registry();
	fd = open(localregpathname, O_WRONLY | O_CREAT, 00666);
	if (fd == -1)
	{
	    printf("Failed to open registry file '%s' for writing.\n",
		   localregpathname);
	    return;
	}
	write(fd, &reg_size, 4);
	for(i=0; i<reg_size; i++)
	{
	        unsigned len=strlen(regs[i].name);
		write(fd, &regs[i].type, 4);
		write(fd, &len, 4);
		write(fd, regs[i].name, len);
		write(fd, &regs[i].len, 4);
		write(fd, regs[i].value, regs[i].len);
	}
	close(fd);
174 175 176 177 178 179 180
}

void free_registry(void)
{
    reg_handle_t* t = head;
    while (t)
    {
181
	reg_handle_t* f = t;
182
        if (t->name)
183 184
	    free(t->name);
	t=t->prev;
185 186 187 188 189 190
        free(f);
    }
    head = 0;
    if (regs)
    {
        int i;
191 192 193 194 195 196 197
	for(i=0; i<reg_size; i++)
	{
	    free(regs[i].name);
	    free(regs[i].value);
	}
	free(regs);
	regs = 0;
198 199 200
    }

    if (localregpathname && localregpathname != regpathname)
201
	free(localregpathname);
202 203 204 205 206 207
    localregpathname = 0;
}


static reg_handle_t* find_handle_by_name(const char* name)
{
208 209 210 211 212 213 214 215 216
	reg_handle_t* t;
	for(t=head; t; t=t->prev)
	{
		if(!strcmp(t->name, name))
		{
			return t;
		}
	}
	return 0;
217 218 219
}
static struct reg_value* find_value_by_name(const char* name)
{
220 221 222 223 224
	int i;
	for(i=0; i<reg_size; i++)
		if(!strcmp(regs[i].name, name))
			return regs+i;
	return 0;
225 226 227
}
static reg_handle_t* find_handle(int handle)
{
228 229 230 231 232 233 234 235 236
	reg_handle_t* t;
	for(t=head; t; t=t->prev)
	{
		if(t->handle==handle)
		{
			return t;
		}
	}
	return 0;
237 238 239
}
static int generate_handle()
{
240 241 242 243 244
	static unsigned int zz=249;
	zz++;
	while((zz==HKEY_LOCAL_MACHINE) || (zz==HKEY_CURRENT_USER))
		zz++;
	return zz;
245 246 247 248
}

static reg_handle_t* insert_handle(long handle, const char* name)
{
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
	reg_handle_t* t;
	t=(reg_handle_t*)malloc(sizeof(reg_handle_t));
	if(head==0)
	{
		t->prev=0;
	}
	else
	{
		head->next=t;
		t->prev=head;
	}
	t->next=0;
	t->name=(char*)malloc(strlen(name)+1);
	strcpy(t->name, name);
	t->handle=handle;
	head=t;
	return t;
266 267 268
}
static char* build_keyname(long key, const char* subkey)
{
269 270 271 272 273 274 275 276 277 278 279 280 281 282
	char* full_name;
	reg_handle_t* t;
 	if((t=find_handle(key))==0)
	{
		TRACE("Invalid key\n");
		return NULL;
	}
	if(subkey==NULL)
		subkey="<default>";
	full_name=(char*)malloc(strlen(t->name)+strlen(subkey)+10);
	strcpy(full_name, t->name);
	strcat(full_name, "\\");
	strcat(full_name, subkey);
	return full_name;
283 284 285
}
static struct reg_value* insert_reg_value(int handle, const char* name, int type, const void* value, int len)
{
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
	reg_handle_t* t;
	struct reg_value* v;
	char* fullname;
	if((fullname=build_keyname(handle, name))==NULL)
	{
		TRACE("Invalid handle\n");
		return NULL;
	}

	if((v=find_value_by_name(fullname))==0)
	//creating new value in registry
	{
		if(regs==0)
		    create_registry();
		regs=(struct reg_value*)realloc(regs, sizeof(struct reg_value)*(reg_size+1));
		//regs=(struct reg_value*)my_realloc(regs, sizeof(struct reg_value)*(reg_size+1));
		v=regs+reg_size;
		reg_size++;
	}
	else
	//replacing old one
	{
	    free(v->value);
	    free(v->name);
	}
	TRACE("RegInsert '%s'  %p  v:%d  len:%d\n", name, value, *(int*)value, len);
	v->type=type;
	v->len=len;
	v->value=(char*)malloc(len);
	memcpy(v->value, value, len);
	v->name=(char*)malloc(strlen(fullname)+1);
	strcpy(v->name, fullname);
318
        free(fullname);
319 320
	save_registry();
	return v;
321 322 323 324
}

static void init_registry(void)
{
325 326 327
	TRACE("Initializing registry\n");
	// can't be free-ed - it's static and probably thread
	// unsafe structure which is stored in glibc
328 329

#ifdef MPLAYER
330 331
	regpathname = get_path("registry");
	localregpathname = regpathname;
332
#else
333
	// regpathname is an external pointer
334
        //
335 336
	// registry.c is holding its own internal pointer
	// localregpathname  - which is being allocate/deallocated
337

338 339
	if (localregpathname == 0)
	{
340
            const char* pthn = regpathname;
341 342 343 344 345
	    if (!regpathname)
	    {
		// avifile - for now reading data from user's home
		struct passwd* pwent;
		pwent = getpwuid(geteuid());
346
                pthn = pwent->pw_dir;
347
	    }
348

349 350 351 352
	    localregpathname = (char*)malloc(strlen(pthn)+20);
	    strcpy(localregpathname, pthn);
	    strcat(localregpathname, "/.registry");
	}
353 354
#endif

355 356 357
	open_registry();
	insert_handle(HKEY_LOCAL_MACHINE, "HKLM");
	insert_handle(HKEY_CURRENT_USER, "HKCU");
358 359 360 361
}

static reg_handle_t* find_handle_2(long key, const char* subkey)
{
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
	char* full_name;
	reg_handle_t* t;
 	if((t=find_handle(key))==0)
	{
		TRACE("Invalid key\n");
		return (reg_handle_t*)-1;
	}
	if(subkey==NULL)
		return t;
	full_name=(char*)malloc(strlen(t->name)+strlen(subkey)+10);
	strcpy(full_name, t->name);
	strcat(full_name, "\\");
	strcat(full_name, subkey);
	t=find_handle_by_name(full_name);
	free(full_name);
	return t;
378 379 380 381 382 383 384 385 386 387 388 389
}

long __stdcall RegOpenKeyExA(long key, const char* subkey, long reserved, long access, int* newkey)
{
    char* full_name;
    reg_handle_t* t;
    struct reg_value* v;
    TRACE("Opening key %s\n", subkey);

    if(!regs)
        init_registry()
;
390
/*	t=find_handle_2(key, subkey);
391

392 393
	if(t==0)
		return -1;
394

395 396
	if(t==(reg_handle_t*)-1)
		return -1;
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
*/
    full_name=build_keyname(key, subkey);
    if(!full_name)
        return -1;
    TRACE("Opening key Fullname %s\n", full_name);
    v=find_value_by_name(full_name);

    t=insert_handle(generate_handle(), full_name);
    *newkey=t->handle;
    free(full_name);

    return 0;
}
long __stdcall RegCloseKey(long key)
{
    reg_handle_t *handle;
    if(key==(long)HKEY_LOCAL_MACHINE)
414
	return 0;
415
    if(key==(long)HKEY_CURRENT_USER)
416
	return 0;
417 418
    handle=find_handle(key);
    if(handle==0)
419
	return 0;
420
    if(handle->prev)
421
	handle->prev->next=handle->next;
422
    if(handle->next)
423
	handle->next->prev=handle->prev;
424
    if(handle->name)
425
	free(handle->name);
426
    if(handle==head)
427
	head=head->prev;
428 429 430 431 432 433 434 435 436 437
    free(handle);
    return 1;
}

long __stdcall RegQueryValueExA(long key, const char* value, int* reserved, int* type, int* data, int* count)
{
    struct reg_value* t;
    char* c;
    TRACE("Querying value %s\n", value);
    if(!regs)
438
	init_registry();
439 440 441

    c=build_keyname(key, value);
    if (!c)
442
	return 1;
443 444 445
    t=find_value_by_name(c);
    free(c);
    if (t==0)
446
	return 2;
447
    if (type)
448
	*type=t->type;
449 450
    if (data)
    {
451 452
	memcpy(data, t->value, (t->len<*count)?t->len:*count);
	TRACE("returning %d bytes: %d\n", t->len, *(int*)data);
453 454 455
    }
    if(*count<t->len)
    {
456 457
	*count=t->len;
	return ERROR_MORE_DATA;
458 459 460
    }
    else
    {
461
	*count=t->len;
462 463 464 465
    }
    return 0;
}
long __stdcall RegCreateKeyExA(long key, const char* name, long reserved,
466 467
		     void* classs, long options, long security,
		     void* sec_attr, int* newkey, int* status)
468 469 470 471 472 473
{
    reg_handle_t* t;
    char* fullname;
    struct reg_value* v;
    //        TRACE("Creating/Opening key %s\n", name);
    if(!regs)
474
	init_registry();
475 476 477

    fullname=build_keyname(key, name);
    if (!fullname)
478
	return 1;
479 480 481 482
    TRACE("Creating/Opening key %s\n", fullname);
    v=find_value_by_name(fullname);
    if(v==0)
    {
483 484 485 486
	int qw=45708;
	v=insert_reg_value(key, name, DIR, &qw, 4);
	if (status) *status=REG_CREATED_NEW_KEY;
	//		return 0;
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
    }

    t=insert_handle(generate_handle(), fullname);
    *newkey=t->handle;
    free(fullname);
    return 0;
}

/*
LONG RegEnumValue(
  HKEY hKey,              // handle to key to query
  DWORD dwIndex,          // index of value to query
  LPTSTR lpValueName,     // address of buffer for value string
  LPDWORD lpcbValueName,  // address for size of value buffer
  LPDWORD lpReserved,     // reserved
  LPDWORD lpType,         // address of buffer for type code
  LPBYTE lpData,          // address of buffer for value data
  LPDWORD lpcbData        // address for size of data buffer
);
*/

long __stdcall RegEnumValueA(HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
509
		   LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count)
510 511 512 513 514 515 516
{
    // currenly just made to support MSZH & ZLIB
    //printf("Reg Enum 0x%x %d  %s %d   data: %p %d  %d >%s<\n", hkey, index,
    //       value, *val_count, data, *count, reg_size, data);
    reg_handle_t* t = find_handle(hkey);
    if (t && index < 10)
    {
517 518 519 520 521 522 523 524 525 526 527
	struct reg_value* v=find_value_by_name(t->name);
	if (v)
	{
	    memcpy(data, v->value, (v->len < *count) ? v->len : *count);
	    if(*count < v->len)
		*count = v->len;
	    if (type)
		*type = v->type;
	    //printf("Found handle  %s\n", v->name);
	    return 0;
	}
528 529 530 531 532 533 534 535 536 537
    }
    return ERROR_NO_MORE_ITEMS;
}

long __stdcall RegSetValueExA(long key, const char* name, long v1, long v2, const void* data, long size)
{
    struct reg_value* t;
    char* c;
    TRACE("Request to set value %s %d\n", name, *(const int*)data);
    if(!regs)
538
	init_registry();
539 540 541

    c=build_keyname(key, name);
    if(c==NULL)
542
	return 1;
543 544 545 546 547 548
    insert_reg_value(key, name, v2, data, size);
    free(c);
    return 0;
}

long __stdcall RegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcbName,
549 550
		   LPDWORD lpReserved, LPSTR lpClass, LPDWORD lpcbClass,
		   LPFILETIME lpftLastWriteTime)
551 552 553
{
    return ERROR_NO_MORE_ITEMS;
}