diff --git a/reactos/tools/Makefile b/reactos/tools/Makefile index c4e208b4855..c38b40ab038 100644 --- a/reactos/tools/Makefile +++ b/reactos/tools/Makefile @@ -14,7 +14,7 @@ TOOLS = \ CLEAN_FILES = $(TOOLS) -all: $(TOOLS) wmc_directory_target cdmake_directory_target +all: $(TOOLS) wmc_target cdmake_target mkhive_target buildno$(EXE_POSTFIX): buildno.c ../include/reactos/version.h $(HOST_CC) $(CFLAGS) -o buildno$(EXE_POSTFIX) buildno.c @@ -90,15 +90,20 @@ mkflpimg$(EXE_POSTFIX): mkflpimg.c endif -wmc_directory_target: +wmc_target: $(MAKE) -C wmc wmc$(EXE_POSTFIX) -cdmake_directory_target: +cdmake_target: $(MAKE) -C cdmake cdmake$(EXE_POSTFIX) +mkhive_target: + $(MAKE) -C mkhive mkhive$(EXE_POSTFIX) + + ifeq ($(HOST),mingw32-linux) clean: $(MAKE) -C cdmake clean + $(MAKE) -C mkhive clean $(MAKE) -C wmc clean rm mkconfig rm $(TOOLS) @@ -106,6 +111,7 @@ endif ifeq ($(HOST),mingw32-windows) clean: $(MAKE) -C cdmake clean + $(MAKE) -C mkhive clean $(MAKE) -C wmc clean del *$(EXE_POSTFIX) endif diff --git a/reactos/tools/mkhive/Makefile b/reactos/tools/mkhive/Makefile new file mode 100644 index 00000000000..cb50408e290 --- /dev/null +++ b/reactos/tools/mkhive/Makefile @@ -0,0 +1,49 @@ +# +# Hive-Maker +# +PATH_TO_TOP = ../.. + +TARGET = mkhive$(EXE_POSTFIX) + +all: $(TARGET) + +OBJECTS = mkhive.o binhive.o infcache.o reginf.o registry.o + +CLEAN_FILES = *.o mkhive$(EXE_POSTFIX) + +HOST_CFLAGS = -I. + +mkhive.o: mkhive.c + $(HOST_CC) $(HOST_CFLAGS) -c mkhive.c -o mkhive.o + +binhive.o: binhive.c + $(HOST_CC) $(HOST_CFLAGS) -c binhive.c -o binhive.o + +infcache.o: infcache.c + $(HOST_CC) $(HOST_CFLAGS) -c infcache.c -o infcache.o + +reginf.o: reginf.c + $(HOST_CC) $(HOST_CFLAGS) -c reginf.c -o reginf.o + +registry.o: registry.c + $(HOST_CC) $(HOST_CFLAGS) -c registry.c -o registry.o + +mkhive$(EXE_POSTFIX): $(OBJECTS) + $(HOST_CC) $(OBJECTS) -o mkhive$(EXE_POSTFIX) + +ifeq ($(HOST),mingw32-linux) +clean: + rm -f *.o + rm -f mkhive$(EXE_POSTFIX) +endif +ifeq ($(HOST),mingw32-windows) +clean: + del *.o + del mkhive$(EXE_POSTFIX) +endif + +.phony: clean + +include $(PATH_TO_TOP)/rules.mak + +# EOF diff --git a/reactos/tools/mkhive/binhive.c b/reactos/tools/mkhive/binhive.c new file mode 100644 index 00000000000..c0d8d66171f --- /dev/null +++ b/reactos/tools/mkhive/binhive.c @@ -0,0 +1,38 @@ +/* + * ReactOS kernel + * Copyright (C) 2003 ReactOS Team + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: binhive.c,v 1.1 2003/04/14 17:18:48 ekohl Exp $ + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS hive maker + * FILE: tools/mkhive/binhive.c + * PURPOSE: Binary hive export code + * PROGRAMMER: Eric Kohl + */ + +/* INCLUDES *****************************************************************/ + +#include "mkhive.h" + +BOOL +ExportBinaryHive (PCHAR FileName, + PCHAR KeyName) +{ + return TRUE; +} + +/* EOF */ diff --git a/reactos/tools/mkhive/binhive.h b/reactos/tools/mkhive/binhive.h new file mode 100644 index 00000000000..1830317d29e --- /dev/null +++ b/reactos/tools/mkhive/binhive.h @@ -0,0 +1,36 @@ +/* + * ReactOS kernel + * Copyright (C) 2003 ReactOS Team + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: binhive.h,v 1.1 2003/04/14 17:18:48 ekohl Exp $ + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS hive maker + * FILE: tools/mkhive/binhive.h + * PURPOSE: Binary hive export code + * PROGRAMMER: Eric Kohl + */ + +#ifndef __BINHIVE_H__ +#define __BINHIVE_H__ + +BOOL +ExportBinaryHive (PCHAR FileName, + PCHAR KeyName); + +#endif /* __BINHIVE_H__ */ + +/* EOF */ diff --git a/reactos/tools/mkhive/infcache.c b/reactos/tools/mkhive/infcache.c new file mode 100644 index 00000000000..148c72093cb --- /dev/null +++ b/reactos/tools/mkhive/infcache.c @@ -0,0 +1,1478 @@ +/* + * ReactOS kernel + * Copyright (C) 2003 ReactOS Team + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: infcache.c,v 1.1 2003/04/14 17:18:48 ekohl Exp $ + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS hive maker + * FILE: tools/mkhive/infcache.c + * PURPOSE: INF file parser that caches contents of INF file in memory + * PROGRAMMER: Royce Mitchell III + * Eric Kohl + */ + +/* INCLUDES *****************************************************************/ + +#include +#include + +#include "mkhive.h" +#include "infcache.h" + + +#define CONTROL_Z '\x1a' +#define MAX_SECTION_NAME_LEN 255 +#define MAX_FIELD_LEN 511 /* larger fields get silently truncated */ +/* actual string limit is MAX_INF_STRING_LENGTH+1 (plus terminating null) under Windows */ +#define MAX_STRING_LEN (MAX_INF_STRING_LENGTH+1) + + +typedef struct _INFCACHEFIELD +{ + struct _INFCACHEFIELD *Next; + struct _INFCACHEFIELD *Prev; + + CHAR Data[1]; +} INFCACHEFIELD, *PINFCACHEFIELD; + + +typedef struct _INFCACHELINE +{ + struct _INFCACHELINE *Next; + struct _INFCACHELINE *Prev; + + LONG FieldCount; + + PCHAR Key; + + PINFCACHEFIELD FirstField; + PINFCACHEFIELD LastField; + +} INFCACHELINE, *PINFCACHELINE; + + +typedef struct _INFCACHESECTION +{ + struct _INFCACHESECTION *Next; + struct _INFCACHESECTION *Prev; + + PINFCACHELINE FirstLine; + PINFCACHELINE LastLine; + + LONG LineCount; + + CHAR Name[1]; +} INFCACHESECTION, *PINFCACHESECTION; + + +typedef struct _INFCACHE +{ + PINFCACHESECTION FirstSection; + PINFCACHESECTION LastSection; + + PINFCACHESECTION StringsSection; +} INFCACHE, *PINFCACHE; + + +/* parser definitions */ + +enum parser_state +{ + LINE_START, /* at beginning of a line */ + SECTION_NAME, /* parsing a section name */ + KEY_NAME, /* parsing a key name */ + VALUE_NAME, /* parsing a value name */ + EOL_BACKSLASH, /* backslash at end of line */ + QUOTES, /* inside quotes */ + LEADING_SPACES, /* leading spaces */ + TRAILING_SPACES, /* trailing spaces */ + COMMENT, /* inside a comment */ + NB_PARSER_STATES +}; + +struct parser +{ + const CHAR *start; /* start position of item being parsed */ + const CHAR *end; /* end of buffer */ + PINFCACHE file; /* file being built */ + enum parser_state state; /* current parser state */ + enum parser_state stack[4]; /* state stack */ + int stack_pos; /* current pos in stack */ + + PINFCACHESECTION cur_section; /* pointer to the section being parsed*/ + PINFCACHELINE line; /* current line */ + unsigned int line_pos; /* current line position in file */ + unsigned int error; /* error code */ + unsigned int token_len; /* current token len */ + CHAR token[MAX_FIELD_LEN+1]; /* current token */ +}; + +typedef const CHAR * (*parser_state_func)( struct parser *parser, const CHAR *pos ); + +/* parser state machine functions */ +static const CHAR *line_start_state( struct parser *parser, const CHAR *pos ); +static const CHAR *section_name_state( struct parser *parser, const CHAR *pos ); +static const CHAR *key_name_state( struct parser *parser, const CHAR *pos ); +static const CHAR *value_name_state( struct parser *parser, const CHAR *pos ); +static const CHAR *eol_backslash_state( struct parser *parser, const CHAR *pos ); +static const CHAR *quotes_state( struct parser *parser, const CHAR *pos ); +static const CHAR *leading_spaces_state( struct parser *parser, const CHAR *pos ); +static const CHAR *trailing_spaces_state( struct parser *parser, const CHAR *pos ); +static const CHAR *comment_state( struct parser *parser, const CHAR *pos ); + +static const parser_state_func parser_funcs[NB_PARSER_STATES] = +{ + line_start_state, /* LINE_START */ + section_name_state, /* SECTION_NAME */ + key_name_state, /* KEY_NAME */ + value_name_state, /* VALUE_NAME */ + eol_backslash_state, /* EOL_BACKSLASH */ + quotes_state, /* QUOTES */ + leading_spaces_state, /* LEADING_SPACES */ + trailing_spaces_state, /* TRAILING_SPACES */ + comment_state /* COMMENT */ +}; + + +/* PRIVATE FUNCTIONS ********************************************************/ + +static PINFCACHELINE +InfpCacheFreeLine (PINFCACHELINE Line) +{ + PINFCACHELINE Next; + PINFCACHEFIELD Field; + + if (Line == NULL) + { + return NULL; + } + + Next = Line->Next; + if (Line->Key != NULL) + { + free (Line->Key); + Line->Key = NULL; + } + + /* Remove data fields */ + while (Line->FirstField != NULL) + { + Field = Line->FirstField->Next; + free (Line->FirstField); + Line->FirstField = Field; + } + Line->LastField = NULL; + + free (Line); + + return Next; +} + + +static PINFCACHESECTION +InfpCacheFreeSection (PINFCACHESECTION Section) +{ + PINFCACHESECTION Next; + + if (Section == NULL) + { + return NULL; + } + + /* Release all keys */ + Next = Section->Next; + while (Section->FirstLine != NULL) + { + Section->FirstLine = InfpCacheFreeLine (Section->FirstLine); + } + Section->LastLine = NULL; + + free (Section); + + return Next; +} + + +static PINFCACHESECTION +InfpCacheFindSection (PINFCACHE Cache, + PCHAR Name) +{ + PINFCACHESECTION Section = NULL; + + if (Cache == NULL || Name == NULL) + { + return NULL; + } + + /* iterate through list of sections */ + Section = Cache->FirstSection; + while (Section != NULL) + { + if (stricmp (Section->Name, Name) == 0) + { + return Section; + } + + /* get the next section*/ + Section = Section->Next; + } + + return NULL; +} + + +static PINFCACHESECTION +InfpCacheAddSection (PINFCACHE Cache, + PCHAR Name) +{ + PINFCACHESECTION Section = NULL; + ULONG Size; + + if (Cache == NULL || Name == NULL) + { + DPRINT ("Invalid parameter\n"); + return NULL; + } + + /* Allocate and initialize the new section */ + Size = sizeof(INFCACHESECTION) + strlen (Name); + Section = (PINFCACHESECTION)malloc (Size); + if (Section == NULL) + { + DPRINT ("RtlAllocateHeap() failed\n"); + return NULL; + } + memset (Section, 0, Size); + + /* Copy section name */ + strcpy (Section->Name, Name); + + /* Append section */ + if (Cache->FirstSection == NULL) + { + Cache->FirstSection = Section; + Cache->LastSection = Section; + } + else + { + Cache->LastSection->Next = Section; + Section->Prev = Cache->LastSection; + Cache->LastSection = Section; + } + + return Section; +} + + +static PINFCACHELINE +InfpCacheAddLine (PINFCACHESECTION Section) +{ + PINFCACHELINE Line; + + if (Section == NULL) + { + DPRINT("Invalid parameter\n"); + return NULL; + } + + Line = (PINFCACHELINE)malloc (sizeof(INFCACHELINE)); + if (Line == NULL) + { + DPRINT("RtlAllocateHeap() failed\n"); + return NULL; + } + memset (Line, 0, sizeof(INFCACHELINE)); + + /* Append line */ + if (Section->FirstLine == NULL) + { + Section->FirstLine = Line; + Section->LastLine = Line; + } + else + { + Section->LastLine->Next = Line; + Line->Prev = Section->LastLine; + Section->LastLine = Line; + } + Section->LineCount++; + + return Line; +} + + +static PVOID +InfpAddKeyToLine (PINFCACHELINE Line, + PCHAR Key) +{ + if (Line == NULL) + return NULL; + + if (Line->Key != NULL) + return NULL; + + Line->Key = (PCHAR)malloc (strlen (Key) + 1); + if (Line->Key == NULL) + return NULL; + + strcpy (Line->Key, Key); + + return (PVOID)Line->Key; +} + + +static PVOID +InfpAddFieldToLine (PINFCACHELINE Line, + PCHAR Data) +{ + PINFCACHEFIELD Field; + ULONG Size; + + Size = sizeof(INFCACHEFIELD) + strlen(Data); + Field = (PINFCACHEFIELD)malloc (Size); + if (Field == NULL) + { + return NULL; + } + memset (Field, 0, Size); + strcpy (Field->Data, Data); + + /* Append key */ + if (Line->FirstField == NULL) + { + Line->FirstField = Field; + Line->LastField = Field; + } + else + { + Line->LastField->Next = Field; + Field->Prev = Line->LastField; + Line->LastField = Field; + } + Line->FieldCount++; + + return (PVOID)Field; +} + + +static PINFCACHELINE +InfpCacheFindKeyLine (PINFCACHESECTION Section, + PCHAR Key) +{ + PINFCACHELINE Line; + + Line = Section->FirstLine; + while (Line != NULL) + { + if (Line->Key != NULL && stricmp (Line->Key, Key) == 0) + { + return Line; + } + + Line = Line->Next; + } + + return NULL; +} + + +/* push the current state on the parser stack */ +inline static void push_state( struct parser *parser, enum parser_state state ) +{ +// assert( parser->stack_pos < sizeof(parser->stack)/sizeof(parser->stack[0]) ); + parser->stack[parser->stack_pos++] = state; +} + + +/* pop the current state */ +inline static void pop_state( struct parser *parser ) +{ +// assert( parser->stack_pos ); + parser->state = parser->stack[--parser->stack_pos]; +} + + +/* set the parser state and return the previous one */ +inline static enum parser_state set_state( struct parser *parser, enum parser_state state ) +{ + enum parser_state ret = parser->state; + parser->state = state; + return ret; +} + + +/* check if the pointer points to an end of file */ +inline static int is_eof( struct parser *parser, const CHAR *ptr ) +{ + return (ptr >= parser->end || *ptr == CONTROL_Z); +} + + +/* check if the pointer points to an end of line */ +inline static int is_eol( struct parser *parser, const CHAR *ptr ) +{ + return (ptr >= parser->end || *ptr == CONTROL_Z || *ptr == '\r' /*'\n'*/); +} + + +/* push data from current token start up to pos into the current token */ +static int push_token( struct parser *parser, const CHAR *pos ) +{ + int len = pos - parser->start; + const CHAR *src = parser->start; + CHAR *dst = parser->token + parser->token_len; + + if (len > MAX_FIELD_LEN - parser->token_len) + len = MAX_FIELD_LEN - parser->token_len; + + parser->token_len += len; + for ( ; len > 0; len--, dst++, src++) + *dst = *src ? *src : ' '; + *dst = 0; + parser->start = pos; + + return 0; +} + + + +/* add a section with the current token as name */ +static PVOID add_section_from_token( struct parser *parser ) +{ + PINFCACHESECTION Section; + + if (parser->token_len > MAX_SECTION_NAME_LEN) + { + parser->error = STATUS_SECTION_NAME_TOO_LONG; + return NULL; + } + + Section = InfpCacheFindSection (parser->file, + parser->token); + if (Section == NULL) + { + /* need to create a new one */ + Section= InfpCacheAddSection (parser->file, + parser->token); + if (Section == NULL) + { + parser->error = STATUS_NOT_ENOUGH_MEMORY; + return NULL; + } + } + + parser->token_len = 0; + parser->cur_section = Section; + + return (PVOID)Section; +} + + +/* add a field containing the current token to the current line */ +static struct field *add_field_from_token( struct parser *parser, int is_key ) +{ + PVOID field; + CHAR *text; + + if (!parser->line) /* need to start a new line */ + { + if (parser->cur_section == NULL) /* got a line before the first section */ + { + parser->error = STATUS_WRONG_INF_STYLE; + return NULL; + } + + parser->line = InfpCacheAddLine (parser->cur_section); + if (parser->line == NULL) + goto error; + } + else + { +// assert(!is_key); + } + + if (is_key) + { + field = InfpAddKeyToLine(parser->line, parser->token); + } + else + { + field = InfpAddFieldToLine(parser->line, parser->token); + } + + if (field != NULL) + { + parser->token_len = 0; + return field; + } + +error: + parser->error = STATUS_NOT_ENOUGH_MEMORY; + return NULL; +} + + +/* close the current line and prepare for parsing a new one */ +static void close_current_line( struct parser *parser ) +{ + parser->line = NULL; +} + + + +/* handler for parser LINE_START state */ +static const CHAR *line_start_state( struct parser *parser, const CHAR *pos ) +{ + const CHAR *p; + + for (p = pos; !is_eof( parser, p ); p++) + { + switch(*p) + { +// case '\n': + case '\r': + p++; + parser->line_pos++; + close_current_line( parser ); + break; + case ';': + push_state( parser, LINE_START ); + set_state( parser, COMMENT ); + return p + 1; + case '[': + parser->start = p + 1; + set_state( parser, SECTION_NAME ); + return p + 1; + default: + if (!isspace(*p)) + { + parser->start = p; + set_state( parser, KEY_NAME ); + return p; + } + break; + } + } + close_current_line( parser ); + return NULL; +} + + +/* handler for parser SECTION_NAME state */ +static const CHAR *section_name_state( struct parser *parser, const CHAR *pos ) +{ + const CHAR *p; + + for (p = pos; !is_eol( parser, p ); p++) + { + if (*p == ']') + { + push_token( parser, p ); + if (add_section_from_token( parser ) == NULL) + return NULL; + push_state( parser, LINE_START ); + set_state( parser, COMMENT ); /* ignore everything else on the line */ + return p + 1; + } + } + parser->error = STATUS_BAD_SECTION_NAME_LINE; /* unfinished section name */ + return NULL; +} + + +/* handler for parser KEY_NAME state */ +static const CHAR *key_name_state( struct parser *parser, const CHAR *pos ) +{ + const CHAR *p, *token_end = parser->start; + + for (p = pos; !is_eol( parser, p ); p++) + { + if (*p == ',') break; + switch(*p) + { + + case '=': + push_token( parser, token_end ); + if (!add_field_from_token( parser, 1 )) return NULL; + parser->start = p + 1; + push_state( parser, VALUE_NAME ); + set_state( parser, LEADING_SPACES ); + return p + 1; + case ';': + push_token( parser, token_end ); + if (!add_field_from_token( parser, 0 )) return NULL; + push_state( parser, LINE_START ); + set_state( parser, COMMENT ); + return p + 1; + case '"': + push_token( parser, token_end ); + parser->start = p + 1; + push_state( parser, KEY_NAME ); + set_state( parser, QUOTES ); + return p + 1; + case '\\': + push_token( parser, token_end ); + parser->start = p; + push_state( parser, KEY_NAME ); + set_state( parser, EOL_BACKSLASH ); + return p; + default: + if (!isspace(*p)) token_end = p + 1; + else + { + push_token( parser, p ); + push_state( parser, KEY_NAME ); + set_state( parser, TRAILING_SPACES ); + return p; + } + break; + } + } + push_token( parser, token_end ); + set_state( parser, VALUE_NAME ); + return p; +} + + +/* handler for parser VALUE_NAME state */ +static const CHAR *value_name_state( struct parser *parser, const CHAR *pos ) +{ + const CHAR *p, *token_end = parser->start; + + for (p = pos; !is_eol( parser, p ); p++) + { + switch(*p) + { + case ';': + push_token( parser, token_end ); + if (!add_field_from_token( parser, 0 )) return NULL; + push_state( parser, LINE_START ); + set_state( parser, COMMENT ); + return p + 1; + case ',': + push_token( parser, token_end ); + if (!add_field_from_token( parser, 0 )) return NULL; + parser->start = p + 1; + push_state( parser, VALUE_NAME ); + set_state( parser, LEADING_SPACES ); + return p + 1; + case '"': + push_token( parser, token_end ); + parser->start = p + 1; + push_state( parser, VALUE_NAME ); + set_state( parser, QUOTES ); + return p + 1; + case '\\': + push_token( parser, token_end ); + parser->start = p; + push_state( parser, VALUE_NAME ); + set_state( parser, EOL_BACKSLASH ); + return p; + default: + if (!isspace(*p)) token_end = p + 1; + else + { + push_token( parser, p ); + push_state( parser, VALUE_NAME ); + set_state( parser, TRAILING_SPACES ); + return p; + } + break; + } + } + push_token( parser, token_end ); + if (!add_field_from_token( parser, 0 )) return NULL; + set_state( parser, LINE_START ); + return p; +} + + +/* handler for parser EOL_BACKSLASH state */ +static const CHAR *eol_backslash_state( struct parser *parser, const CHAR *pos ) +{ + const CHAR *p; + + for (p = pos; !is_eof( parser, p ); p++) + { + switch(*p) + { +// case '\n': + case '\r': + parser->line_pos++; +// parser->start = p + 1; + parser->start = p + 2; + set_state( parser, LEADING_SPACES ); +// return p + 1; + return p + 2; + case '\\': + continue; + case ';': + push_state( parser, EOL_BACKSLASH ); + set_state( parser, COMMENT ); + return p + 1; + default: + if (isspace(*p)) + continue; + push_token( parser, p ); + pop_state( parser ); + return p; + } + } + parser->start = p; + pop_state( parser ); + + return p; +} + + +/* handler for parser QUOTES state */ +static const CHAR *quotes_state( struct parser *parser, const CHAR *pos ) +{ + const CHAR *p, *token_end = parser->start; + + for (p = pos; !is_eol( parser, p ); p++) + { + if (*p == '"') + { + if (p+1 < parser->end && p[1] == '"') /* double quotes */ + { + push_token( parser, p + 1 ); + parser->start = token_end = p + 2; + p++; + } + else /* end of quotes */ + { + push_token( parser, p ); + parser->start = p + 1; + pop_state( parser ); + return p + 1; + } + } + } + push_token( parser, p ); + pop_state( parser ); + return p; +} + + +/* handler for parser LEADING_SPACES state */ +static const CHAR *leading_spaces_state( struct parser *parser, const CHAR *pos ) +{ + const CHAR *p; + + for (p = pos; !is_eol( parser, p ); p++) + { + if (*p == '\\') + { + parser->start = p; + set_state( parser, EOL_BACKSLASH ); + return p; + } + if (!isspace(*p)) + break; + } + parser->start = p; + pop_state( parser ); + return p; +} + + +/* handler for parser TRAILING_SPACES state */ +static const CHAR *trailing_spaces_state( struct parser *parser, const CHAR *pos ) +{ + const CHAR *p; + + for (p = pos; !is_eol( parser, p ); p++) + { + if (*p == '\\') + { + set_state( parser, EOL_BACKSLASH ); + return p; + } + if (!isspace(*p)) + break; + } + pop_state( parser ); + return p; +} + + +/* handler for parser COMMENT state */ +static const CHAR *comment_state( struct parser *parser, const CHAR *pos ) +{ + const CHAR *p = pos; + + while (!is_eol( parser, p )) + p++; + pop_state( parser ); + return p; +} + + +/* parse a complete buffer */ +static BOOL +InfpParseBuffer (PINFCACHE file, + const CHAR *buffer, + const CHAR *end, + PULONG error_line) +{ + struct parser parser; + const CHAR *pos = buffer; + + parser.start = buffer; + parser.end = end; + parser.file = file; + parser.line = NULL; + parser.state = LINE_START; + parser.stack_pos = 0; + parser.cur_section = NULL; + parser.line_pos = 1; + parser.error = 0; + parser.token_len = 0; + + /* parser main loop */ + while (pos) + pos = (parser_funcs[parser.state])(&parser, pos); + + if (parser.error) + { + if (error_line) + *error_line = parser.line_pos; + return parser.error; + } + + /* find the [strings] section */ + file->StringsSection = InfpCacheFindSection (file, + "Strings"); + + return TRUE; +} + + + +/* PUBLIC FUNCTIONS *********************************************************/ + +BOOL +InfOpenFile(PHINF InfHandle, + PCHAR FileName, + PULONG ErrorLine) +{ + FILE *File; + PCHAR FileBuffer; + ULONG FileLength; + PINFCACHE Cache; + + *InfHandle = NULL; + *ErrorLine = (ULONG)-1; + + /* Open the inf file */ + File = fopen (FileName, "rb"); + if (File == NULL) + { + DPRINT("fopen() failed\n"); + return FALSE; + } + + DPRINT("fopen() successful\n"); + + /* Query file size */ + fseek (File, 0, SEEK_END); + FileLength = ftell (File); + fseek (File, 0, SEEK_SET); + + DPRINT("File size: %lu\n", FileLength); + + /* Allocate file buffer */ + FileBuffer = malloc (FileLength + 1); + if (FileBuffer == NULL) + { + DPRINT1("malloc() failed\n"); + fclose (File); + return FALSE; + } + + /* Read file */ + if (fread (FileBuffer, FileLength, 1, File) < 0) + { + DPRINT ("fread() failed\n"); + fclose (File); + free (FileBuffer); + return FALSE; + } + + fclose (File); + + /* Append string terminator */ + FileBuffer[FileLength] = 0; + + /* Allocate infcache header */ + Cache = (PINFCACHE)malloc (sizeof(INFCACHE)); + if (Cache == NULL) + { + DPRINT("malloc() failed\n"); + free (FileBuffer); + return FALSE; + } + + /* Initialize inicache header */ + memset (Cache, 0, sizeof(INFCACHE)); + + /* Parse the inf buffer */ + if (!InfpParseBuffer (Cache, + FileBuffer, + FileBuffer + FileLength, + ErrorLine)) + { + free (Cache); + free (FileBuffer); + return FALSE; + } + + /* Free file buffer */ + free (FileBuffer); + + *InfHandle = (HINF)Cache; + + return TRUE; +} + + +VOID +InfCloseFile(HINF InfHandle) +{ + PINFCACHE Cache; + + Cache = (PINFCACHE)InfHandle; + + if (Cache == NULL) + { + return; + } + + while (Cache->FirstSection != NULL) + { + Cache->FirstSection = InfpCacheFreeSection(Cache->FirstSection); + } + Cache->LastSection = NULL; + + free (Cache); +} + + +BOOL +InfFindFirstLine (HINF InfHandle, + PCHAR Section, + PCHAR Key, + PINFCONTEXT Context) +{ + PINFCACHE Cache; + PINFCACHESECTION CacheSection; + PINFCACHELINE CacheLine; + + if (InfHandle == NULL || Section == NULL || Context == NULL) + { + DPRINT("Invalid parameter\n"); + return FALSE; + } + + Cache = (PINFCACHE)InfHandle; + + /* Iterate through list of sections */ + CacheSection = Cache->FirstSection; + while (Section != NULL) + { + DPRINT("Comparing '%s' and '%s'\n", CacheSection->Name, Section); + + /* Are the section names the same? */ + if (stricmp(CacheSection->Name, Section) == 0) + { + if (Key != NULL) + { + CacheLine = InfpCacheFindKeyLine (CacheSection, (PCHAR)Key); + } + else + { + CacheLine = CacheSection->FirstLine; + } + + if (CacheLine == NULL) + return FALSE; + + Context->Inf = (PVOID)Cache; + Context->Section = (PVOID)CacheSection; + Context->Line = (PVOID)CacheLine; + + return TRUE; + } + + /* Get the next section */ + CacheSection = CacheSection->Next; + } + + DPRINT("Section not found\n"); + + return FALSE; +} + + +BOOL +InfFindNextLine (PINFCONTEXT ContextIn, + PINFCONTEXT ContextOut) +{ + PINFCACHELINE CacheLine; + + if (ContextIn == NULL || ContextOut == NULL) + return FALSE; + + if (ContextIn->Line == NULL) + return FALSE; + + CacheLine = (PINFCACHELINE)ContextIn->Line; + if (CacheLine->Next == NULL) + return FALSE; + + if (ContextIn != ContextOut) + { + ContextOut->Inf = ContextIn->Inf; + ContextOut->Section = ContextIn->Section; + } + ContextOut->Line = (PVOID)(CacheLine->Next); + + return TRUE; +} + + +BOOL +InfFindFirstMatchLine (PINFCONTEXT ContextIn, + PCHAR Key, + PINFCONTEXT ContextOut) +{ + PINFCACHELINE CacheLine; + + if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0) + return FALSE; + + if (ContextIn->Inf == NULL || ContextIn->Section == NULL) + return FALSE; + + CacheLine = ((PINFCACHESECTION)(ContextIn->Section))->FirstLine; + while (CacheLine != NULL) + { + if (CacheLine->Key != NULL && stricmp (CacheLine->Key, Key) == 0) + { + + if (ContextIn != ContextOut) + { + ContextOut->Inf = ContextIn->Inf; + ContextOut->Section = ContextIn->Section; + } + ContextOut->Line = (PVOID)CacheLine; + + return TRUE; + } + + CacheLine = CacheLine->Next; + } + + return FALSE; +} + + +BOOL +InfFindNextMatchLine (PINFCONTEXT ContextIn, + PCHAR Key, + PINFCONTEXT ContextOut) +{ + PINFCACHELINE CacheLine; + + if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0) + return FALSE; + + if (ContextIn->Inf == NULL || ContextIn->Section == NULL || ContextIn->Line == NULL) + return FALSE; + + CacheLine = (PINFCACHELINE)ContextIn->Line; + while (CacheLine != NULL) + { + if (CacheLine->Key != NULL && stricmp (CacheLine->Key, Key) == 0) + { + + if (ContextIn != ContextOut) + { + ContextOut->Inf = ContextIn->Inf; + ContextOut->Section = ContextIn->Section; + } + ContextOut->Line = (PVOID)CacheLine; + + return TRUE; + } + + CacheLine = CacheLine->Next; + } + + return FALSE; +} + + +LONG +InfGetLineCount(HINF InfHandle, + PCHAR Section) +{ + PINFCACHE Cache; + PINFCACHESECTION CacheSection; + + if (InfHandle == NULL || Section == NULL) + { + DPRINT("Invalid parameter\n"); + return -1; + } + + Cache = (PINFCACHE)InfHandle; + + /* Iterate through list of sections */ + CacheSection = Cache->FirstSection; + while (Section != NULL) + { + DPRINT("Comparing '%s' and '%s'\n", CacheSection->Name, Section); + + /* Are the section names the same? */ + if (stricmp(CacheSection->Name, Section) == 0) + { + return CacheSection->LineCount; + } + + /* Get the next section */ + CacheSection = CacheSection->Next; + } + + DPRINT("Section not found\n"); + + return -1; +} + + +/* InfGetLineText */ + + +LONG +InfGetFieldCount(PINFCONTEXT Context) +{ + if (Context == NULL || Context->Line == NULL) + return 0; + + return ((PINFCACHELINE)Context->Line)->FieldCount; +} + + +BOOL +InfGetBinaryField (PINFCONTEXT Context, + ULONG FieldIndex, + PUCHAR ReturnBuffer, + ULONG ReturnBufferSize, + PULONG RequiredSize) +{ + PINFCACHELINE CacheLine; + PINFCACHEFIELD CacheField; + ULONG Index; + ULONG Size; + PUCHAR Ptr; + + if (Context == NULL || Context->Line == NULL || FieldIndex == 0) + { + DPRINT("Invalid parameter\n"); + return FALSE; + } + + if (RequiredSize != NULL) + *RequiredSize = 0; + + CacheLine = (PINFCACHELINE)Context->Line; + + if (FieldIndex > CacheLine->FieldCount) + return FALSE; + + CacheField = CacheLine->FirstField; + for (Index = 1; Index < FieldIndex; Index++) + CacheField = CacheField->Next; + + Size = CacheLine->FieldCount - FieldIndex + 1; + + if (RequiredSize != NULL) + *RequiredSize = Size; + + if (ReturnBuffer != NULL) + { + if (ReturnBufferSize < Size) + return FALSE; + + /* Copy binary data */ + Ptr = ReturnBuffer; + while (CacheField != NULL) + { + *Ptr = (UCHAR)strtoul (CacheField->Data, NULL, 16); + + Ptr++; + CacheField = CacheField->Next; + } + } + + return TRUE; +} + + +BOOL +InfGetIntField (PINFCONTEXT Context, + ULONG FieldIndex, + PLONG IntegerValue) +{ + PINFCACHELINE CacheLine; + PINFCACHEFIELD CacheField; + ULONG Index; + PCHAR Ptr; + + if (Context == NULL || Context->Line == NULL || IntegerValue == NULL) + { + DPRINT("Invalid parameter\n"); + return FALSE; + } + + CacheLine = (PINFCACHELINE)Context->Line; + + if (FieldIndex > CacheLine->FieldCount) + { + DPRINT("Invalid parameter\n"); + return FALSE; + } + + if (FieldIndex == 0) + { + Ptr = CacheLine->Key; + } + else + { + CacheField = CacheLine->FirstField; + for (Index = 1; Index < FieldIndex; Index++) + CacheField = CacheField->Next; + + Ptr = CacheField->Data; + } + + *IntegerValue = strtol (Ptr, NULL, 0); + + return TRUE; +} + + +BOOL +InfGetMultiSzField (PINFCONTEXT Context, + ULONG FieldIndex, + PCHAR ReturnBuffer, + ULONG ReturnBufferSize, + PULONG RequiredSize) +{ + PINFCACHELINE CacheLine; + PINFCACHEFIELD CacheField; + PINFCACHEFIELD FieldPtr; + ULONG Index; + ULONG Size; + PCHAR Ptr; + + if (Context == NULL || Context->Line == NULL || FieldIndex == 0) + { + DPRINT("Invalid parameter\n"); + return FALSE; + } + + if (RequiredSize != NULL) + *RequiredSize = 0; + + CacheLine = (PINFCACHELINE)Context->Line; + + if (FieldIndex > CacheLine->FieldCount) + return FALSE; + + CacheField = CacheLine->FirstField; + for (Index = 1; Index < FieldIndex; Index++) + CacheField = CacheField->Next; + + /* Calculate the required buffer size */ + FieldPtr = CacheField; + Size = 0; + while (FieldPtr != NULL) + { + Size += (strlen (FieldPtr->Data) + 1); + FieldPtr = FieldPtr->Next; + } + Size++; + + if (RequiredSize != NULL) + *RequiredSize = Size; + + if (ReturnBuffer != NULL) + { + if (ReturnBufferSize < Size) + return FALSE; + + /* Copy multi-sz string */ + Ptr = ReturnBuffer; + FieldPtr = CacheField; + while (FieldPtr != NULL) + { + Size = strlen (FieldPtr->Data) + 1; + + strcpy (Ptr, FieldPtr->Data); + + Ptr = Ptr + Size; + FieldPtr = FieldPtr->Next; + } + *Ptr = 0; + } + + return TRUE; +} + + +BOOL +InfGetStringField (PINFCONTEXT Context, + ULONG FieldIndex, + PCHAR ReturnBuffer, + ULONG ReturnBufferSize, + PULONG RequiredSize) +{ + PINFCACHELINE CacheLine; + PINFCACHEFIELD CacheField; + ULONG Index; + PCHAR Ptr; + ULONG Size; + + if (Context == NULL || Context->Line == NULL || FieldIndex == 0) + { + DPRINT("Invalid parameter\n"); + return FALSE; + } + + if (RequiredSize != NULL) + *RequiredSize = 0; + + CacheLine = (PINFCACHELINE)Context->Line; + + if (FieldIndex > CacheLine->FieldCount) + return FALSE; + + if (FieldIndex == 0) + { + Ptr = CacheLine->Key; + } + else + { + CacheField = CacheLine->FirstField; + for (Index = 1; Index < FieldIndex; Index++) + CacheField = CacheField->Next; + + Ptr = CacheField->Data; + } + + Size = wcslen (Ptr) + 1; + + if (RequiredSize != NULL) + *RequiredSize = Size; + + if (ReturnBuffer != NULL) + { + if (ReturnBufferSize < Size) + return FALSE; + + strcpy (ReturnBuffer, Ptr); + } + + return TRUE; +} + + + + +BOOL +InfGetData (PINFCONTEXT Context, + PCHAR *Key, + PCHAR *Data) +{ + PINFCACHELINE CacheKey; + + if (Context == NULL || Context->Line == NULL || Data == NULL) + { + DPRINT("Invalid parameter\n"); + return FALSE; + } + + CacheKey = (PINFCACHELINE)Context->Line; + if (Key != NULL) + *Key = CacheKey->Key; + + if (Data != NULL) + { + if (CacheKey->FirstField == NULL) + { + *Data = NULL; + } + else + { + *Data = CacheKey->FirstField->Data; + } + } + + return TRUE; +} + + +BOOL +InfGetDataField (PINFCONTEXT Context, + ULONG FieldIndex, + PCHAR *Data) +{ + PINFCACHELINE CacheLine; + PINFCACHEFIELD CacheField; + ULONG Index; + + if (Context == NULL || Context->Line == NULL || Data == NULL) + { + DPRINT("Invalid parameter\n"); + return FALSE; + } + + CacheLine = (PINFCACHELINE)Context->Line; + + if (FieldIndex > CacheLine->FieldCount) + return FALSE; + + if (FieldIndex == 0) + { + *Data = CacheLine->Key; + } + else + { + CacheField = CacheLine->FirstField; + for (Index = 1; Index < FieldIndex; Index++) + CacheField = CacheField->Next; + + *Data = CacheField->Data; + } + + return TRUE; +} + + +/* EOF */ diff --git a/reactos/tools/mkhive/infcache.h b/reactos/tools/mkhive/infcache.h new file mode 100644 index 00000000000..a91faef86ce --- /dev/null +++ b/reactos/tools/mkhive/infcache.h @@ -0,0 +1,132 @@ +/* + * ReactOS kernel + * Copyright (C) 2003 ReactOS Team + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: infcache.h,v 1.1 2003/04/14 17:18:48 ekohl Exp $ + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS hive maker + * FILE: tools/mkhive/infcache.h + * PURPOSE: INF file parser that caches contents of INF file in memory + * PROGRAMMER: Royce Mitchell III + * Eric Kohl + */ + +/* INCLUDES *****************************************************************/ + +#ifndef __INFCACHE_H__ +#define __INFCACHE_H__ + + +#define STATUS_BAD_SECTION_NAME_LINE (0xC0700001) +#define STATUS_SECTION_NAME_TOO_LONG (0xC0700002) +#define STATUS_WRONG_INF_STYLE (0xC0700003) +#define STATUS_NOT_ENOUGH_MEMORY (0xC0700004) + +#define MAX_INF_STRING_LENGTH 512 + +typedef PVOID HINF, *PHINF; + +typedef struct _INFCONTEXT +{ + PVOID Inf; +// PVOID CurrentInf; + PVOID Section; + PVOID Line; +} INFCONTEXT, *PINFCONTEXT; + + +/* FUNCTIONS ****************************************************************/ + +BOOL +InfOpenFile (PHINF InfHandle, + PCHAR FileName, + PULONG ErrorLine); + +VOID +InfCloseFile (HINF InfHandle); + + +BOOL +InfFindFirstLine (HINF InfHandle, + PCHAR Section, + PCHAR Key, + PINFCONTEXT Context); + +BOOL +InfFindNextLine (PINFCONTEXT ContextIn, + PINFCONTEXT ContextOut); + +BOOL +InfFindFirstMatchLine (PINFCONTEXT ContextIn, + PCHAR Key, + PINFCONTEXT ContextOut); + +BOOL +InfFindNextMatchLine (PINFCONTEXT ContextIn, + PCHAR Key, + PINFCONTEXT ContextOut); + + +LONG +InfGetLineCount (HINF InfHandle, + PCHAR Section); + +LONG +InfGetFieldCount (PINFCONTEXT Context); + + +BOOL +InfGetBinaryField (PINFCONTEXT Context, + ULONG FieldIndex, + PUCHAR ReturnBuffer, + ULONG ReturnBufferSize, + PULONG RequiredSize); + +BOOL +InfGetIntField (PINFCONTEXT Context, + ULONG FieldIndex, + PLONG IntegerValue); + +BOOL +InfGetMultiSzField (PINFCONTEXT Context, + ULONG FieldIndex, + PCHAR ReturnBuffer, + ULONG ReturnBufferSize, + PULONG RequiredSize); + +BOOL +InfGetStringField (PINFCONTEXT Context, + ULONG FieldIndex, + PCHAR ReturnBuffer, + ULONG ReturnBufferSize, + PULONG RequiredSize); + + + +BOOL +InfGetData (PINFCONTEXT Context, + PCHAR *Key, + PCHAR *Data); + +BOOL +InfGetDataField (PINFCONTEXT Context, + ULONG FieldIndex, + PCHAR *Data); + +#endif /* __INFCACHE_H__ */ + +/* EOF */ diff --git a/reactos/tools/mkhive/mkhive.c b/reactos/tools/mkhive/mkhive.c new file mode 100644 index 00000000000..64b38177bb6 --- /dev/null +++ b/reactos/tools/mkhive/mkhive.c @@ -0,0 +1,97 @@ +/* + * ReactOS kernel + * Copyright (C) 2003 ReactOS Team + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: mkhive.c,v 1.1 2003/04/14 17:18:48 ekohl Exp $ + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS hive maker + * FILE: tools/mkhive/mkhive.c + * PURPOSE: Hive maker + * PROGRAMMER: Eric Kohl + */ + +#include +#include + +#include "mkhive.h" +#include "registry.h" +#include "reginf.h" +#include "binhive.h" + +#ifndef WIN32 +#ifndef PATH_MAX +#define PATH_MAX 260 +#endif +#define DIR_SEPARATOR_CHAR '/' +#define DIR_SEPARATOR_STRING "/" +#else +#define DIR_SEPARATOR_CHAR '\\' +#define DIR_SEPARATOR_STRING "\\" +#endif + + +void usage (void) +{ + printf ("Usage: mkhive \n\n"); +} + + +int main (int argc, char *argv[]) +{ + char FileName[PATH_MAX]; + + if (argc < 3) + { + usage (); + } + + RegInitializeRegistry (); + + strcpy (FileName, argv[1]); + strcat (FileName, DIR_SEPARATOR_STRING); + strcat (FileName, "hivesys.inf"); + ImportRegistryFile (FileName, "AddReg", FALSE); + +#if 0 + strcpy (FileName, argv[1]); + strcat (FileName, DIR_SEPARATOR_STRING); + strcat (FileName, "hivecls.inf"); + ImportRegistryFile (FileName, "AddReg", FALSE); + + strcpy (FileName, argv[1]); + strcat (FileName, DIR_SEPARATOR_STRING); + strcat (FileName, "hivesft.inf"); + ImportRegistryFile (FileName, "AddReg", FALSE); + + strcpy (FileName, argv[1]); + strcat (FileName, DIR_SEPARATOR_STRING); + strcat (FileName, "hivedef.inf"); + ImportRegistryFile (FileName, "AddReg", FALSE); +#endif + + strcpy (FileName, argv[2]); + strcat (FileName, DIR_SEPARATOR_STRING); + strcat (FileName, "system"); + ExportBinaryHive (FileName, "\\Registy\\Machine\\System"); + + +// RegShutdownRegistry (); + + return 0; +} + +/* EOF */ diff --git a/reactos/tools/mkhive/mkhive.h b/reactos/tools/mkhive/mkhive.h new file mode 100644 index 00000000000..e8b4faef56c --- /dev/null +++ b/reactos/tools/mkhive/mkhive.h @@ -0,0 +1,74 @@ +/* + * ReactOS kernel + * Copyright (C) 2003 ReactOS Team + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: mkhive.h,v 1.1 2003/04/14 17:18:48 ekohl Exp $ + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS hive maker + * FILE: tools/mkhive/mkhive.h + * PURPOSE: Hive maker + * PROGRAMMER: Eric Kohl + */ + +#ifndef __MKHIVE_H__ +#define __MKHIVE_H__ + + +#define VOID void +typedef void *PVOID; +typedef char CHAR, *PCHAR; +typedef unsigned char UCHAR, *PUCHAR; +typedef short SHORT, *PSHORT; +typedef unsigned short USHORT, *PUSHORT; +typedef long LONG, *PLONG; +typedef unsigned long ULONG, *PULONG; + +typedef int BOOL, *PBOOL; + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef NULL +#define NULL ((void*)0) +#endif + + +#ifndef max +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef min +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + + +/* Debugging macros */ + +#define DPRINT1(args...) do { printf("(%s:%d) ",__FILE__,__LINE__); printf(args); } while(0); +#define CHECKPOINT1 do { printf("%s:%d\n",__FILE__,__LINE__); } while(0); + +#define DPRINT(args...) +#define CHECKPOINT + + +#endif /* __MKHIVE_H__ */ + +/* EOF */ diff --git a/reactos/tools/mkhive/reginf.c b/reactos/tools/mkhive/reginf.c new file mode 100644 index 00000000000..ee1fbd42ea8 --- /dev/null +++ b/reactos/tools/mkhive/reginf.c @@ -0,0 +1,470 @@ +/* + * ReactOS kernel + * Copyright (C) 2003 ReactOS Team + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: reginf.c,v 1.1 2003/04/14 17:18:48 ekohl Exp $ + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS hive maker + * FILE: tools/mkhive/reginf.h + * PURPOSE: Inf file import code + * PROGRAMMER: Eric Kohl + */ + +/* INCLUDES *****************************************************************/ + +#include +#include + +#include "mkhive.h" +#include "registry.h" +#include "infcache.h" + + + +#define FLG_ADDREG_BINVALUETYPE 0x00000001 +#define FLG_ADDREG_NOCLOBBER 0x00000002 +#define FLG_ADDREG_DELVAL 0x00000004 +#define FLG_ADDREG_APPEND 0x00000008 +#define FLG_ADDREG_KEYONLY 0x00000010 +#define FLG_ADDREG_OVERWRITEONLY 0x00000020 +#define FLG_ADDREG_TYPE_SZ 0x00000000 +#define FLG_ADDREG_TYPE_MULTI_SZ 0x00010000 +#define FLG_ADDREG_TYPE_EXPAND_SZ 0x00020000 +#define FLG_ADDREG_TYPE_BINARY (0x00000000 | FLG_ADDREG_BINVALUETYPE) +#define FLG_ADDREG_TYPE_DWORD (0x00010000 | FLG_ADDREG_BINVALUETYPE) +#define FLG_ADDREG_TYPE_NONE (0x00020000 | FLG_ADDREG_BINVALUETYPE) +#define FLG_ADDREG_TYPE_MASK (0xFFFF0000 | FLG_ADDREG_BINVALUETYPE) + + +/* FUNCTIONS ****************************************************************/ + +static BOOL +GetRootKey (PCHAR Name) +{ + if (!stricmp (Name, "HKCR")) + { + strcpy (Name, "\\Registry\\Machine\\SOFTWARE\\Classes\\"); + return TRUE; + } + + if (!stricmp (Name, "HKCU")) + { + strcpy (Name, "\\Registry\\User\\.DEFAULT\\"); + return TRUE; + } + + if (!stricmp (Name, "HKLM")) + { + strcpy (Name, "\\Registry\\Machine\\"); + return TRUE; + } + + if (!stricmp (Name, "HKU")) + { + strcpy (Name, "\\Registry\\User\\"); + return TRUE; + } + +#if 0 + if (!stricmp (Name, "HKR")) + return FALSE; +#endif + + return FALSE; +} + + +/*********************************************************************** + * append_multi_sz_value + * + * Append a multisz string to a multisz registry value. + */ +#if 0 +static void +append_multi_sz_value (HANDLE hkey, + const WCHAR *value, + const WCHAR *strings, + DWORD str_size ) +{ + DWORD size, type, total; + WCHAR *buffer, *p; + + if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return; + if (type != REG_MULTI_SZ) return; + + if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (size + str_size) * sizeof(WCHAR) ))) return; + if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done; + + /* compare each string against all the existing ones */ + total = size; + while (*strings) + { + int len = strlenW(strings) + 1; + + for (p = buffer; *p; p += strlenW(p) + 1) + if (!strcmpiW( p, strings )) break; + + if (!*p) /* not found, need to append it */ + { + memcpy( p, strings, len * sizeof(WCHAR) ); + p[len] = 0; + total += len; + } + strings += len; + } + if (total != size) + { + TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer) ); + RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, (BYTE *)buffer, total ); + } + done: + HeapFree( GetProcessHeap(), 0, buffer ); +} +#endif + +/*********************************************************************** + * delete_multi_sz_value + * + * Remove a string from a multisz registry value. + */ +#if 0 +static void delete_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *string ) +{ + DWORD size, type; + WCHAR *buffer, *src, *dst; + + if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return; + if (type != REG_MULTI_SZ) return; + /* allocate double the size, one for value before and one for after */ + if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size * 2 * sizeof(WCHAR) ))) return; + if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done; + src = buffer; + dst = buffer + size; + while (*src) + { + int len = strlenW(src) + 1; + if (strcmpiW( src, string )) + { + memcpy( dst, src, len * sizeof(WCHAR) ); + dst += len; + } + src += len; + } + *dst++ = 0; + if (dst != buffer + 2*size) /* did we remove something? */ + { + TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer + size) ); + RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, + (BYTE *)(buffer + size), dst - (buffer + size) ); + } + done: + HeapFree( GetProcessHeap(), 0, buffer ); +} +#endif + +/*********************************************************************** + * do_reg_operation + * + * Perform an add/delete registry operation depending on the flags. + */ +static BOOL +do_reg_operation(HKEY KeyHandle, + PCHAR ValueName, + PINFCONTEXT Context, + ULONG Flags) +{ + CHAR EmptyStr = (CHAR)0; + ULONG Type; + ULONG Size; +// NTSTATUS Status; + + if (Flags & FLG_ADDREG_DELVAL) /* deletion */ + { +#if 0 + if (ValueName) + { + RegDeleteValueW( hkey, value ); + } + else + { + RegDeleteKeyW( hkey, NULL ); + } +#endif + return TRUE; + } + + if (Flags & FLG_ADDREG_KEYONLY) + return TRUE; + +#if 0 + if (Flags & (FLG_ADDREG_NOCLOBBER | FLG_ADDREG_OVERWRITEONLY)) + { + BOOL exists = !RegQueryValueExW( hkey, value, NULL, NULL, NULL, NULL ); + if (exists && (flags & FLG_ADDREG_NOCLOBBER)) + return TRUE; + if (!exists & (flags & FLG_ADDREG_OVERWRITEONLY)) + return TRUE; + } +#endif + + switch (Flags & FLG_ADDREG_TYPE_MASK) + { + case FLG_ADDREG_TYPE_SZ: + Type = REG_SZ; + break; + + case FLG_ADDREG_TYPE_MULTI_SZ: + Type = REG_MULTI_SZ; + break; + + case FLG_ADDREG_TYPE_EXPAND_SZ: + Type = REG_EXPAND_SZ; + break; + + case FLG_ADDREG_TYPE_BINARY: + Type = REG_BINARY; + break; + + case FLG_ADDREG_TYPE_DWORD: + Type = REG_DWORD; + break; + + case FLG_ADDREG_TYPE_NONE: + Type = REG_NONE; + break; + + default: + Type = Flags >> 16; + break; + } + + if (!(Flags & FLG_ADDREG_BINVALUETYPE) || + (Type == REG_DWORD && InfGetFieldCount (Context) == 5)) + { + PCHAR Str = NULL; + + if (Type == REG_MULTI_SZ) + { + if (!InfGetMultiSzField (Context, 5, NULL, 0, &Size)) + Size = 0; + + if (Size) + { + Str = malloc (Size); + if (Str == NULL) + return FALSE; + + InfGetMultiSzField (Context, 5, Str, Size, NULL); + } + + if (Flags & FLG_ADDREG_APPEND) + { + if (Str == NULL) + return TRUE; + +// append_multi_sz_value( hkey, value, str, size ); + + free (Str); + return TRUE; + } + /* else fall through to normal string handling */ + } + else + { + if (!InfGetStringField (Context, 5, NULL, 0, &Size)) + Size = 0; + + if (Size) + { + Str = malloc (Size); + if (Str == NULL) + return FALSE; + + InfGetStringField (Context, 5, Str, Size, NULL); + } + } + + if (Type == REG_DWORD) + { + ULONG dw = Str ? strtol (Str, NULL, 0) : 0; + + DPRINT("setting dword %s to %lx\n", ValueName, dw); + + RegSetValue (KeyHandle, + ValueName, + Type, + (PVOID)&dw, + sizeof(ULONG)); + } + else + { + DPRINT ("setting value %wZ to %S\n", ValueName, Str); + + if (Str) + { + RegSetValue (KeyHandle, + ValueName, + Type, + (PVOID)Str, + Size); + } + else + { + RegSetValue (KeyHandle, + ValueName, + Type, + (PVOID)&EmptyStr, + sizeof(CHAR)); + } + } + free (Str); + } + else /* get the binary data */ + { + PUCHAR Data = NULL; + + if (!InfGetBinaryField (Context, 5, NULL, 0, &Size)) + Size = 0; + + if (Size) + { + Data = malloc (Size); + if (Data == NULL) + return FALSE; + + DPRINT("setting binary data %s len %lu\n", ValueName, Size); + InfGetBinaryField (Context, 5, Data, Size, NULL); + } + + RegSetValue (KeyHandle, + ValueName, + Type, + (PVOID)Data, + Size); + + free (Data); + } + + return TRUE; +} + + +/*********************************************************************** + * registry_callback + * + * Called once for each AddReg and DelReg entry in a given section. + */ +static BOOL +registry_callback (HINF hInf, PCHAR Section, BOOL Delete) +{ + CHAR Buffer[MAX_INF_STRING_LENGTH]; + PCHAR ValuePtr; + ULONG Flags; + ULONG Length; + + INFCONTEXT Context; + HKEY KeyHandle; + BOOL Ok; + + + Ok = InfFindFirstLine (hInf, Section, NULL, &Context); + + for (;Ok; Ok = InfFindNextLine (&Context, &Context)) + { + /* get root */ + if (!InfGetStringField (&Context, 1, Buffer, MAX_INF_STRING_LENGTH, NULL)) + continue; + if (!GetRootKey (Buffer)) + continue; + + /* get key */ + Length = strlen (Buffer); + if (!InfGetStringField (&Context, 2, Buffer + Length, MAX_INF_STRING_LENGTH - Length, NULL)) + *Buffer = 0; + + DPRINT("KeyName: <%s>\n", Buffer); + + /* get flags */ + if (!InfGetIntField (&Context, 4, (PLONG)&Flags)) + Flags = 0; + + DPRINT("Flags: %lx\n", Flags); + + if (Delete || (Flags & FLG_ADDREG_OVERWRITEONLY)) + { + if (RegOpenKey (NULL, Buffer, &KeyHandle) != ERROR_SUCCESS) + { + DPRINT("RegOpenKey(%s) failed\n", Buffer); + continue; /* ignore if it doesn't exist */ + } + } + else + { + if (RegCreateKey (NULL, Buffer, &KeyHandle) != ERROR_SUCCESS) + { + DPRINT("RegCreateKey(%s) failed\n", Buffer); + continue; + } + } + + /* get value name */ + if (InfGetStringField (&Context, 3, Buffer, MAX_INF_STRING_LENGTH, NULL)) + { + ValuePtr = Buffer; + } + else + { + ValuePtr = NULL; + } + + /* and now do it */ + if (!do_reg_operation (KeyHandle, ValuePtr, &Context, Flags)) + { + return FALSE; + } + } + + return TRUE; +} + + +BOOL +ImportRegistryFile(PCHAR FileName, + PCHAR Section, + BOOL Delete) +{ + HINF hInf; + ULONG ErrorLine; + + /* Load inf file from install media. */ + if (!InfOpenFile(&hInf, FileName, &ErrorLine)) + { + DPRINT1 ("InfOpenFile() failed\n"); + return FALSE; + } + + if (!registry_callback (hInf, "AddReg", FALSE)) + { + DPRINT1 ("registry_callback() failed\n"); + } + + InfCloseFile (hInf); + + return TRUE; +} + +/* EOF */ diff --git a/reactos/tools/mkhive/reginf.h b/reactos/tools/mkhive/reginf.h new file mode 100644 index 00000000000..af5fd913cac --- /dev/null +++ b/reactos/tools/mkhive/reginf.h @@ -0,0 +1,37 @@ +/* + * ReactOS kernel + * Copyright (C) 2003 ReactOS Team + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: reginf.h,v 1.1 2003/04/14 17:18:48 ekohl Exp $ + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS hive maker + * FILE: tools/mkhive/reginf.h + * PURPOSE: Inf file import code + * PROGRAMMER: Eric Kohl + */ + +#ifndef __REGINF_H__ +#define __REGINF_H__ + +BOOL +ImportRegistryFile(PCHAR Filename, + PCHAR Section, + BOOL Delete); + +#endif /* __REGINF_H__ */ + +/* EOF */ diff --git a/reactos/tools/mkhive/registry.c b/reactos/tools/mkhive/registry.c new file mode 100644 index 00000000000..7e0b0c0bd78 --- /dev/null +++ b/reactos/tools/mkhive/registry.c @@ -0,0 +1,653 @@ +/* + * ReactOS kernel + * Copyright (C) 2003 ReactOS Team + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: registry.c,v 1.1 2003/04/14 17:18:48 ekohl Exp $ + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS hive maker + * FILE: tools/mkhive/registry.c + * PURPOSE: Registry code + * PROGRAMMER: Eric Kohl + */ + +/* + * TODO: + * - Implement RegDeleteKey(). + * - Implement RegQueryMultipleValue(). + * - Fix RegEnumValue(). + */ + +#include +#include + +#include "mkhive.h" +#include "registry.h" + + +static HKEY RootKey; + + +VOID +RegInitializeRegistry(VOID) +{ + /* Create root key */ + RootKey = (HKEY)malloc(sizeof(KEY)); + + InitializeListHead(&RootKey->SubKeyList); + InitializeListHead(&RootKey->ValueList); + InitializeListHead(&RootKey->KeyList); + + RootKey->NameSize = 2; + RootKey->Name = (PUCHAR)malloc(2); + strcpy(RootKey->Name, "\\"); + + RootKey->DataType = 0; + RootKey->DataSize = 0; + RootKey->Data = NULL; + + /* Create SYSTEM key */ + RegCreateKey(RootKey, + "Registry\\Machine\\SYSTEM", + NULL); + + /* Create HARDWARE key */ + RegCreateKey(RootKey, + "Registry\\Machine\\HARDWARE", + NULL); +} + + +LONG +RegCreateKey(HKEY ParentKey, + PCHAR KeyName, + PHKEY Key) +{ + PLIST_ENTRY Ptr; + HKEY SearchKey = INVALID_HANDLE_VALUE; + HKEY CurrentKey; + HKEY NewKey; + PCHAR p; + PCHAR name; + int subkeyLength; + int stringLength; + + DPRINT ("KeyName '%s'\n", KeyName); + + if (*KeyName == '\\') + { + KeyName++; + CurrentKey = RootKey; + } + else if (ParentKey == NULL) + { + CurrentKey = RootKey; + } + else + { + CurrentKey = ParentKey; + } + + /* Check whether current key is a link */ + if (CurrentKey->DataType == REG_LINK) + { + CurrentKey = (HKEY)CurrentKey->Data; + } + + while (*KeyName != 0) + { + DPRINT ("KeyName '%s'\n", KeyName); + + if (*KeyName == '\\') + KeyName++; + p = strchr (KeyName, '\\'); + if ((p != NULL) && (p != KeyName)) + { + subkeyLength = p - KeyName; + stringLength = subkeyLength + 1; + name = KeyName; + } + else + { + subkeyLength = strlen (KeyName); + stringLength = subkeyLength; + name = KeyName; + } + + Ptr = CurrentKey->SubKeyList.Flink; + while (Ptr != &CurrentKey->SubKeyList) + { + DPRINT ("Ptr 0x%x\n", Ptr); + + SearchKey = CONTAINING_RECORD(Ptr, + KEY, + KeyList); + DPRINT ("SearchKey 0x%x\n", SearchKey); + DPRINT ("Searching '%s'\n", SearchKey->Name); + if (strncmp (SearchKey->Name, name, subkeyLength) == 0) + break; + + Ptr = Ptr->Flink; + } + + if (Ptr == &CurrentKey->SubKeyList) + { + /* no key found -> create new subkey */ + NewKey = (HKEY)malloc (sizeof(KEY)); + if (NewKey == NULL) + return ERROR_OUTOFMEMORY; + + InitializeListHead (&NewKey->SubKeyList); + InitializeListHead (&NewKey->ValueList); + + NewKey->DataType = 0; + NewKey->DataSize = 0; + NewKey->Data = NULL; + + InsertTailList (&CurrentKey->SubKeyList, &NewKey->KeyList); + NewKey->NameSize = subkeyLength + 1; + NewKey->Name = (PCHAR)malloc (NewKey->NameSize); + if (NewKey->Name == NULL) + return(ERROR_OUTOFMEMORY); + memcpy(NewKey->Name, name, subkeyLength); + NewKey->Name[subkeyLength] = 0; + + DPRINT ("NewKey 0x%x\n", NewKey); + DPRINT ("NewKey '%s' Length %d\n", NewKey->Name, NewKey->NameSize); + + CurrentKey = NewKey; + } + else + { + CurrentKey = SearchKey; + + /* Check whether current key is a link */ + if (CurrentKey->DataType == REG_LINK) + { + CurrentKey = (HKEY)CurrentKey->Data; + } + } + + KeyName = KeyName + stringLength; + } + + if (Key != NULL) + *Key = CurrentKey; + + return ERROR_SUCCESS; +} + + +LONG +RegDeleteKey(HKEY Key, + PCHAR Name) +{ + + + if (strchr(Name, '\\') != NULL) + return(ERROR_INVALID_PARAMETER); + + + + return(ERROR_SUCCESS); +} + + +LONG +RegEnumKey(HKEY Key, + ULONG Index, + PCHAR Name, + PULONG NameSize) +{ + PLIST_ENTRY Ptr; + HKEY SearchKey; + ULONG Count = 0; + ULONG Size; + + Ptr = Key->SubKeyList.Flink; + while (Ptr != &Key->SubKeyList) + { + if (Index == Count) + break; + + Count++; + Ptr = Ptr->Flink; + } + + if (Ptr == &Key->SubKeyList) + return(ERROR_NO_MORE_ITEMS); + + SearchKey = CONTAINING_RECORD(Ptr, + KEY, + KeyList); + + DPRINT ("Name '%s' Length %d\n", SearchKey->Name, SearchKey->NameSize); + + Size = min(SearchKey->NameSize, *NameSize); + *NameSize = Size; + memcpy(Name, SearchKey->Name, Size); + + return(ERROR_SUCCESS); +} + + +LONG +RegOpenKey(HKEY ParentKey, + PCHAR KeyName, + PHKEY Key) +{ + PLIST_ENTRY Ptr; + HKEY SearchKey = INVALID_HANDLE_VALUE; + HKEY CurrentKey; + PCHAR p; + PCHAR name; + int subkeyLength; + int stringLength; + + DPRINT("KeyName '%s'\n", KeyName); + + *Key = NULL; + + if (*KeyName == '\\') + { + KeyName++; + CurrentKey = RootKey; + } + else if (ParentKey == NULL) + { + CurrentKey = RootKey; + } + else + { + CurrentKey = ParentKey; + } + + /* Check whether current key is a link */ + if (CurrentKey->DataType == REG_LINK) + { + CurrentKey = (HKEY)CurrentKey->Data; + } + + while (*KeyName != 0) + { + DPRINT ("KeyName '%s'\n", KeyName); + + if (*KeyName == '\\') + KeyName++; + p = strchr(KeyName, '\\'); + if ((p != NULL) && (p != KeyName)) + { + subkeyLength = p - KeyName; + stringLength = subkeyLength + 1; + name = KeyName; + } + else + { + subkeyLength = strlen(KeyName); + stringLength = subkeyLength; + name = KeyName; + } + + Ptr = CurrentKey->SubKeyList.Flink; + while (Ptr != &CurrentKey->SubKeyList) + { + DPRINT ("Ptr 0x%x\n", Ptr); + + SearchKey = CONTAINING_RECORD(Ptr, + KEY, + KeyList); + + DPRINT ("SearchKey 0x%x\n", SearchKey); + DPRINT ("Searching '%s'\n", SearchKey->Name); + + if (strncmp(SearchKey->Name, name, subkeyLength) == 0) + break; + + Ptr = Ptr->Flink; + } + + if (Ptr == &CurrentKey->SubKeyList) + { + return(ERROR_PATH_NOT_FOUND); + } + else + { + CurrentKey = SearchKey; + + /* Check whether current key is a link */ + if (CurrentKey->DataType == REG_LINK) + { + CurrentKey = (HKEY)CurrentKey->Data; + } + } + + KeyName = KeyName + stringLength; + } + + if (Key != NULL) + *Key = CurrentKey; + + return(ERROR_SUCCESS); +} + + +LONG +RegSetValue(HKEY Key, + PCHAR ValueName, + ULONG Type, + PUCHAR Data, + ULONG DataSize) +{ + PLIST_ENTRY Ptr; + PVALUE Value = NULL; + + DPRINT ("Key 0x%x, ValueName '%s', Type %d, Data 0x%x, DataSize %d\n", + (int)Key, ValueName, (int)Type, (int)Data, (int)DataSize); + + if ((ValueName == NULL) || (*ValueName == 0)) + { + /* set default value */ + if ((Key->Data != NULL) && (Key->DataSize > sizeof(PUCHAR))) + { + free(Key->Data); + } + + if (DataSize <= sizeof(PUCHAR)) + { + Key->DataSize = DataSize; + Key->DataType = Type; + memcpy(&Key->Data, Data, DataSize); + } + else + { + Key->Data = (PUCHAR)malloc(DataSize); + Key->DataSize = DataSize; + Key->DataType = Type; + memcpy(Key->Data, Data, DataSize); + } + } + else + { + /* set non-default value */ + Ptr = Key->ValueList.Flink; + while (Ptr != &Key->ValueList) + { + Value = CONTAINING_RECORD(Ptr, + VALUE, + ValueList); + + DPRINT ("Value->Name '%s'\n", Value->Name); + + if (stricmp(Value->Name, ValueName) == 0) + break; + + Ptr = Ptr->Flink; + } + + if (Ptr == &Key->ValueList) + { + /* add new value */ + DPRINT("No value found - adding new value\n"); + + Value = (PVALUE)malloc(sizeof(VALUE)); + if (Value == NULL) + return(ERROR_OUTOFMEMORY); + InsertTailList(&Key->ValueList, &Value->ValueList); + Value->NameSize = strlen(ValueName)+1; + Value->Name = (PCHAR)malloc(Value->NameSize); + if (Value->Name == NULL) + return(ERROR_OUTOFMEMORY); + strcpy(Value->Name, ValueName); + Value->DataType = REG_NONE; + Value->DataSize = 0; + Value->Data = NULL; + } + + /* set new value */ + if ((Value->Data != NULL) && (Value->DataSize > sizeof(PUCHAR))) + { + free(Value->Data); + } + + if (DataSize <= sizeof(PUCHAR)) + { + Value->DataSize = DataSize; + Value->DataType = Type; + memcpy(&Value->Data, Data, DataSize); + } + else + { + Value->Data = (PUCHAR)malloc(DataSize); + if (Value->Data == NULL) + return(ERROR_OUTOFMEMORY); + Value->DataType = Type; + Value->DataSize = DataSize; + memcpy(Value->Data, Data, DataSize); + } + } + return(ERROR_SUCCESS); +} + + +LONG +RegQueryValue(HKEY Key, + PCHAR ValueName, + PULONG Type, + PUCHAR Data, + PULONG DataSize) +{ + ULONG Size; + PLIST_ENTRY Ptr; + PVALUE Value = NULL; + + if ((ValueName == NULL) || (*ValueName == 0)) + { + /* query default value */ + if (Key->Data == NULL) + return(ERROR_INVALID_PARAMETER); + + if (Type != NULL) + *Type = Key->DataType; + if ((Data != NULL) && (DataSize != NULL)) + { + if (Key->DataSize <= sizeof(PUCHAR)) + { + Size = min(Key->DataSize, *DataSize); + memcpy(Data, &Key->Data, Size); + *DataSize = Size; + } + else + { + Size = min(Key->DataSize, *DataSize); + memcpy(Data, Key->Data, Size); + *DataSize = Size; + } + } + else if ((Data == NULL) && (DataSize != NULL)) + { + *DataSize = Key->DataSize; + } + } + else + { + /* query non-default value */ + Ptr = Key->ValueList.Flink; + while (Ptr != &Key->ValueList) + { + Value = CONTAINING_RECORD(Ptr, + VALUE, + ValueList); + + DPRINT("Searching for '%s'. Value name '%s'\n", ValueName, Value->Name); + + if (stricmp(Value->Name, ValueName) == 0) + break; + + Ptr = Ptr->Flink; + } + + if (Ptr == &Key->ValueList) + return(ERROR_INVALID_PARAMETER); + + if (Type != NULL) + *Type = Value->DataType; + if ((Data != NULL) && (DataSize != NULL)) + { + if (Value->DataSize <= sizeof(PUCHAR)) + { + Size = min(Value->DataSize, *DataSize); + memcpy(Data, &Value->Data, Size); + *DataSize = Size; + } + else + { + Size = min(Value->DataSize, *DataSize); + memcpy(Data, Value->Data, Size); + *DataSize = Size; + } + } + else if ((Data == NULL) && (DataSize != NULL)) + { + *DataSize = Value->DataSize; + } + } + + return(ERROR_SUCCESS); +} + + +LONG +RegDeleteValue(HKEY Key, + PCHAR ValueName) +{ + PLIST_ENTRY Ptr; + PVALUE Value = NULL; + + if ((ValueName == NULL) || (*ValueName == 0)) + { + /* delete default value */ + if (Key->Data != NULL) + free(Key->Data); + Key->Data = NULL; + Key->DataSize = 0; + Key->DataType = 0; + } + else + { + /* delete non-default value */ + Ptr = Key->ValueList.Flink; + while (Ptr != &Key->ValueList) + { + Value = CONTAINING_RECORD(Ptr, + VALUE, + ValueList); + if (strcmp(Value->Name, ValueName) == 0) + break; + + Ptr = Ptr->Flink; + } + + if (Ptr == &Key->ValueList) + return(ERROR_INVALID_PARAMETER); + + /* delete value */ + if (Value->Name != NULL) + free(Value->Name); + Value->Name = NULL; + Value->NameSize = 0; + + if (Value->DataSize > sizeof(PUCHAR)) + { + if (Value->Data != NULL) + free(Value->Data); + } + Value->Data = NULL; + Value->DataSize = 0; + Value->DataType = 0; + + RemoveEntryList(&Value->ValueList); + free(Value); + } + return(ERROR_SUCCESS); +} + + +LONG +RegEnumValue(HKEY Key, + ULONG Index, + PCHAR ValueName, + PULONG NameSize, + PULONG Type, + PUCHAR Data, + PULONG DataSize) +{ + PLIST_ENTRY Ptr; + PVALUE Value; + ULONG Count = 0; + + if (Key->Data != NULL) + { + if (Index > 0) + { + Index--; + } + else + { + /* enumerate default value */ + if (ValueName != NULL) + *ValueName = 0; + if (Type != NULL) + *Type = Key->DataType; + if (DataSize != NULL) + *DataSize = Key->DataSize; + + /* FIXME: return more values */ + } + } + + Ptr = Key->ValueList.Flink; + while (Ptr != &Key->ValueList) + { + if (Index == Count) + break; + + Count++; + Ptr = Ptr->Flink; + } + + if (Ptr == &Key->ValueList) + return(ERROR_NO_MORE_ITEMS); + + Value = CONTAINING_RECORD(Ptr, + VALUE, + ValueList); + + /* FIXME: return values */ + + return(ERROR_SUCCESS); +} + + +#if 0 +LONG +RegQueryMultipleValue(HKEY Key, + ...) +{ + return(ERROR_SUCCESS); +} +#endif + +/* EOF */ diff --git a/reactos/tools/mkhive/registry.h b/reactos/tools/mkhive/registry.h new file mode 100644 index 00000000000..a9bb354e423 --- /dev/null +++ b/reactos/tools/mkhive/registry.h @@ -0,0 +1,297 @@ +/* + * ReactOS kernel + * Copyright (C) 2003 ReactOS Team + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: registry.h,v 1.1 2003/04/14 17:18:48 ekohl Exp $ + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS hive maker + * FILE: tools/mkhive/registry.h + * PURPOSE: Registry code + * PROGRAMMER: Eric Kohl + */ + +#ifndef __REGISTRY_H__ +#define __REGISTRY_H__ + + +#define INVALID_HANDLE_VALUE NULL + +typedef struct _LIST_ENTRY +{ + struct _LIST_ENTRY *Flink; + struct _LIST_ENTRY *Blink; +} LIST_ENTRY, *PLIST_ENTRY; + + +typedef struct _REG_KEY +{ + LIST_ENTRY KeyList; + LIST_ENTRY SubKeyList; + LIST_ENTRY ValueList; + + ULONG NameSize; + PUCHAR Name; + + /* default data */ + ULONG DataType; + ULONG DataSize; + PUCHAR Data; +} KEY, *HKEY, **PHKEY; + + +typedef struct _REG_VALUE +{ + LIST_ENTRY ValueList; + + /* value name */ + ULONG NameSize; + PUCHAR Name; + + /* value data */ + ULONG DataType; + ULONG DataSize; + PUCHAR Data; +} VALUE, *PVALUE; + + +#define ERROR_SUCCESS 0L +#define ERROR_PATH_NOT_FOUND 2L +#define ERROR_OUTOFMEMORY 14L +#define ERROR_INVALID_PARAMETER 87L +#define ERROR_MORE_DATA 234L +#define ERROR_NO_MORE_ITEMS 259L + + +#define assert(x) + +/* + * VOID + * InitializeListHead ( + * PLIST_ENTRY ListHead + * ); + * + * FUNCTION: Initializes a double linked list + * ARGUMENTS: + * ListHead = Caller supplied storage for the head of the list + */ +#define InitializeListHead(ListHead) \ +{ \ + (ListHead)->Flink = (ListHead); \ + (ListHead)->Blink = (ListHead); \ +} + + +/* + * VOID + * InsertHeadList ( + * PLIST_ENTRY ListHead, + * PLIST_ENTRY Entry + * ); + * + * FUNCTION: Inserts an entry in a double linked list + * ARGUMENTS: + * ListHead = Head of the list + * Entry = Entry to insert + */ +#define InsertHeadList(ListHead, ListEntry) \ +{ \ + PLIST_ENTRY OldFlink; \ + OldFlink = (ListHead)->Flink; \ + (ListEntry)->Flink = OldFlink; \ + (ListEntry)->Blink = (ListHead); \ + OldFlink->Blink = (ListEntry); \ + (ListHead)->Flink = (ListEntry); \ + assert((ListEntry) != NULL); \ + assert((ListEntry)->Blink!=NULL); \ + assert((ListEntry)->Blink->Flink == (ListEntry)); \ + assert((ListEntry)->Flink != NULL); \ + assert((ListEntry)->Flink->Blink == (ListEntry)); \ +} + + +/* + * VOID + * InsertTailList ( + * PLIST_ENTRY ListHead, + * PLIST_ENTRY Entry + * ); + * + * FUNCTION: + * Inserts an entry in a double linked list + * + * ARGUMENTS: + * ListHead = Head of the list + * Entry = Entry to insert + */ +#define InsertTailList(ListHead, ListEntry) \ +{ \ + PLIST_ENTRY OldBlink; \ + OldBlink = (ListHead)->Blink; \ + (ListEntry)->Flink = (ListHead); \ + (ListEntry)->Blink = OldBlink; \ + OldBlink->Flink = (ListEntry); \ + (ListHead)->Blink = (ListEntry); \ + assert((ListEntry) != NULL); \ + assert((ListEntry)->Blink != NULL); \ + assert((ListEntry)->Blink->Flink == (ListEntry)); \ + assert((ListEntry)->Flink != NULL); \ + assert((ListEntry)->Flink->Blink == (ListEntry)); \ +} + +/* + * BOOLEAN + * IsListEmpty ( + * PLIST_ENTRY ListHead + * ); + * + * FUNCTION: + * Checks if a double linked list is empty + * + * ARGUMENTS: + * ListHead = Head of the list +*/ +#define IsListEmpty(ListHead) \ + ((ListHead)->Flink == (ListHead)) + + +/* + *VOID + *RemoveEntryList ( + * PLIST_ENTRY Entry + * ); + * + * FUNCTION: + * Removes an entry from a double linked list + * + * ARGUMENTS: + * ListEntry = Entry to remove + */ +#define RemoveEntryList(ListEntry) \ +{ \ + PLIST_ENTRY OldFlink; \ + PLIST_ENTRY OldBlink; \ + assert((ListEntry) != NULL); \ + assert((ListEntry)->Blink!=NULL); \ + assert((ListEntry)->Blink->Flink == (ListEntry)); \ + assert((ListEntry)->Flink != NULL); \ + assert((ListEntry)->Flink->Blink == (ListEntry)); \ + OldFlink = (ListEntry)->Flink; \ + OldBlink = (ListEntry)->Blink; \ + OldFlink->Blink = OldBlink; \ + OldBlink->Flink = OldFlink; \ + (ListEntry)->Flink = NULL; \ + (ListEntry)->Blink = NULL; \ +} + +/* + * PURPOSE: Returns the byte offset of a field within a structure + */ +#define FIELD_OFFSET(Type,Field) (LONG)(&(((Type *)(0))->Field)) + +/* + * PURPOSE: Returns the base address structure if the caller knows the + * address of a field within the structure + * ARGUMENTS: + * Address = address of the field + * Type = Type of the whole structure + * Field = Name of the field whose address is none + */ +#define CONTAINING_RECORD(Address,Type,Field) \ + (Type *)(((LONG)Address) - FIELD_OFFSET(Type,Field)) + + +#define REG_NONE 0 +#define REG_SZ 1 +#define REG_EXPAND_SZ 2 +#define REG_BINARY 3 +#define REG_DWORD 4 +#define REG_DWORD_BIG_ENDIAN 5 +#define REG_DWORD_LITTLE_ENDIAN 4 +#define REG_LINK 6 +#define REG_MULTI_SZ 7 +#define REG_RESOURCE_LIST 8 +#define REG_FULL_RESOURCE_DESCRIPTOR 9 +#define REG_RESOURCE_REQUIREMENTS_LIST 10 + + + +VOID +RegInitializeRegistry(VOID); + +LONG +RegCreateKey(HKEY ParentKey, + PCHAR KeyName, + PHKEY Key); + +LONG +RegDeleteKey(HKEY Key, + PCHAR Name); + +LONG +RegEnumKey(HKEY Key, + ULONG Index, + PCHAR Name, + PULONG NameSize); + +LONG +RegOpenKey(HKEY ParentKey, + PCHAR KeyName, + PHKEY Key); + + +LONG +RegSetValue(HKEY Key, + PCHAR ValueName, + ULONG Type, + PUCHAR Data, + ULONG DataSize); + +LONG +RegQueryValue(HKEY Key, + PCHAR ValueName, + PULONG Type, + PUCHAR Data, + PULONG DataSize); + +LONG +RegDeleteValue(HKEY Key, + PCHAR ValueName); + +LONG +RegEnumValue(HKEY Key, + ULONG Index, + PCHAR ValueName, + PULONG NameSize, + PULONG Type, + PUCHAR Data, + PULONG DataSize); + + +#if 0 +BOOL +RegImportTextHive(PCHAR ChunkBase, + U32 ChunkSize); + +BOOL +RegImportBinaryHive(PCHAR ChunkBase, + U32 ChunkSize); +#endif + +#endif /* __REGISTRY_H__ */ + +/* EOF */ +