diff --git a/reactos/lib/lib.rbuild b/reactos/lib/lib.rbuild index 42e49d6ab2f..fe9cf995715 100644 --- a/reactos/lib/lib.rbuild +++ b/reactos/lib/lib.rbuild @@ -37,6 +37,9 @@ + + + diff --git a/reactos/lib/newinflib/README.txt b/reactos/lib/newinflib/README.txt new file mode 100644 index 00000000000..5e27e2b0d5e --- /dev/null +++ b/reactos/lib/newinflib/README.txt @@ -0,0 +1,16 @@ +Routines to handle .inf files. + +This is the UNICODE-enabled version of inflib. It will be used by usetup and mkhive. + +This library is used to share .inf handling code between build tools and +ReactOS code. Two versions are built, "inflib_host" (for use by build tools) +and "inflib" (for use by ReactOS code). Both depend on the same core source, +with a wrapper for the appropriate interface. +Most of the differences between the host and the ReactOS environment are +abstracted away in builddep.h. Of particular note is that the host version +uses Ansi characters while the ReactOS version uses Unicode. So, the core +source uses TCHARs. builddep.h depends on a preprocessor variable INFLIB_HOST +which is defined when building the host version (inflib.mak) but not defined +when building the ReactOS version (inflib.xml). +The wrappers have "host" or "ros" in their filename. The library interface is +"infhost.h" for the host version, "infros.h" for the ReactOS version. diff --git a/reactos/lib/newinflib/builddep.h b/reactos/lib/newinflib/builddep.h new file mode 100644 index 00000000000..c768a2ca88b --- /dev/null +++ b/reactos/lib/newinflib/builddep.h @@ -0,0 +1,98 @@ +/* + * PROJECT: .inf file parser + * LICENSE: GPL - See COPYING in the top level directory + * COPYRIGHT: Copyright 2005 Ge van Geldorp + */ + +#ifdef INFLIB_HOST + +/* Definitions native to the host on which we're building */ + +#include + +#include +#include +#include +#include + +#define FREE(Area) free(Area) +#define MALLOC(Size) malloc((size_t)(Size)) +#define ZEROMEMORY(Area, Size) memset((Area), '\0', (size_t)(Size)) +#define MEMCPY(Dest, Src, Size) memcpy((Dest), (Src), (size_t)(Size)) + +#define STATUS_SUCCESS 0 +#define INF_STATUS_SUCCESS 0 +#define INF_STATUS_NO_MEMORY ENOMEM +#define INF_STATUS_INVALID_PARAMETER EINVAL +#define INF_STATUS_NOT_FOUND ENOENT +#define INF_STATUS_BUFFER_OVERFLOW E2BIG +#define INF_SUCCESS(x) (0 == (x)) + +typedef char TCHAR, *PTCHAR, *PTSTR; +typedef const TCHAR *PCTSTR; +typedef WORD LCID; + +#define _T(x) x +#define _tcsicmp strcasecmp +#define _tcslen strlen +#define _tcscpy strcpy +#define _tcstoul strtoul +#define _tcstol strtol +#define STRFMT "%s" + +#ifdef _MSC_VER +#define strcasecmp _stricmp +#endif + +#define IS_TEXT_UNICODE_ASCII16 1 +#define IS_TEXT_UNICODE_REVERSE_ASCII16 16 +#define IS_TEXT_UNICODE_STATISTICS 2 +#define IS_TEXT_UNICODE_REVERSE_STATISTICS 32 +#define IS_TEXT_UNICODE_CONTROLS 4 +#define IS_TEXT_UNICODE_REVERSE_CONTROLS 64 +#define IS_TEXT_UNICODE_SIGNATURE 8 +#define IS_TEXT_UNICODE_REVERSE_SIGNATURE 128 +#define IS_TEXT_UNICODE_ILLEGAL_CHARS 256 +#define IS_TEXT_UNICODE_ODD_LENGTH 512 +#define IS_TEXT_UNICODE_NULL_BYTES 4096 +#define IS_TEXT_UNICODE_UNICODE_MASK 15 +#define IS_TEXT_UNICODE_REVERSE_MASK 240 +#define IS_TEXT_UNICODE_NOT_UNICODE_MASK 3840 +#define IS_TEXT_UNICODE_NOT_ASCII_MASK 61440 + +#define SUBLANG_NEUTRAL 0 +#define PRIMARYLANGID(lgid) ((WORD)(lgid) & 0x3ff) +#define MAKELANGID(p, s) ((((WORD)(s)) << 10) | (WORD)(p)) + + +#else /* ! defined(INFLIB_HOST) */ + +/* ReactOS definitions */ + +#define UNICODE +#define _UNICODE +#define WIN32_NO_STATUS +#include +#define NTOS_MODE_USER +#include +#include + +extern PVOID InfpHeap; + +#define FREE(Area) RtlFreeHeap(InfpHeap, 0, (Area)) +#define MALLOC(Size) RtlAllocateHeap(InfpHeap, 0, (Size)) +#define ZEROMEMORY(Area, Size) RtlZeroMemory((Area), (Size)) +#define MEMCPY(Dest, Src, Size) RtlCopyMemory((Dest), (Src), (Size)) + +#define INF_STATUS_SUCCESS STATUS_SUCCESS +#define INF_STATUS_NO_MEMORY STATUS_NO_MEMORY +#define INF_STATUS_INVALID_PARAMETER STATUS_INVALID_PARAMETER +#define INF_STATUS_NOT_FOUND STATUS_NOT_FOUND +#define INF_STATUS_BUFFER_OVERFLOW STATUS_BUFFER_OVERFLOW +#define INF_SUCCESS(x) (0 <= (x)) + +#define STRFMT "%S" + +#endif /* INFLIB_HOST */ + +/* EOF */ diff --git a/reactos/lib/newinflib/infcommon.h b/reactos/lib/newinflib/infcommon.h new file mode 100644 index 00000000000..a80f2029078 --- /dev/null +++ b/reactos/lib/newinflib/infcommon.h @@ -0,0 +1,16 @@ +/* + * PROJECT: .inf file parser + * LICENSE: GPL - See COPYING in the top level directory + * PROGRAMMER: Royce Mitchell III + * Eric Kohl + * Ge van Geldorp + */ + +#pragma once + +#define MAX_INF_STRING_LENGTH 512 + +typedef void *HINF, **PHINF; +typedef struct _INFCONTEXT *PINFCONTEXT; + +/* EOF */ diff --git a/reactos/lib/newinflib/infcore.c b/reactos/lib/newinflib/infcore.c new file mode 100644 index 00000000000..3582ec56787 --- /dev/null +++ b/reactos/lib/newinflib/infcore.c @@ -0,0 +1,831 @@ +/* + * PROJECT: .inf file parser + * LICENSE: GPL - See COPYING in the top level directory + * PROGRAMMER: Royce Mitchell III + * Eric Kohl + * Ge van Geldorp + */ + +/* INCLUDES *****************************************************************/ + +#include "inflib.h" + +#define NDEBUG +#include + +#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) + + +/* 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 WCHAR *start; /* start position of item being parsed */ + const WCHAR *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 */ + INFSTATUS error; /* error code */ + unsigned int token_len; /* current token len */ + WCHAR token[MAX_FIELD_LEN+1]; /* current token */ +}; + +typedef const WCHAR * (*parser_state_func)( struct parser *parser, const WCHAR *pos ); + +/* parser state machine functions */ +static const WCHAR *line_start_state( struct parser *parser, const WCHAR *pos ); +static const WCHAR *section_name_state( struct parser *parser, const WCHAR *pos ); +static const WCHAR *key_name_state( struct parser *parser, const WCHAR *pos ); +static const WCHAR *value_name_state( struct parser *parser, const WCHAR *pos ); +static const WCHAR *eol_backslash_state( struct parser *parser, const WCHAR *pos ); +static const WCHAR *quotes_state( struct parser *parser, const WCHAR *pos ); +static const WCHAR *leading_spaces_state( struct parser *parser, const WCHAR *pos ); +static const WCHAR *trailing_spaces_state( struct parser *parser, const WCHAR *pos ); +static const WCHAR *comment_state( struct parser *parser, const WCHAR *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 +InfpFreeLine (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; +} + + +PINFCACHESECTION +InfpFreeSection (PINFCACHESECTION Section) +{ + PINFCACHESECTION Next; + + if (Section == NULL) + { + return NULL; + } + + /* Release all keys */ + Next = Section->Next; + while (Section->FirstLine != NULL) + { + Section->FirstLine = InfpFreeLine (Section->FirstLine); + } + Section->LastLine = NULL; + + FREE (Section); + + return Next; +} + + +PINFCACHESECTION +InfpFindSection(PINFCACHE Cache, + PCWSTR Name) +{ + PINFCACHESECTION Section = NULL; + + if (Cache == NULL || Name == NULL) + { + return NULL; + } + + /* iterate through list of sections */ + Section = Cache->FirstSection; + while (Section != NULL) + { + if (_wcsicmp (Section->Name, Name) == 0) + { + return Section; + } + + /* get the next section*/ + Section = Section->Next; + } + + return NULL; +} + + +PINFCACHESECTION +InfpAddSection(PINFCACHE Cache, + PCWSTR Name) +{ + PINFCACHESECTION Section = NULL; + ULONG Size; + + if (Cache == NULL || Name == NULL) + { + DPRINT("Invalid parameter\n"); + return NULL; + } + + /* Allocate and initialize the new section */ + Size = (ULONG)FIELD_OFFSET(INFCACHESECTION, + Name[wcslen (Name) + 1]); + Section = (PINFCACHESECTION)MALLOC(Size); + if (Section == NULL) + { + DPRINT("MALLOC() failed\n"); + return NULL; + } + ZEROMEMORY (Section, + Size); + + /* Copy section name */ + wcscpy (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; +} + + +PINFCACHELINE +InfpAddLine(PINFCACHESECTION Section) +{ + PINFCACHELINE Line; + + if (Section == NULL) + { + DPRINT("Invalid parameter\n"); + return NULL; + } + + Line = (PINFCACHELINE)MALLOC(sizeof(INFCACHELINE)); + if (Line == NULL) + { + DPRINT("MALLOC() failed\n"); + return NULL; + } + ZEROMEMORY(Line, + 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; +} + + +PVOID +InfpAddKeyToLine(PINFCACHELINE Line, + PCWSTR Key) +{ + if (Line == NULL) + { + DPRINT1("Invalid Line\n"); + return NULL; + } + + if (Line->Key != NULL) + { + DPRINT1("Line already has a key\n"); + return NULL; + } + + Line->Key = (PWCHAR)MALLOC((wcslen(Key) + 1) * sizeof(WCHAR)); + if (Line->Key == NULL) + { + DPRINT1("MALLOC() failed\n"); + return NULL; + } + + wcscpy(Line->Key, Key); + + return (PVOID)Line->Key; +} + + +PVOID +InfpAddFieldToLine(PINFCACHELINE Line, + PCWSTR Data) +{ + PINFCACHEFIELD Field; + ULONG Size; + + Size = (ULONG)FIELD_OFFSET(INFCACHEFIELD, + Data[wcslen(Data) + 1]); + Field = (PINFCACHEFIELD)MALLOC(Size); + if (Field == NULL) + { + DPRINT1("MALLOC() failed\n"); + return NULL; + } + ZEROMEMORY (Field, + Size); + wcscpy (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; +} + + +PINFCACHELINE +InfpFindKeyLine(PINFCACHESECTION Section, + PCWSTR Key) +{ + PINFCACHELINE Line; + + Line = Section->FirstLine; + while (Line != NULL) + { + if (Line->Key != NULL && _wcsicmp (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 WCHAR *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 WCHAR *ptr ) +{ + return (ptr >= parser->end || + *ptr == CONTROL_Z || + *ptr == '\n' || + (*ptr == '\r' && *(ptr + 1) == '\n')); +} + + +/* push data from current token start up to pos into the current token */ +static int push_token( struct parser *parser, const WCHAR *pos ) +{ + UINT len = (UINT)(pos - parser->start); + const WCHAR *src = parser->start; + WCHAR *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++) + { + if (*src) + { + *dst = *src; + } + else + { + *dst = ' '; + } + } + + *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 = INF_STATUS_SECTION_NAME_TOO_LONG; + return NULL; + } + + Section = InfpFindSection(parser->file, + parser->token); + if (Section == NULL) + { + /* need to create a new one */ + Section= InfpAddSection(parser->file, + parser->token); + if (Section == NULL) + { + parser->error = INF_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; + + if (!parser->line) /* need to start a new line */ + { + if (parser->cur_section == NULL) /* got a line before the first section */ + { + parser->error = INF_STATUS_WRONG_INF_STYLE; + return NULL; + } + + parser->line = InfpAddLine(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 = INF_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 WCHAR *line_start_state( struct parser *parser, const WCHAR *pos ) +{ + const WCHAR *p; + + for (p = pos; !is_eof( parser, p ); p++) + { + switch(*p) + { + case '\r': + continue; + + case '\n': + 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 (!iswspace(*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 WCHAR *section_name_state( struct parser *parser, const WCHAR *pos ) +{ + const WCHAR *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 = INF_STATUS_BAD_SECTION_NAME_LINE; /* unfinished section name */ + return NULL; +} + + +/* handler for parser KEY_NAME state */ +static const WCHAR *key_name_state( struct parser *parser, const WCHAR *pos ) +{ + const WCHAR *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 (!iswspace(*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 WCHAR *value_name_state( struct parser *parser, const WCHAR *pos ) +{ + const WCHAR *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 WCHAR *eol_backslash_state( struct parser *parser, const WCHAR *pos ) +{ + const WCHAR *p; + + for (p = pos; !is_eof( parser, p ); p++) + { + switch(*p) + { + case '\r': + continue; + + case '\n': + parser->line_pos++; + parser->start = p + 1; + set_state( parser, LEADING_SPACES ); + return p + 1; + + case '\\': + continue; + + case ';': + push_state( parser, EOL_BACKSLASH ); + set_state( parser, COMMENT ); + return p + 1; + + default: + if (iswspace(*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 WCHAR *quotes_state( struct parser *parser, const WCHAR *pos ) +{ + const WCHAR *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 WCHAR *leading_spaces_state( struct parser *parser, const WCHAR *pos ) +{ + const WCHAR *p; + + for (p = pos; !is_eol( parser, p ); p++) + { + if (*p == '\\') + { + parser->start = p; + set_state( parser, EOL_BACKSLASH ); + return p; + } + if (!iswspace(*p)) + break; + } + parser->start = p; + pop_state( parser ); + return p; +} + + +/* handler for parser TRAILING_SPACES state */ +static const WCHAR *trailing_spaces_state( struct parser *parser, const WCHAR *pos ) +{ + const WCHAR *p; + + for (p = pos; !is_eol( parser, p ); p++) + { + if (*p == '\\') + { + set_state( parser, EOL_BACKSLASH ); + return p; + } + if (!iswspace(*p)) + break; + } + pop_state( parser ); + return p; +} + + +/* handler for parser COMMENT state */ +static const WCHAR *comment_state( struct parser *parser, const WCHAR *pos ) +{ + const WCHAR *p = pos; + + while (!is_eol( parser, p )) + p++; + pop_state( parser ); + return p; +} + + +/* parse a complete buffer */ +INFSTATUS +InfpParseBuffer (PINFCACHE file, + const WCHAR *buffer, + const WCHAR *end, + PULONG error_line) +{ + struct parser parser; + const WCHAR *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 = InfpFindSection(file, + L"Strings"); + + return INF_STATUS_SUCCESS; +} + +/* EOF */ diff --git a/reactos/lib/newinflib/infget.c b/reactos/lib/newinflib/infget.c new file mode 100644 index 00000000000..1cdbebf2ee5 --- /dev/null +++ b/reactos/lib/newinflib/infget.c @@ -0,0 +1,668 @@ +/* + * PROJECT: .inf file parser + * LICENSE: GPL - See COPYING in the top level directory + * PROGRAMMER: Royce Mitchell III + * Eric Kohl + * Ge van Geldorp + */ + +/* INCLUDES *****************************************************************/ + +#include "inflib.h" + +#define NDEBUG +#include + +static unsigned int +InfpSubstituteString(PINFCACHE Inf, + const WCHAR *text, + WCHAR *buffer, + unsigned int size); + +/* retrieve the string substitution for a given string, or NULL if not found */ +/* if found, len is set to the substitution length */ +static PCWSTR +InfpGetSubstitutionString(PINFCACHE Inf, + PCWSTR str, + unsigned int *len, + BOOL no_trailing_slash) +{ + static const WCHAR percent = '%'; + + INFSTATUS Status = INF_STATUS_NOT_FOUND; + PINFCONTEXT Context = NULL; + PWCHAR Data = NULL; + WCHAR ValueName[MAX_INF_STRING_LENGTH +1]; + WCHAR StringLangId[13]; + + if (!*len) /* empty string (%%) is replaced by single percent */ + { + *len = 1; + return &percent; + } + + wcsncpy(ValueName, str, *len); + ValueName[*len] = 0; + + DPRINT("Value name: %S\n", ValueName); + + if (Inf->LocaleId != 0) + { + swprintf(StringLangId, + L"Strings.%04hx", + Inf->LocaleId); + + Status = InfpFindFirstLine(Inf, + StringLangId, + ValueName, + &Context); + if (Status != INF_STATUS_SUCCESS) + { + swprintf(StringLangId, + L"Strings.%04hx", + MAKELANGID(PRIMARYLANGID(Inf->LocaleId), SUBLANG_NEUTRAL)); + + Status = InfpFindFirstLine(Inf, + StringLangId, + ValueName, + &Context); + if (Status != INF_STATUS_SUCCESS) + { + Status = InfpFindFirstLine(Inf, + L"Strings", + ValueName, + &Context); + } + } + } + else + { + Status = InfpFindFirstLine(Inf, + L"Strings", + ValueName, + &Context); + } + + if (Status != INF_STATUS_SUCCESS || Context == NULL) + return NULL; + + Status = InfpGetData(Context, + NULL, + &Data); + + InfpFreeContext(Context); + + if (Status == STATUS_SUCCESS) + { + *len = wcslen(Data); + DPRINT("Substitute: %S Length: %ul\n", Data, *len); + return Data; + } + + return NULL; +} + + +/* do string substitutions on the specified text */ +/* the buffer is assumed to be large enough */ +/* returns necessary length not including terminating null */ +static unsigned int +InfpSubstituteString(PINFCACHE Inf, + PCWSTR text, + PWSTR buffer, + unsigned int size) +{ + const WCHAR *start, *subst, *p; + unsigned int len, total = 0; + int inside = 0; + + if (!buffer) size = MAX_INF_STRING_LENGTH + 1; + for (p = start = text; *p; p++) + { + if (*p != '%') continue; + inside = !inside; + if (inside) /* start of a %xx% string */ + { + len = (unsigned int)(p - start); + if (len > size - 1) len = size - 1; + if (buffer) memcpy( buffer + total, start, len * sizeof(WCHAR) ); + total += len; + size -= len; + start = p; + } + else /* end of the %xx% string, find substitution */ + { + len = (unsigned int)(p - start - 1); + subst = InfpGetSubstitutionString( Inf, start + 1, &len, p[1] == '\\' ); + if (!subst) + { + subst = start; + len = (unsigned int)(p - start + 1); + } + if (len > size - 1) len = size - 1; + if (buffer) memcpy( buffer + total, subst, len * sizeof(WCHAR) ); + total += len; + size -= len; + start = p + 1; + } + } + + if (start != p) /* unfinished string, copy it */ + { + len = (unsigned int)(p - start); + if (len > size - 1) len = size - 1; + if (buffer) memcpy( buffer + total, start, len * sizeof(WCHAR) ); + total += len; + } + if (buffer && size) buffer[total] = 0; + return total; +} + + +INFSTATUS +InfpFindFirstLine(PINFCACHE Cache, + PCWSTR Section, + PCWSTR Key, + PINFCONTEXT *Context) +{ + PINFCACHESECTION CacheSection; + PINFCACHELINE CacheLine; + + if (Cache == NULL || Section == NULL || Context == NULL) + { + DPRINT1("Invalid parameter\n"); + return INF_STATUS_INVALID_PARAMETER; + } + + CacheSection = InfpFindSection(Cache, Section); + if (NULL == CacheSection) + { + DPRINT("Section not found\n"); + return INF_STATUS_NOT_FOUND; + } + + if (Key != NULL) + { + CacheLine = InfpFindKeyLine(CacheSection, Key); + } + else + { + CacheLine = CacheSection->FirstLine; + } + + if (NULL == CacheLine) + { + DPRINT("Key not found\n"); + return INF_STATUS_NOT_FOUND; + } + + *Context = MALLOC(sizeof(INFCONTEXT)); + if (NULL == *Context) + { + DPRINT1("MALLOC() failed\n"); + return INF_STATUS_NO_MEMORY; + } + (*Context)->Inf = (PVOID)Cache; + (*Context)->Section = (PVOID)CacheSection; + (*Context)->Line = (PVOID)CacheLine; + + return INF_STATUS_SUCCESS; +} + + +INFSTATUS +InfpFindNextLine(PINFCONTEXT ContextIn, + PINFCONTEXT ContextOut) +{ + PINFCACHELINE CacheLine; + + if (ContextIn == NULL || ContextOut == NULL) + return INF_STATUS_INVALID_PARAMETER; + + if (ContextIn->Line == NULL) + return INF_STATUS_INVALID_PARAMETER; + + CacheLine = (PINFCACHELINE)ContextIn->Line; + if (CacheLine->Next == NULL) + return INF_STATUS_NOT_FOUND; + + if (ContextIn != ContextOut) + { + ContextOut->Inf = ContextIn->Inf; + ContextOut->Section = ContextIn->Section; + } + ContextOut->Line = (PVOID)(CacheLine->Next); + + return INF_STATUS_SUCCESS; +} + + +INFSTATUS +InfpFindFirstMatchLine(PINFCONTEXT ContextIn, + PCWSTR Key, + PINFCONTEXT ContextOut) +{ + PINFCACHELINE CacheLine; + + if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0) + return INF_STATUS_INVALID_PARAMETER; + + if (ContextIn->Inf == NULL || ContextIn->Section == NULL) + return INF_STATUS_INVALID_PARAMETER; + + CacheLine = ((PINFCACHESECTION)(ContextIn->Section))->FirstLine; + while (CacheLine != NULL) + { + if (CacheLine->Key != NULL && _wcsicmp (CacheLine->Key, Key) == 0) + { + + if (ContextIn != ContextOut) + { + ContextOut->Inf = ContextIn->Inf; + ContextOut->Section = ContextIn->Section; + } + ContextOut->Line = (PVOID)CacheLine; + + return INF_STATUS_SUCCESS; + } + + CacheLine = CacheLine->Next; + } + + return INF_STATUS_NOT_FOUND; +} + + +INFSTATUS +InfpFindNextMatchLine(PINFCONTEXT ContextIn, + PCWSTR Key, + PINFCONTEXT ContextOut) +{ + PINFCACHELINE CacheLine; + + if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0) + return INF_STATUS_INVALID_PARAMETER; + + if (ContextIn->Inf == NULL || ContextIn->Section == NULL || ContextIn->Line == NULL) + return INF_STATUS_INVALID_PARAMETER; + + CacheLine = (PINFCACHELINE)ContextIn->Line; + while (CacheLine != NULL) + { + if (CacheLine->Key != NULL && _wcsicmp (CacheLine->Key, Key) == 0) + { + + if (ContextIn != ContextOut) + { + ContextOut->Inf = ContextIn->Inf; + ContextOut->Section = ContextIn->Section; + } + ContextOut->Line = (PVOID)CacheLine; + + return INF_STATUS_SUCCESS; + } + + CacheLine = CacheLine->Next; + } + + return INF_STATUS_NOT_FOUND; +} + + +LONG +InfpGetLineCount(HINF InfHandle, + PCWSTR 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 (CacheSection != NULL) + { + /* Are the section names the same? */ + if (_wcsicmp(CacheSection->Name, Section) == 0) + { + return CacheSection->LineCount; + } + + /* Get the next section */ + CacheSection = CacheSection->Next; + } + + DPRINT("Section not found\n"); + + return -1; +} + + +/* InfpGetLineText */ + + +LONG +InfpGetFieldCount(PINFCONTEXT Context) +{ + if (Context == NULL || Context->Line == NULL) + return 0; + + return ((PINFCACHELINE)Context->Line)->FieldCount; +} + + +INFSTATUS +InfpGetBinaryField(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 INF_STATUS_INVALID_PARAMETER; + } + + if (RequiredSize != NULL) + *RequiredSize = 0; + + CacheLine = (PINFCACHELINE)Context->Line; + + if (FieldIndex > (ULONG)CacheLine->FieldCount) + return INF_STATUS_NOT_FOUND; + + CacheField = CacheLine->FirstField; + for (Index = 1; Index < FieldIndex; Index++) + CacheField = CacheField->Next; + + Size = (ULONG)CacheLine->FieldCount - FieldIndex + 1; + + if (RequiredSize != NULL) + *RequiredSize = Size; + + if (ReturnBuffer != NULL) + { + if (ReturnBufferSize < Size) + return INF_STATUS_BUFFER_OVERFLOW; + + /* Copy binary data */ + Ptr = ReturnBuffer; + while (CacheField != NULL) + { + *Ptr = (UCHAR)wcstoul(CacheField->Data, NULL, 16); + + Ptr++; + CacheField = CacheField->Next; + } + } + + return INF_STATUS_SUCCESS; +} + + +INFSTATUS +InfpGetIntField(PINFCONTEXT Context, + ULONG FieldIndex, + PLONG IntegerValue) +{ + PINFCACHELINE CacheLine; + PINFCACHEFIELD CacheField; + ULONG Index; + PWCHAR Ptr; + + if (Context == NULL || Context->Line == NULL || IntegerValue == NULL) + { + DPRINT("Invalid parameter\n"); + return INF_STATUS_INVALID_PARAMETER; + } + + CacheLine = (PINFCACHELINE)Context->Line; + + if (FieldIndex > (ULONG)CacheLine->FieldCount) + { + DPRINT("Invalid parameter\n"); + return INF_STATUS_INVALID_PARAMETER; + } + + if (FieldIndex == 0) + { + Ptr = CacheLine->Key; + } + else + { + CacheField = CacheLine->FirstField; + for (Index = 1; Index < FieldIndex; Index++) + CacheField = CacheField->Next; + + Ptr = CacheField->Data; + } + + *IntegerValue = (LONG)wcstol(Ptr, NULL, 0); + + return INF_STATUS_SUCCESS; +} + + +INFSTATUS +InfpGetMultiSzField(PINFCONTEXT Context, + ULONG FieldIndex, + PWSTR ReturnBuffer, + ULONG ReturnBufferSize, + PULONG RequiredSize) +{ + PINFCACHELINE CacheLine; + PINFCACHEFIELD CacheField; + PINFCACHEFIELD FieldPtr; + ULONG Index; + ULONG Size; + PWCHAR Ptr; + + if (Context == NULL || Context->Line == NULL || FieldIndex == 0) + { + DPRINT("Invalid parameter\n"); + return INF_STATUS_INVALID_PARAMETER; + } + + if (RequiredSize != NULL) + *RequiredSize = 0; + + CacheLine = (PINFCACHELINE)Context->Line; + + if (FieldIndex > (ULONG)CacheLine->FieldCount) + return INF_STATUS_INVALID_PARAMETER; + + 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 += ((ULONG)wcslen (FieldPtr->Data) + 1); + FieldPtr = FieldPtr->Next; + } + Size++; + + if (RequiredSize != NULL) + *RequiredSize = Size; + + if (ReturnBuffer != NULL) + { + if (ReturnBufferSize < Size) + return INF_STATUS_BUFFER_OVERFLOW; + + /* Copy multi-sz string */ + Ptr = ReturnBuffer; + FieldPtr = CacheField; + while (FieldPtr != NULL) + { + Size = (ULONG)wcslen (FieldPtr->Data) + 1; + + wcscpy (Ptr, FieldPtr->Data); + + Ptr = Ptr + Size; + FieldPtr = FieldPtr->Next; + } + *Ptr = 0; + } + + return INF_STATUS_SUCCESS; +} + + +INFSTATUS +InfpGetStringField(PINFCONTEXT Context, + ULONG FieldIndex, + PWSTR ReturnBuffer, + ULONG ReturnBufferSize, + PULONG RequiredSize) +{ + PINFCACHELINE CacheLine; + PINFCACHEFIELD CacheField; + ULONG Index; + PWCHAR Ptr; + ULONG Size; + + if (Context == NULL || Context->Line == NULL || FieldIndex == 0) + { + DPRINT("Invalid parameter\n"); + return INF_STATUS_INVALID_PARAMETER; + } + + if (RequiredSize != NULL) + *RequiredSize = 0; + + CacheLine = (PINFCACHELINE)Context->Line; + + if (FieldIndex > (ULONG)CacheLine->FieldCount) + return INF_STATUS_INVALID_PARAMETER; + + if (FieldIndex == 0) + { + Ptr = CacheLine->Key; + } + else + { + CacheField = CacheLine->FirstField; + for (Index = 1; Index < FieldIndex; Index++) + CacheField = CacheField->Next; + + Ptr = CacheField->Data; + } + +// Size = (ULONG)wcslen (Ptr) + 1; + Size = InfpSubstituteString(Context->Inf, + Ptr, + NULL, + 0); + + if (RequiredSize != NULL) + *RequiredSize = Size + 1; + + if (ReturnBuffer != NULL) + { + if (ReturnBufferSize <= Size) + return INF_STATUS_BUFFER_OVERFLOW; + +// wcscpy (ReturnBuffer, Ptr); + InfpSubstituteString(Context->Inf, + Ptr, + ReturnBuffer, + ReturnBufferSize); + } + + return INF_STATUS_SUCCESS; +} + + +INFSTATUS +InfpGetData(PINFCONTEXT Context, + PWCHAR *Key, + PWCHAR *Data) +{ + PINFCACHELINE CacheKey; + + if (Context == NULL || Context->Line == NULL || Data == NULL) + { + DPRINT("Invalid parameter\n"); + return INF_STATUS_INVALID_PARAMETER; + } + + 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 INF_STATUS_SUCCESS; +} + + +INFSTATUS +InfpGetDataField(PINFCONTEXT Context, + ULONG FieldIndex, + PWCHAR *Data) +{ + PINFCACHELINE CacheLine; + PINFCACHEFIELD CacheField; + ULONG Index; + + if (Context == NULL || Context->Line == NULL || Data == NULL) + { + DPRINT("Invalid parameter\n"); + return INF_STATUS_INVALID_PARAMETER; + } + + CacheLine = (PINFCACHELINE)Context->Line; + + if (FieldIndex > (ULONG)CacheLine->FieldCount) + return INF_STATUS_INVALID_PARAMETER; + + if (FieldIndex == 0) + { + *Data = CacheLine->Key; + } + else + { + CacheField = CacheLine->FirstField; + for (Index = 1; Index < FieldIndex; Index++) + CacheField = CacheField->Next; + + *Data = CacheField->Data; + } + + return INF_STATUS_SUCCESS; +} + +VOID +InfpFreeContext(PINFCONTEXT Context) +{ + FREE(Context); +} + +/* EOF */ diff --git a/reactos/lib/newinflib/infhost.h b/reactos/lib/newinflib/infhost.h new file mode 100644 index 00000000000..6cdb37cbfa1 --- /dev/null +++ b/reactos/lib/newinflib/infhost.h @@ -0,0 +1,86 @@ +/* + * PROJECT: .inf file parser + * LICENSE: GPL - See COPYING in the top level directory + * PROGRAMMER: Royce Mitchell III + * Eric Kohl + * Ge van Geldorp + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "infcommon.h" + +extern NTSTATUS NTAPI RtlMultiByteToUnicodeN(IN PWCHAR UnicodeString, + IN ULONG UnicodeSize, IN PULONG ResultSize, IN PCSTR MbString, IN ULONG MbSize); + +extern BOOLEAN NTAPI RtlIsTextUnicode( PVOID buf, INT len, INT *pf ); + + +extern int InfHostOpenBufferedFile(PHINF InfHandle, + void *Buffer, + ULONG BufferSize, + LCID LocaleId, + ULONG *ErrorLine); +extern int InfHostOpenFile(PHINF InfHandle, + const CHAR *FileName, + LCID LocaleId, + ULONG *ErrorLine); +extern int InfHostWriteFile(HINF InfHandle, + const CHAR *FileName, + const CHAR *HeaderComment); +extern void InfHostCloseFile(HINF InfHandle); +extern int InfHostFindFirstLine(HINF InfHandle, + const WCHAR *Section, + const WCHAR *Key, + PINFCONTEXT *Context); +extern int InfHostFindNextLine(PINFCONTEXT ContextIn, + PINFCONTEXT ContextOut); +extern int InfHostFindFirstMatchLine(PINFCONTEXT ContextIn, + const WCHAR *Key, + PINFCONTEXT ContextOut); +extern int InfHostFindNextMatchLine(PINFCONTEXT ContextIn, + const WCHAR *Key, + PINFCONTEXT ContextOut); +extern LONG InfHostGetLineCount(HINF InfHandle, + const WCHAR *Section); +extern LONG InfHostGetFieldCount(PINFCONTEXT Context); +extern int InfHostGetBinaryField(PINFCONTEXT Context, + ULONG FieldIndex, + UCHAR *ReturnBuffer, + ULONG ReturnBufferSize, + ULONG *RequiredSize); +extern int InfHostGetIntField(PINFCONTEXT Context, + ULONG FieldIndex, + ULONG *IntegerValue); +extern int InfHostGetMultiSzField(PINFCONTEXT Context, + ULONG FieldIndex, + WCHAR *ReturnBuffer, + ULONG ReturnBufferSize, + ULONG *RequiredSize); +extern int InfHostGetStringField(PINFCONTEXT Context, + ULONG FieldIndex, + WCHAR *ReturnBuffer, + ULONG ReturnBufferSize, + ULONG *RequiredSize); +extern int InfHostGetData(PINFCONTEXT Context, + WCHAR **Key, + WCHAR **Data); +extern int InfHostGetDataField(PINFCONTEXT Context, + ULONG FieldIndex, + WCHAR **Data); +extern int InfHostFindOrAddSection(HINF InfHandle, + const WCHAR *Section, + PINFCONTEXT *Context); +extern int InfHostAddLine(PINFCONTEXT Context, const WCHAR *Key); +extern int InfHostAddField(PINFCONTEXT Context, const WCHAR *Data); +extern void InfHostFreeContext(PINFCONTEXT Context); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +/* EOF */ diff --git a/reactos/lib/newinflib/infhostgen.c b/reactos/lib/newinflib/infhostgen.c new file mode 100644 index 00000000000..e5ad1b96e9b --- /dev/null +++ b/reactos/lib/newinflib/infhostgen.c @@ -0,0 +1,316 @@ +/* + * PROJECT: .inf file parser + * LICENSE: GPL - See COPYING in the top level directory + * PROGRAMMER: Royce Mitchell III + * Eric Kohl + * Ge van Geldorp + */ + +/* INCLUDES *****************************************************************/ + +#include "inflib.h" +#include "infhost.h" + +#define NDEBUG +#include + +/* PUBLIC FUNCTIONS *********************************************************/ + +int +InfHostOpenBufferedFile(PHINF InfHandle, + void *Buffer, + ULONG BufferSize, + LCID LocaleId, + ULONG *ErrorLine) +{ + INFSTATUS Status; + PINFCACHE Cache; + WCHAR *FileBuffer; + ULONG FileBufferSize; + + *InfHandle = NULL; + *ErrorLine = (ULONG)-1; + + /* Allocate file buffer */ + FileBufferSize = BufferSize + 2; + FileBuffer = MALLOC(FileBufferSize); + if (FileBuffer == NULL) + { + DPRINT1("MALLOC() failed\n"); + return(INF_STATUS_INSUFFICIENT_RESOURCES); + } + + MEMCPY(FileBuffer, Buffer, BufferSize); + + /* Append string terminator */ + FileBuffer[BufferSize] = 0; + FileBuffer[BufferSize + 1] = 0; + + /* Allocate infcache header */ + Cache = (PINFCACHE)MALLOC(sizeof(INFCACHE)); + if (Cache == NULL) + { + DPRINT1("MALLOC() failed\n"); + FREE(FileBuffer); + return(INF_STATUS_INSUFFICIENT_RESOURCES); + } + + /* Initialize inicache header */ + ZEROMEMORY(Cache, + sizeof(INFCACHE)); + + Cache->LocaleId = LocaleId; + + if (!RtlIsTextUnicode(FileBuffer, (INT)FileBufferSize, NULL)) + { +// static const BYTE utf8_bom[3] = { 0xef, 0xbb, 0xbf }; + WCHAR *new_buff; +// UINT codepage = CP_ACP; + UINT offset = 0; + +// if (BufferSize > sizeof(utf8_bom) && !memcmp(FileBuffer, utf8_bom, sizeof(utf8_bom) )) +// { +// codepage = CP_UTF8; +// offset = sizeof(utf8_bom); +// } + + new_buff = MALLOC(FileBufferSize * sizeof(WCHAR)); + if (new_buff != NULL) + { +// DWORD len = MultiByteToWideChar( codepage, 0, (char *)FileBuffer + offset, +// FileBufferSize - offset, new_buff, FileBufferSize); + + ULONG len; + Status = RtlMultiByteToUnicodeN(new_buff, + FileBufferSize * sizeof(WCHAR), + &len, + (char *)FileBuffer + offset, + FileBufferSize - offset); + + Status = InfpParseBuffer(Cache, + new_buff, + new_buff + len / sizeof(WCHAR), + ErrorLine); + FREE(new_buff); + } + else + Status = INF_STATUS_INSUFFICIENT_RESOURCES; + } + else + { + WCHAR *new_buff = (WCHAR *)FileBuffer; + /* UCS-16 files should start with the Unicode BOM; we should skip it */ + if (*new_buff == 0xfeff) + { + new_buff++; + FileBufferSize -= sizeof(WCHAR); + } + Status = InfpParseBuffer(Cache, + new_buff, + (WCHAR*)((char*)new_buff + FileBufferSize), + ErrorLine); + } + + /* Parse the inf buffer */ +// Status = InfpParseBuffer (Cache, +// FileBuffer, +// FileBuffer + BufferSize, +// ErrorLine); + if (!INF_SUCCESS(Status)) + { + FREE(Cache); + Cache = NULL; + } + + /* Free file buffer */ + FREE(FileBuffer); + + *InfHandle = (HINF)Cache; + + return INF_SUCCESS(Status) ? 0 : -1; +} + + +int +InfHostOpenFile(PHINF InfHandle, + const CHAR *FileName, + LCID LocaleId, + ULONG *ErrorLine) +{ + FILE *File; + CHAR *FileBuffer; + ULONG FileLength; + ULONG FileBufferLength; + PINFCACHE Cache; + INFSTATUS Status = INF_STATUS_SUCCESS; + + *InfHandle = NULL; + *ErrorLine = (ULONG)-1; + + /* Open the inf file */ + File = fopen(FileName, "rb"); + if (NULL == File) + { + DPRINT1("fopen() failed (errno %d)\n", errno); + return -1; + } + + DPRINT("fopen() successful\n"); + + /* Query file size */ + if (fseek(File, (size_t)0, SEEK_END)) + { + DPRINT1("fseek() to EOF failed (errno %d)\n", errno); + fclose(File); + return -1; + } + + FileLength = (ULONG)ftell(File); + if ((ULONG) -1 == FileLength) + { + DPRINT1("ftell() failed (errno %d)\n", errno); + fclose(File); + return -1; + } + DPRINT("File size: %u\n", (UINT)FileLength); + + /* Rewind */ + if (fseek(File, (size_t)0, SEEK_SET)) + { + DPRINT1("fseek() to BOF failed (errno %d)\n", errno); + fclose(File); + return -1; + } + + /* Allocate file buffer */ + FileBufferLength = FileLength + 2; + FileBuffer = MALLOC(FileBufferLength); + if (FileBuffer == NULL) + { + DPRINT1("MALLOC() failed\n"); + fclose(File); + return -1; + } + + /* Read file */ + if (FileLength != fread(FileBuffer, (size_t)1, (size_t)FileLength, File)) + { + DPRINT1("fread() failed (errno %d)\n", errno); + fclose(File); + return -1; + } + + fclose(File); + + /* Append string terminator */ + FileBuffer[FileLength] = 0; + FileBuffer[FileLength + 1] = 0; + + /* Allocate infcache header */ + Cache = (PINFCACHE)MALLOC(sizeof(INFCACHE)); + if (Cache == NULL) + { + DPRINT1("MALLOC() failed\n"); + FREE(FileBuffer); + return -1; + } + + /* Initialize inicache header */ + ZEROMEMORY(Cache, + sizeof(INFCACHE)); + + Cache->LocaleId = LocaleId; + + /* Parse the inf buffer */ + if (!RtlIsTextUnicode(FileBuffer, (INT)FileBufferLength, NULL)) + { +// static const BYTE utf8_bom[3] = { 0xef, 0xbb, 0xbf }; + WCHAR *new_buff; +// UINT codepage = CP_ACP; + UINT offset = 0; + +// if (FileLength > sizeof(utf8_bom) && !memcmp(FileBuffer, utf8_bom, sizeof(utf8_bom) )) +// { +// codepage = CP_UTF8; +// offset = sizeof(utf8_bom); +// } + + new_buff = MALLOC(FileBufferLength * sizeof(WCHAR)); + if (new_buff != NULL) + { +// DWORD len = MultiByteToWideChar( codepage, 0, (char *)FileBuffer + offset, +// FileLength - offset, new_buff, FileLength); + + ULONG len; + Status = RtlMultiByteToUnicodeN(new_buff, + FileBufferLength * sizeof(WCHAR), + &len, + (char *)FileBuffer + offset, + FileBufferLength - offset); + + Status = InfpParseBuffer(Cache, + new_buff, + new_buff + len / sizeof(WCHAR), + ErrorLine); + + FREE(new_buff); + } + else + Status = INF_STATUS_INSUFFICIENT_RESOURCES; + } + else + { + WCHAR *new_buff = (WCHAR *)FileBuffer; + /* UCS-16 files should start with the Unicode BOM; we should skip it */ + if (*new_buff == 0xfeff) + { + new_buff++; + FileBufferLength -= sizeof(WCHAR); + } + Status = InfpParseBuffer(Cache, + new_buff, + (WCHAR*)((char*)new_buff + FileBufferLength), + ErrorLine); + } + +// Status = InfpParseBuffer (Cache, +// FileBuffer, +// FileBuffer + FileLength, +// ErrorLine); + if (!INF_SUCCESS(Status)) + { + FREE(Cache); + Cache = NULL; + } + + /* Free file buffer */ + FREE(FileBuffer); + + *InfHandle = (HINF)Cache; + + return INF_SUCCESS(Status) ? 0 : -1; +} + + +void +InfHostCloseFile(HINF InfHandle) +{ + PINFCACHE Cache; + + Cache = (PINFCACHE)InfHandle; + + if (Cache == NULL) + { + return; + } + + while (Cache->FirstSection != NULL) + { + Cache->FirstSection = InfpFreeSection(Cache->FirstSection); + } + Cache->LastSection = NULL; + + FREE(Cache); +} + +/* EOF */ diff --git a/reactos/lib/newinflib/infhostget.c b/reactos/lib/newinflib/infhostget.c new file mode 100644 index 00000000000..bd49be17002 --- /dev/null +++ b/reactos/lib/newinflib/infhostget.c @@ -0,0 +1,249 @@ +/* + * PROJECT: .inf file parser + * LICENSE: GPL - See COPYING in the top level directory + * PROGRAMMER: Royce Mitchell III + * Eric Kohl + * Ge van Geldorp + */ + +/* INCLUDES *****************************************************************/ + +#include "inflib.h" +#include "infhost.h" + +#define NDEBUG +#include + +int +InfHostFindFirstLine(HINF InfHandle, + const WCHAR *Section, + const WCHAR *Key, + PINFCONTEXT *Context) +{ + INFSTATUS Status; + + Status = InfpFindFirstLine(InfHandle, Section, Key, Context); + if (INF_SUCCESS(Status)) + { + return 0; + } + else + { + errno = Status; + return -1; + } +} + + +int +InfHostFindNextLine(PINFCONTEXT ContextIn, + PINFCONTEXT ContextOut) +{ + INFSTATUS Status; + + Status = InfpFindNextLine(ContextIn, ContextOut); + if (INF_SUCCESS(Status)) + { + return 0; + } + else + { + errno = Status; + return -1; + } +} + + +int +InfHostFindFirstMatchLine(PINFCONTEXT ContextIn, + const WCHAR *Key, + PINFCONTEXT ContextOut) +{ + INFSTATUS Status; + + Status = InfpFindFirstMatchLine(ContextIn, Key, ContextOut); + if (INF_SUCCESS(Status)) + { + return 0; + } + else + { + errno = Status; + return -1; + } +} + + +int +InfHostFindNextMatchLine(PINFCONTEXT ContextIn, + const WCHAR *Key, + PINFCONTEXT ContextOut) +{ + INFSTATUS Status; + + Status = InfpFindNextMatchLine(ContextIn, Key, ContextOut); + if (INF_SUCCESS(Status)) + { + return 0; + } + else + { + errno = Status; + return -1; + } +} + + +LONG +InfHostGetLineCount(HINF InfHandle, + PCWSTR Section) +{ + return InfpGetLineCount(InfHandle, Section); +} + + +/* InfGetLineText */ + + +LONG +InfHostGetFieldCount(PINFCONTEXT Context) +{ + return InfpGetFieldCount(Context); +} + + +int +InfHostGetBinaryField(PINFCONTEXT Context, + ULONG FieldIndex, + UCHAR *ReturnBuffer, + ULONG ReturnBufferSize, + ULONG *RequiredSize) +{ + INFSTATUS Status; + + Status = InfpGetBinaryField(Context, FieldIndex, ReturnBuffer, + ReturnBufferSize, RequiredSize); + if (INF_SUCCESS(Status)) + { + return 0; + } + else + { + errno = Status; + return -1; + } +} + + +int +InfHostGetIntField(PINFCONTEXT Context, + ULONG FieldIndex, + ULONG *IntegerValue) +{ + INFSTATUS Status; + + Status = InfpGetIntField(Context, FieldIndex, (PLONG)IntegerValue); + if (INF_SUCCESS(Status)) + { + return 0; + } + else + { + errno = Status; + return -1; + } +} + + +int +InfHostGetMultiSzField(PINFCONTEXT Context, + ULONG FieldIndex, + WCHAR *ReturnBuffer, + ULONG ReturnBufferSize, + ULONG *RequiredSize) +{ + INFSTATUS Status; + + Status = InfpGetMultiSzField(Context, FieldIndex, ReturnBuffer, + ReturnBufferSize, RequiredSize); + if (INF_SUCCESS(Status)) + { + return 0; + } + else + { + errno = Status; + return -1; + } +} + + +int +InfHostGetStringField(PINFCONTEXT Context, + ULONG FieldIndex, + WCHAR *ReturnBuffer, + ULONG ReturnBufferSize, + ULONG *RequiredSize) +{ + INFSTATUS Status; + + Status = InfpGetStringField(Context, FieldIndex, ReturnBuffer, + ReturnBufferSize, RequiredSize); + if (INF_SUCCESS(Status)) + { + return 0; + } + else + { + errno = Status; + return -1; + } +} + + +int +InfHostGetData(PINFCONTEXT Context, + WCHAR **Key, + WCHAR **Data) +{ + INFSTATUS Status; + + Status = InfpGetData(Context, Key, Data); + if (INF_SUCCESS(Status)) + { + return 0; + } + else + { + errno = Status; + return -1; + } +} + + +int +InfHostGetDataField(PINFCONTEXT Context, + ULONG FieldIndex, + WCHAR **Data) +{ + INFSTATUS Status; + + Status = InfpGetDataField(Context, FieldIndex, Data); + if (INF_SUCCESS(Status)) + { + return 0; + } + else + { + errno = Status; + return -1; + } +} + +VOID +InfHostFreeContext(PINFCONTEXT Context) +{ + InfpFreeContext(Context); +} + +/* EOF */ diff --git a/reactos/lib/newinflib/infhostput.c b/reactos/lib/newinflib/infhostput.c new file mode 100644 index 00000000000..a5233e50545 --- /dev/null +++ b/reactos/lib/newinflib/infhostput.c @@ -0,0 +1,115 @@ +/* + * PROJECT: .inf file parser + * LICENSE: GPL - See COPYING in the top level directory + * COPYRIGHT: Copyright 2005 Ge van Geldorp + */ + +/* INCLUDES *****************************************************************/ + +#include "inflib.h" +#include "infhost.h" + +#define NDEBUG +#include + +int +InfHostWriteFile(HINF InfHandle, + const CHAR *FileName, + const CHAR *HeaderComment) +{ + WCHAR *Buffer; + ULONG BufferSize; + INFSTATUS Status; + FILE *File; + + Status = InfpBuildFileBuffer((PINFCACHE) InfHandle, &Buffer, &BufferSize); + if (! INF_SUCCESS(Status)) + { + errno = Status; + return -1; + } + + File = fopen(FileName, "wb"); + if (NULL == File) + { + FREE(Buffer); + DPRINT1("fopen() failed (errno %d)\n", errno); + return -1; + } + + DPRINT("fopen() successful\n"); + + if (NULL != HeaderComment && '\0' != *HeaderComment) + { +// fprintf(File, "; %s\r\n\r\n", HeaderComment); + } + + if (BufferSize != fwrite(Buffer, (size_t)1, (size_t)BufferSize, File)) + { + DPRINT1("fwrite() failed (errno %d)\n", errno); + fclose(File); + FREE(Buffer); + return -1; + } + + fclose(File); + + FREE(Buffer); + + return 0; +} + +int +InfHostFindOrAddSection(HINF InfHandle, + const WCHAR *Section, + PINFCONTEXT *Context) +{ + INFSTATUS Status; + + Status = InfpFindOrAddSection((PINFCACHE) InfHandle, Section, Context); + if (INF_SUCCESS(Status)) + { + return 0; + } + else + { + errno = Status; + return -1; + } +} + +int +InfHostAddLine(PINFCONTEXT Context, const WCHAR *Key) +{ + INFSTATUS Status; + + Status = InfpAddLineWithKey(Context, Key); + if (INF_SUCCESS(Status)) + { + return 0; + } + else + { + errno = Status; + return -1; + } +} + +int +InfHostAddField(PINFCONTEXT Context, const WCHAR *Data) +{ + INFSTATUS Status; + + Status = InfpAddField(Context, Data); + if (INF_SUCCESS(Status)) + { + return 0; + } + else + { + errno = Status; + return -1; + } +} + +/* EOF */ diff --git a/reactos/lib/newinflib/infhostrtl.c b/reactos/lib/newinflib/infhostrtl.c new file mode 100644 index 00000000000..c9a522149df --- /dev/null +++ b/reactos/lib/newinflib/infhostrtl.c @@ -0,0 +1,151 @@ +/* + * PROJECT: .inf file parser + * LICENSE: GPL - See COPYING in the top level directory + * PROGRAMMER: Royce Mitchell III + * Eric Kohl + * Ge van Geldorp + */ + +/* INCLUDES *****************************************************************/ + +#include "inflib.h" +#include "infhost.h" + +#define NDEBUG +#include + +NTSTATUS NTAPI +RtlMultiByteToUnicodeN( + IN PWCHAR UnicodeString, + IN ULONG UnicodeSize, + IN PULONG ResultSize, + IN PCSTR MbString, + IN ULONG MbSize) +{ + ULONG Size = 0; + ULONG i; + PUCHAR WideString; + + /* single-byte code page */ + if (MbSize > (UnicodeSize / sizeof(WCHAR))) + Size = UnicodeSize / sizeof(WCHAR); + else + Size = MbSize; + + if (ResultSize != NULL) + *ResultSize = Size * sizeof(WCHAR); + + WideString = (PUCHAR)UnicodeString; + for (i = 0; i <= Size; i++) + { + WideString[2 * i + 0] = (UCHAR)MbString[i]; + WideString[2 * i + 1] = 0; + } + + return STATUS_SUCCESS; +} + + +BOOLEAN +NTAPI +RtlIsTextUnicode( PVOID buf, INT len, INT *pf ) +{ + static const WCHAR std_control_chars[] = {'\r','\n','\t',' ',0x3000,0}; + static const WCHAR byterev_control_chars[] = {0x0d00,0x0a00,0x0900,0x2000,0}; + const WCHAR *s = buf; + int i; + unsigned int flags = MAXULONG, out_flags = 0; + + if (len < sizeof(WCHAR)) + { + /* FIXME: MSDN documents IS_TEXT_UNICODE_BUFFER_TOO_SMALL but there is no such thing... */ + if (pf) *pf = 0; + return FALSE; + } + if (pf) + flags = (unsigned int)*pf; + /* + * Apply various tests to the text string. According to the + * docs, each test "passed" sets the corresponding flag in + * the output flags. But some of the tests are mutually + * exclusive, so I don't see how you could pass all tests ... + */ + + /* Check for an odd length ... pass if even. */ + if (len & 1) out_flags |= IS_TEXT_UNICODE_ODD_LENGTH; + + if (((char *)buf)[len - 1] == 0) + len--; /* Windows seems to do something like that to avoid e.g. false IS_TEXT_UNICODE_NULL_BYTES */ + + len /= (INT)sizeof(WCHAR); + /* Windows only checks the first 256 characters */ + if (len > 256) len = 256; + + /* Check for the special byte order unicode marks. */ + if (*s == 0xFEFF) out_flags |= IS_TEXT_UNICODE_SIGNATURE; + if (*s == 0xFFFE) out_flags |= IS_TEXT_UNICODE_REVERSE_SIGNATURE; + + /* apply some statistical analysis */ + if (flags & IS_TEXT_UNICODE_STATISTICS) + { + int stats = 0; + /* FIXME: checks only for ASCII characters in the unicode stream */ + for (i = 0; i < len; i++) + { + if (s[i] <= 255) stats++; + } + if (stats > len / 2) + out_flags |= IS_TEXT_UNICODE_STATISTICS; + } + + /* Check for unicode NULL chars */ + if (flags & IS_TEXT_UNICODE_NULL_BYTES) + { + for (i = 0; i < len; i++) + { + if (!(s[i] & 0xff) || !(s[i] >> 8)) + { + out_flags |= IS_TEXT_UNICODE_NULL_BYTES; + break; + } + } + } + + if (flags & IS_TEXT_UNICODE_CONTROLS) + { + for (i = 0; i < len; i++) + { + if (wcschr(std_control_chars, s[i])) + { + out_flags |= IS_TEXT_UNICODE_CONTROLS; + break; + } + } + } + + if (flags & IS_TEXT_UNICODE_REVERSE_CONTROLS) + { + for (i = 0; i < len; i++) + { + if (wcschr(byterev_control_chars, s[i])) + { + out_flags |= IS_TEXT_UNICODE_REVERSE_CONTROLS; + break; + } + } + } + + if (pf) + { + out_flags &= (unsigned int)*pf; + *pf = (INT)out_flags; + } + /* check for flags that indicate it's definitely not valid Unicode */ + if (out_flags & (IS_TEXT_UNICODE_REVERSE_MASK | IS_TEXT_UNICODE_NOT_UNICODE_MASK)) return FALSE; + /* now check for invalid ASCII, and assume Unicode if so */ + if (out_flags & IS_TEXT_UNICODE_NOT_ASCII_MASK) return TRUE; + /* now check for Unicode flags */ + if (out_flags & IS_TEXT_UNICODE_UNICODE_MASK) return TRUE; + /* no flags set */ + return FALSE; +} diff --git a/reactos/lib/newinflib/inflib.h b/reactos/lib/newinflib/inflib.h new file mode 100644 index 00000000000..7dff17fa035 --- /dev/null +++ b/reactos/lib/newinflib/inflib.h @@ -0,0 +1,15 @@ +/* + * PROJECT: .inf file parser + * LICENSE: GPL - See COPYING in the top level directory + * COPYRIGHT: Copyright 2005 Ge van Geldorp + */ + +#include +#include +#include + +#include "builddep.h" +#include "infcommon.h" +#include "infpriv.h" + +/* EOF */ diff --git a/reactos/lib/newinflib/inflib.mak b/reactos/lib/newinflib/inflib.mak new file mode 100644 index 00000000000..a0edbe26b96 --- /dev/null +++ b/reactos/lib/newinflib/inflib.mak @@ -0,0 +1,76 @@ +INFLIB_BASE = $(LIB_BASE_)newinflib +INFLIB_BASE_ = $(INFLIB_BASE)$(SEP) +INFLIB_INT = $(INTERMEDIATE_)$(INFLIB_BASE)_host +INFLIB_INT_ = $(INTERMEDIATE_)$(INFLIB_BASE)_host$(SEP) +INFLIB_OUT = $(OUTPUT_)$(INFLIB_BASE)_host +INFLIB_OUT_ = $(OUTPUT_)$(INFLIB_BASE)_host$(SEP) + +$(INFLIB_INT): | $(LIB_INT) + $(ECHO_MKDIR) + ${mkdir} $@ + +ifneq ($(INTERMEDIATE),$(OUTPUT)) +$(INFLIB_OUT): | $(OUTPUT_)$(LIB_BASE) + $(ECHO_MKDIR) + ${mkdir} $@ +endif + +INFLIB_HOST_TARGET = \ + $(INFLIB_OUT)$(SEP)newinflib.a + +INFLIB_HOST_SOURCES = $(addprefix $(INFLIB_BASE_), \ + infcore.c \ + infget.c \ + infput.c \ + infhostgen.c \ + infhostget.c \ + infhostput.c \ + infhostrtl.c \ + ) + +INFLIB_HOST_OBJECTS = \ + $(subst $(INFLIB_BASE), $(INFLIB_INT), $(INFLIB_HOST_SOURCES:.c=.o)) + +INFLIB_HOST_CFLAGS = -O3 -Wall -Wpointer-arith -Wconversion \ + -Wstrict-prototypes -Wmissing-prototypes -DINFLIB_HOST \ + -Iinclude/reactos -Iinclude $(HOST_CFLAGS) + +$(INFLIB_HOST_TARGET): $(INFLIB_HOST_OBJECTS) | $(INFLIB_OUT) + $(ECHO_HOSTAR) + $(host_ar) -r $@ $(INFLIB_HOST_OBJECTS) + +$(INFLIB_INT_)infcore.o: $(INFLIB_BASE_)infcore.c | $(INFLIB_INT) + $(ECHO_HOSTCC) + ${host_gcc} $(INFLIB_HOST_CFLAGS) -c $< -o $@ + +$(INFLIB_INT_)infget.o: $(INFLIB_BASE_)infget.c | $(INFLIB_INT) + $(ECHO_HOSTCC) + ${host_gcc} $(INFLIB_HOST_CFLAGS) -c $< -o $@ + +$(INFLIB_INT_)infput.o: $(INFLIB_BASE_)infput.c | $(INFLIB_INT) + $(ECHO_HOSTCC) + ${host_gcc} $(INFLIB_HOST_CFLAGS) -c $< -o $@ + +$(INFLIB_INT_)infhostgen.o: $(INFLIB_BASE_)infhostgen.c | $(INFLIB_INT) + $(ECHO_HOSTCC) + ${host_gcc} $(INFLIB_HOST_CFLAGS) -c $< -o $@ + +$(INFLIB_INT_)infhostget.o: $(INFLIB_BASE_)infhostget.c | $(INFLIB_INT) + $(ECHO_HOSTCC) + ${host_gcc} $(INFLIB_HOST_CFLAGS) -c $< -o $@ + +$(INFLIB_INT_)infhostput.o: $(INFLIB_BASE_)infhostput.c | $(INFLIB_INT) + $(ECHO_HOSTCC) + ${host_gcc} $(INFLIB_HOST_CFLAGS) -c $< -o $@ + +$(INFLIB_INT_)infhostrtl.o: $(INFLIB_BASE_)infhostrtl.c | $(INFLIB_INT) + $(ECHO_HOSTCC) + ${host_gcc} $(INFLIB_HOST_CFLAGS) -c $< -o $@ + +.PHONY: newinflib_host +newinflib_host: $(INFLIB_HOST_TARGET) + +.PHONY: newinflib_host_clean +newinflib_host_clean: + -@$(rm) $(INFLIB_HOST_TARGET) $(INFLIB_HOST_OBJECTS) 2>$(NUL) +clean: newinflib_host_clean diff --git a/reactos/lib/newinflib/inflib.rbuild b/reactos/lib/newinflib/inflib.rbuild new file mode 100644 index 00000000000..fc7c2cdd7bb --- /dev/null +++ b/reactos/lib/newinflib/inflib.rbuild @@ -0,0 +1,31 @@ + + + + + . + infcore.c + infget.c + infput.c + infrosgen.c + infrosget.c + infrosput.c + + + . + + + -Wpointer-arith + -Wconversion + -Wstrict-prototypes + -Wmissing-prototypes + + + infcore.c + infget.c + infput.c + infhostgen.c + infhostget.c + infhostput.c + infhostrtl.c + + diff --git a/reactos/lib/newinflib/infpriv.h b/reactos/lib/newinflib/infpriv.h new file mode 100644 index 00000000000..0d2cea94dc4 --- /dev/null +++ b/reactos/lib/newinflib/infpriv.h @@ -0,0 +1,145 @@ +/* + * PROJECT: .inf file parser + * LICENSE: GPL - See COPYING in the top level directory + * PROGRAMMER: Royce Mitchell III + * Eric Kohl + * Ge van Geldorp + */ + +#pragma once + +#ifndef FIELD_OFFSET +#define FIELD_OFFSET(t,f) ((ptrdiff_t)&(((t*)0)->f)) +#endif + +#define INF_STATUS_INSUFFICIENT_RESOURCES ((INFSTATUS)0xC000009A) +#define INF_STATUS_BAD_SECTION_NAME_LINE ((INFSTATUS)0xC0700001) +#define INF_STATUS_SECTION_NAME_TOO_LONG ((INFSTATUS)0xC0700002) +#define INF_STATUS_WRONG_INF_STYLE ((INFSTATUS)0xC0700003) +#define INF_STATUS_NOT_ENOUGH_MEMORY ((INFSTATUS)0xC0700004) + +typedef struct _INFCACHEFIELD +{ + struct _INFCACHEFIELD *Next; + struct _INFCACHEFIELD *Prev; + + WCHAR Data[1]; +} INFCACHEFIELD, *PINFCACHEFIELD; + +typedef struct _INFCACHELINE +{ + struct _INFCACHELINE *Next; + struct _INFCACHELINE *Prev; + + LONG FieldCount; + + PWCHAR Key; + + PINFCACHEFIELD FirstField; + PINFCACHEFIELD LastField; + +} INFCACHELINE, *PINFCACHELINE; + +typedef struct _INFCACHESECTION +{ + struct _INFCACHESECTION *Next; + struct _INFCACHESECTION *Prev; + + PINFCACHELINE FirstLine; + PINFCACHELINE LastLine; + + LONG LineCount; + + WCHAR Name[1]; +} INFCACHESECTION, *PINFCACHESECTION; + +typedef struct _INFCACHE +{ + LCID LocaleId; + PINFCACHESECTION FirstSection; + PINFCACHESECTION LastSection; + + PINFCACHESECTION StringsSection; +} INFCACHE, *PINFCACHE; + +typedef struct _INFCONTEXT +{ + PINFCACHE Inf; + PINFCACHESECTION Section; + PINFCACHELINE Line; +} INFCONTEXT; + +typedef int INFSTATUS; + +/* FUNCTIONS ****************************************************************/ + +extern INFSTATUS InfpParseBuffer(PINFCACHE file, + const WCHAR *buffer, + const WCHAR *end, + PULONG error_line); +extern PINFCACHESECTION InfpFreeSection(PINFCACHESECTION Section); +extern PINFCACHESECTION InfpAddSection(PINFCACHE Cache, + PCWSTR Name); +extern PINFCACHELINE InfpAddLine(PINFCACHESECTION Section); +extern PVOID InfpAddKeyToLine(PINFCACHELINE Line, + PCWSTR Key); +extern PVOID InfpAddFieldToLine(PINFCACHELINE Line, + PCWSTR Data); +extern PINFCACHELINE InfpFindKeyLine(PINFCACHESECTION Section, + PCWSTR Key); +extern PINFCACHESECTION InfpFindSection(PINFCACHE Cache, + PCWSTR Section); + +extern INFSTATUS InfpBuildFileBuffer(PINFCACHE InfHandle, + PWCHAR *Buffer, + PULONG BufferSize); + +extern INFSTATUS InfpFindFirstLine(PINFCACHE InfHandle, + PCWSTR Section, + PCWSTR Key, + PINFCONTEXT *Context); +extern INFSTATUS InfpFindNextLine(PINFCONTEXT ContextIn, + PINFCONTEXT ContextOut); +extern INFSTATUS InfpFindFirstMatchLine(PINFCONTEXT ContextIn, + PCWSTR Key, + PINFCONTEXT ContextOut); +extern INFSTATUS InfpFindNextMatchLine(PINFCONTEXT ContextIn, + PCWSTR Key, + PINFCONTEXT ContextOut); +extern LONG InfpGetLineCount(HINF InfHandle, + PCWSTR Section); +extern LONG InfpGetFieldCount(PINFCONTEXT Context); +extern INFSTATUS InfpGetBinaryField(PINFCONTEXT Context, + ULONG FieldIndex, + PUCHAR ReturnBuffer, + ULONG ReturnBufferSize, + PULONG RequiredSize); +extern INFSTATUS InfpGetIntField(PINFCONTEXT Context, + ULONG FieldIndex, + PLONG IntegerValue); +extern INFSTATUS InfpGetMultiSzField(PINFCONTEXT Context, + ULONG FieldIndex, + PWSTR ReturnBuffer, + ULONG ReturnBufferSize, + PULONG RequiredSize); +extern INFSTATUS InfpGetStringField(PINFCONTEXT Context, + ULONG FieldIndex, + PWSTR ReturnBuffer, + ULONG ReturnBufferSize, + PULONG RequiredSize); +extern INFSTATUS InfpGetData(PINFCONTEXT Context, + PWCHAR *Key, + PWCHAR *Data); +extern INFSTATUS InfpGetDataField(PINFCONTEXT Context, + ULONG FieldIndex, + PWCHAR *Data); + +extern INFSTATUS InfpFindOrAddSection(PINFCACHE Cache, + PCWSTR Section, + PINFCONTEXT *Context); +extern INFSTATUS InfpAddLineWithKey(PINFCONTEXT Context, PCWSTR Key); +extern INFSTATUS InfpAddField(PINFCONTEXT Context, PCWSTR Data); + +extern VOID InfpFreeContext(PINFCONTEXT Context); + +/* EOF */ diff --git a/reactos/lib/newinflib/infput.c b/reactos/lib/newinflib/infput.c new file mode 100644 index 00000000000..2d60af0fb9f --- /dev/null +++ b/reactos/lib/newinflib/infput.c @@ -0,0 +1,264 @@ +/* + * PROJECT: .inf file parser + * LICENSE: GPL - See COPYING in the top level directory + * COPYRIGHT: Copyright 2005 Ge van Geldorp + */ + +/* INCLUDES *****************************************************************/ + +#include "inflib.h" + +#define NDEBUG +#include + +#define EOL L"\r\n" +#define SIZE_INC 1024 + +typedef struct _OUTPUTBUFFER +{ + PWCHAR Buffer; + PWCHAR Current; + ULONG TotalSize; + ULONG FreeSize; + INFSTATUS Status; +} OUTPUTBUFFER, *POUTPUTBUFFER; + +static void +Output(POUTPUTBUFFER OutBuf, PCWSTR Text) +{ + ULONG Length; + PWCHAR NewBuf; + ULONG NewSize; + + /* Skip mode? */ + if (! INF_SUCCESS(OutBuf->Status)) + { + return; + } + + /* Doesn't fit? */ + Length = (ULONG)wcslen(Text) * sizeof(WCHAR); + if (OutBuf->FreeSize < Length + 1 && INF_SUCCESS(OutBuf->Status)) + { + DPRINT("Out of free space. TotalSize %u FreeSize %u Length %u\n", + (UINT)OutBuf->TotalSize, (UINT)OutBuf->FreeSize, (UINT)Length); + /* Round up to next SIZE_INC */ + NewSize = OutBuf->TotalSize + + (((Length + 1) - OutBuf->FreeSize + (SIZE_INC - 1)) / + SIZE_INC) * SIZE_INC; + DPRINT("NewSize %u\n", (UINT)NewSize); + NewBuf = MALLOC(NewSize); + /* Abort if failed */ + if (NULL == NewBuf) + { + DPRINT1("MALLOC() failed\n"); + OutBuf->Status = INF_STATUS_NO_MEMORY; + return; + } + + /* Need to copy old contents? */ + if (NULL != OutBuf->Buffer) + { + DPRINT("Copying %u bytes from old content\n", + (UINT)(OutBuf->TotalSize - OutBuf->FreeSize)); + MEMCPY(NewBuf, OutBuf->Buffer, OutBuf->TotalSize - OutBuf->FreeSize); + OutBuf->Current = NewBuf + (OutBuf->Current - OutBuf->Buffer); + FREE(OutBuf->Buffer); + } + else + { + OutBuf->Current = NewBuf; + } + OutBuf->Buffer = NewBuf; + OutBuf->FreeSize += NewSize - OutBuf->TotalSize; + OutBuf->TotalSize = NewSize; + DPRINT("After reallocation TotalSize %u FreeSize %u\n", + (UINT)OutBuf->TotalSize, (UINT)OutBuf->FreeSize); + } + + /* We're guaranteed to have enough room now. Copy char by char because of + possible "conversion" from Unicode to Ansi */ + while (Length--) + { + *OutBuf->Current++ = *Text++; + OutBuf->FreeSize--; + } + *OutBuf->Current = '\0'; +} + +INFSTATUS +InfpBuildFileBuffer(PINFCACHE Cache, + PWCHAR *Buffer, + PULONG BufferSize) +{ + OUTPUTBUFFER OutBuf; + PINFCACHESECTION CacheSection; + PINFCACHELINE CacheLine; + PINFCACHEFIELD CacheField; + PWCHAR p; + BOOLEAN NeedQuotes; + + OutBuf.Buffer = NULL; + OutBuf.Current = NULL; + OutBuf.FreeSize = 0; + OutBuf.TotalSize = 0; + OutBuf.Status = INF_STATUS_SUCCESS; + + /* Iterate through list of sections */ + CacheSection = Cache->FirstSection; + while (CacheSection != NULL) + { + DPRINT("Processing section %S\n", CacheSection->Name); + if (CacheSection != Cache->FirstSection) + { + Output(&OutBuf, EOL); + } + Output(&OutBuf, L"["); + Output(&OutBuf, CacheSection->Name); + Output(&OutBuf, L"]"); + Output(&OutBuf, EOL); + + /* Iterate through list of lines */ + CacheLine = CacheSection->FirstLine; + while (CacheLine != NULL) + { + if (NULL != CacheLine->Key) + { + DPRINT("Line with key %S\n", CacheLine->Key); + Output(&OutBuf, CacheLine->Key); + Output(&OutBuf, L" = "); + } + else + { + DPRINT("Line without key\n"); + } + + /* Iterate through list of lines */ + CacheField = CacheLine->FirstField; + while (CacheField != NULL) + { + if (CacheField != CacheLine->FirstField) + { + Output(&OutBuf, L","); + } + p = CacheField->Data; + NeedQuotes = FALSE; + while (L'\0' != *p && ! NeedQuotes) + { + NeedQuotes = (BOOLEAN)(L',' == *p || L';' == *p || + L'\\' == *p); + p++; + } + if (NeedQuotes) + { + Output(&OutBuf, L"\""); + Output(&OutBuf, CacheField->Data); + Output(&OutBuf, L"\""); + } + else + { + Output(&OutBuf, CacheField->Data); + } + + /* Get the next field */ + CacheField = CacheField->Next; + } + + Output(&OutBuf, EOL); + /* Get the next line */ + CacheLine = CacheLine->Next; + } + + /* Get the next section */ + CacheSection = CacheSection->Next; + } + + if (INF_SUCCESS(OutBuf.Status)) + { + *Buffer = OutBuf.Buffer; + *BufferSize = OutBuf.TotalSize - OutBuf.FreeSize; + } + else if (NULL != OutBuf.Buffer) + { + FREE(OutBuf.Buffer); + } + + return INF_STATUS_SUCCESS; +} + +INFSTATUS +InfpFindOrAddSection(PINFCACHE Cache, + PCWSTR Section, + PINFCONTEXT *Context) +{ + DPRINT("InfpFindOrAddSection section %S\n", Section); + + *Context = MALLOC(sizeof(INFCONTEXT)); + if (NULL == *Context) + { + DPRINT1("MALLOC() failed\n"); + return INF_STATUS_NO_MEMORY; + } + + (*Context)->Inf = Cache; + (*Context)->Section = InfpFindSection(Cache, Section); + (*Context)->Line = NULL; + if (NULL == (*Context)->Section) + { + DPRINT("Section not found, creating it\n"); + (*Context)->Section = InfpAddSection(Cache, Section); + if (NULL == (*Context)->Section) + { + DPRINT("Failed to create section\n"); + FREE(*Context); + return INF_STATUS_NO_MEMORY; + } + } + + return INF_STATUS_SUCCESS; +} + +INFSTATUS +InfpAddLineWithKey(PINFCONTEXT Context, PCWSTR Key) +{ + if (NULL == Context) + { + DPRINT1("Invalid parameter\n"); + return INF_STATUS_INVALID_PARAMETER; + } + + Context->Line = InfpAddLine(Context->Section); + if (NULL == Context->Line) + { + DPRINT("Failed to create line\n"); + return INF_STATUS_NO_MEMORY; + } + + if (NULL != Key && NULL == InfpAddKeyToLine(Context->Line, Key)) + { + DPRINT("Failed to add key\n"); + return INF_STATUS_NO_MEMORY; + } + + return INF_STATUS_SUCCESS; +} + +INFSTATUS +InfpAddField(PINFCONTEXT Context, PCWSTR Data) +{ + if (NULL == Context || NULL == Context->Line) + { + DPRINT1("Invalid parameter\n"); + return INF_STATUS_INVALID_PARAMETER; + } + + if (NULL == InfpAddFieldToLine(Context->Line, Data)) + { + DPRINT("Failed to add field\n"); + return INF_STATUS_NO_MEMORY; + } + + return INF_STATUS_SUCCESS; +} + +/* EOF */ diff --git a/reactos/lib/newinflib/infros.h b/reactos/lib/newinflib/infros.h new file mode 100644 index 00000000000..c467af9f3fb --- /dev/null +++ b/reactos/lib/newinflib/infros.h @@ -0,0 +1,81 @@ +/* + * PROJECT: .inf file parser + * LICENSE: GPL - See COPYING in the top level directory + * PROGRAMMER: Royce Mitchell III + * Eric Kohl + * Ge van Geldorp + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include + +extern VOID InfSetHeap(PVOID Heap); +extern NTSTATUS InfOpenBufferedFile(PHINF InfHandle, + PVOID Buffer, + ULONG BufferSize, + LCID LocaleId, + PULONG ErrorLine); +extern NTSTATUS InfOpenFile(PHINF InfHandle, + PUNICODE_STRING FileName, + LCID LocaleId, + PULONG ErrorLine); +extern NTSTATUS InfWriteFile(HINF InfHandle, + PUNICODE_STRING FileName, + PUNICODE_STRING HeaderComment); +extern VOID InfCloseFile(HINF InfHandle); +extern BOOLEAN InfFindFirstLine(HINF InfHandle, + PCWSTR Section, + PCWSTR Key, + PINFCONTEXT *Context); +extern BOOLEAN InfFindNextLine(PINFCONTEXT ContextIn, + PINFCONTEXT ContextOut); +extern BOOLEAN InfFindFirstMatchLine(PINFCONTEXT ContextIn, + PCWSTR Key, + PINFCONTEXT ContextOut); +extern BOOLEAN InfFindNextMatchLine(PINFCONTEXT ContextIn, + PCWSTR Key, + PINFCONTEXT ContextOut); +extern LONG InfGetLineCount(HINF InfHandle, + PCWSTR Section); +extern LONG InfGetFieldCount(PINFCONTEXT Context); +extern BOOLEAN InfGetBinaryField(PINFCONTEXT Context, + ULONG FieldIndex, + PUCHAR ReturnBuffer, + ULONG ReturnBufferSize, + PULONG RequiredSize); +extern BOOLEAN InfGetIntField(PINFCONTEXT Context, + ULONG FieldIndex, + PLONG IntegerValue); +extern BOOLEAN InfGetMultiSzField(PINFCONTEXT Context, + ULONG FieldIndex, + PWSTR ReturnBuffer, + ULONG ReturnBufferSize, + PULONG RequiredSize); +extern BOOLEAN InfGetStringField(PINFCONTEXT Context, + ULONG FieldIndex, + PWSTR ReturnBuffer, + ULONG ReturnBufferSize, + PULONG RequiredSize); +extern BOOLEAN InfGetData(PINFCONTEXT Context, + PWCHAR *Key, + PWCHAR *Data); +extern BOOLEAN InfGetDataField(PINFCONTEXT Context, + ULONG FieldIndex, + PWCHAR *Data); +extern BOOLEAN InfFindOrAddSection(HINF InfHandle, + PCWSTR Section, + PINFCONTEXT *Context); +extern BOOLEAN InfAddLine(PINFCONTEXT Context, PCWSTR Key); +extern BOOLEAN InfAddField(PINFCONTEXT Context, PCWSTR Data); +extern VOID InfFreeContext(PINFCONTEXT Context); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +/* EOF */ diff --git a/reactos/lib/newinflib/infrosgen.c b/reactos/lib/newinflib/infrosgen.c new file mode 100644 index 00000000000..8ea53ae58d2 --- /dev/null +++ b/reactos/lib/newinflib/infrosgen.c @@ -0,0 +1,370 @@ +/* + * PROJECT: .inf file parser + * LICENSE: GPL - See COPYING in the top level directory + * PROGRAMMER: Royce Mitchell III + * Eric Kohl + * Ge van Geldorp + */ + +/* INCLUDES *****************************************************************/ + +#include "inflib.h" +#include "infros.h" + +#define NDEBUG +#include + +/* PRIVATE FUNCTIONS ********************************************************/ + +static int InfpHeapRefCount; + +static VOID +CheckHeap() +{ + if (NULL == InfpHeap) + { + InfpHeap = RtlCreateHeap(HEAP_GROWABLE, NULL, 0, 0, NULL, NULL); + } + if (0 <= InfpHeapRefCount) + { + InfpHeapRefCount++; + } +} + + +/* PUBLIC FUNCTIONS *********************************************************/ + +PVOID InfpHeap; + +VOID +InfSetHeap(PVOID Heap) +{ + if (NULL == InfpHeap) + { + InfpHeap = Heap; + InfpHeapRefCount = -1; + } +} + + +NTSTATUS +InfOpenBufferedFile(PHINF InfHandle, + PVOID Buffer, + ULONG BufferSize, + LCID LocaleId, + PULONG ErrorLine) +{ + INFSTATUS Status; + PINFCACHE Cache; + PCHAR FileBuffer; + ULONG FileBufferSize; + + CheckHeap(); + + *InfHandle = NULL; + *ErrorLine = (ULONG)-1; + + /* Allocate file buffer */ + FileBufferSize = BufferSize + 2; + FileBuffer = MALLOC(FileBufferSize); + if (FileBuffer == NULL) + { + DPRINT1("MALLOC() failed\n"); + return(INF_STATUS_INSUFFICIENT_RESOURCES); + } + + MEMCPY(FileBuffer, Buffer, BufferSize); + + /* Append string terminator */ + FileBuffer[BufferSize] = 0; + FileBuffer[BufferSize + 1] = 0; + + /* Allocate infcache header */ + Cache = (PINFCACHE)MALLOC(sizeof(INFCACHE)); + if (Cache == NULL) + { + DPRINT("MALLOC() failed\n"); + FREE(FileBuffer); + return(INF_STATUS_INSUFFICIENT_RESOURCES); + } + + /* Initialize inicache header */ + ZEROMEMORY(Cache, + sizeof(INFCACHE)); + + Cache->LocaleId = LocaleId; + + if (!RtlIsTextUnicode(FileBuffer, FileBufferSize, NULL)) + { +// static const BYTE utf8_bom[3] = { 0xef, 0xbb, 0xbf }; + WCHAR *new_buff; +// UINT codepage = CP_ACP; + UINT offset = 0; + +// if (BufferSize > sizeof(utf8_bom) && !memcmp(FileBuffer, utf8_bom, sizeof(utf8_bom) )) +// { +// codepage = CP_UTF8; +// offset = sizeof(utf8_bom); +// } + + new_buff = MALLOC(FileBufferSize * sizeof(WCHAR)); + if (new_buff != NULL) + { +// DWORD len = MultiByteToWideChar( codepage, 0, (char *)FileBuffer + offset, +// FileBufferSize - offset, new_buff, FileBufferSize); + + ULONG len; + Status = RtlMultiByteToUnicodeN(new_buff, + FileBufferSize * sizeof(WCHAR), + &len, + (char *)FileBuffer + offset, + FileBufferSize - offset); + + Status = InfpParseBuffer(Cache, + new_buff, + new_buff + len, + ErrorLine); + FREE(new_buff); + } + else + Status = INF_STATUS_INSUFFICIENT_RESOURCES; + } + else + { + WCHAR *new_buff = (WCHAR *)FileBuffer; + /* UCS-16 files should start with the Unicode BOM; we should skip it */ + if (*new_buff == 0xfeff) + { + new_buff++; + FileBufferSize -= sizeof(WCHAR); + } + Status = InfpParseBuffer(Cache, + new_buff, + (WCHAR*)((char*)new_buff + FileBufferSize), + ErrorLine); + } + + if (!INF_SUCCESS(Status)) + { + FREE(Cache); + Cache = NULL; + } + + /* Free file buffer */ + FREE(FileBuffer); + + *InfHandle = (HINF)Cache; + + return(Status); +} + + +NTSTATUS +InfOpenFile(PHINF InfHandle, + PUNICODE_STRING FileName, + LCID LocaleId, + PULONG ErrorLine) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + FILE_STANDARD_INFORMATION FileInfo; + IO_STATUS_BLOCK IoStatusBlock; + HANDLE FileHandle; + NTSTATUS Status; + PCHAR FileBuffer; + ULONG FileLength; + ULONG FileBufferLength; + LARGE_INTEGER FileOffset; + PINFCACHE Cache; + + CheckHeap(); + + *InfHandle = NULL; + *ErrorLine = (ULONG)-1; + + /* Open the inf file */ + InitializeObjectAttributes(&ObjectAttributes, + FileName, + 0, + NULL, + NULL); + + Status = NtOpenFile(&FileHandle, + GENERIC_READ | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE); + if (!INF_SUCCESS(Status)) + { + DPRINT("NtOpenFile() failed (Status %lx)\n", Status); + return(Status); + } + + DPRINT("NtOpenFile() successful\n"); + + /* Query file size */ + Status = NtQueryInformationFile(FileHandle, + &IoStatusBlock, + &FileInfo, + sizeof(FILE_STANDARD_INFORMATION), + FileStandardInformation); + if (!INF_SUCCESS(Status)) + { + DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status); + NtClose(FileHandle); + return(Status); + } + + FileLength = FileInfo.EndOfFile.u.LowPart; + + DPRINT("File size: %lu\n", FileLength); + + /* Allocate file buffer */ + FileBufferLength = FileLength + 2; + FileBuffer = MALLOC(FileBufferLength); + if (FileBuffer == NULL) + { + DPRINT1("MALLOC() failed\n"); + NtClose(FileHandle); + return(INF_STATUS_INSUFFICIENT_RESOURCES); + } + + /* Read file */ + FileOffset.QuadPart = 0ULL; + Status = NtReadFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + FileBuffer, + FileLength, + &FileOffset, + NULL); + + /* Append string terminator */ + FileBuffer[FileLength] = 0; + FileBuffer[FileLength + 1] = 0; + + NtClose(FileHandle); + + if (!INF_SUCCESS(Status)) + { + DPRINT("NtReadFile() failed (Status %lx)\n", Status); + FREE(FileBuffer); + return(Status); + } + + /* Allocate infcache header */ + Cache = (PINFCACHE)MALLOC(sizeof(INFCACHE)); + if (Cache == NULL) + { + DPRINT("MALLOC() failed\n"); + FREE(FileBuffer); + return(INF_STATUS_INSUFFICIENT_RESOURCES); + } + + /* Initialize inicache header */ + ZEROMEMORY(Cache, + sizeof(INFCACHE)); + + Cache->LocaleId = LocaleId; + + /* Parse the inf buffer */ + if (!RtlIsTextUnicode(FileBuffer, FileBufferLength, NULL)) + { +// static const BYTE utf8_bom[3] = { 0xef, 0xbb, 0xbf }; + WCHAR *new_buff; +// UINT codepage = CP_ACP; + UINT offset = 0; + +// if (FileLength > sizeof(utf8_bom) && !memcmp(FileBuffer, utf8_bom, sizeof(utf8_bom) )) +// { +// codepage = CP_UTF8; +// offset = sizeof(utf8_bom); +// } + + new_buff = MALLOC(FileBufferLength * sizeof(WCHAR)); + if (new_buff != NULL) + { +// DWORD len = MultiByteToWideChar( codepage, 0, (char *)FileBuffer + offset, +// FileLength - offset, new_buff, FileLength); + + ULONG len; + Status = RtlMultiByteToUnicodeN(new_buff, + FileBufferLength * sizeof(WCHAR), + &len, + (char *)FileBuffer + offset, + FileBufferLength - offset); + + Status = InfpParseBuffer(Cache, + new_buff, + new_buff + len, + ErrorLine); + FREE(new_buff); + } + else + Status = INF_STATUS_INSUFFICIENT_RESOURCES; + } + else + { + WCHAR *new_buff = (WCHAR *)FileBuffer; + /* UCS-16 files should start with the Unicode BOM; we should skip it */ + if (*new_buff == 0xfeff) + { + new_buff++; + FileBufferLength -= sizeof(WCHAR); + } + Status = InfpParseBuffer(Cache, + new_buff, + (WCHAR*)((char*)new_buff + FileBufferLength), + ErrorLine); + } + + if (!INF_SUCCESS(Status)) + { + FREE(Cache); + Cache = NULL; + } + + /* Free file buffer */ + FREE(FileBuffer); + + *InfHandle = (HINF)Cache; + + return(Status); +} + + +VOID +InfCloseFile(HINF InfHandle) +{ + PINFCACHE Cache; + + Cache = (PINFCACHE)InfHandle; + + if (Cache == NULL) + { + return; + } + + while (Cache->FirstSection != NULL) + { + Cache->FirstSection = InfpFreeSection(Cache->FirstSection); + } + Cache->LastSection = NULL; + + FREE(Cache); + + if (0 < InfpHeapRefCount) + { + InfpHeapRefCount--; + if (0 == InfpHeapRefCount) + { + RtlDestroyHeap(InfpHeap); + InfpHeap = NULL; + } + } +} + + +/* EOF */ diff --git a/reactos/lib/newinflib/infrosget.c b/reactos/lib/newinflib/infrosget.c new file mode 100644 index 00000000000..9f3e7b06abf --- /dev/null +++ b/reactos/lib/newinflib/infrosget.c @@ -0,0 +1,140 @@ +/* + * PROJECT: .inf file parser + * LICENSE: GPL - See COPYING in the top level directory + * PROGRAMMER: Royce Mitchell III + * Eric Kohl + * Ge van Geldorp + */ + +/* INCLUDES *****************************************************************/ + +#include "inflib.h" +#include "infros.h" + +#define NDEBUG +#include + + +BOOLEAN +InfFindFirstLine(HINF InfHandle, + PCWSTR Section, + PCWSTR Key, + PINFCONTEXT *Context) +{ + return INF_SUCCESS(InfpFindFirstLine(InfHandle, Section, Key, Context)); +} + + +BOOLEAN +InfFindNextLine(PINFCONTEXT ContextIn, + PINFCONTEXT ContextOut) +{ + return INF_SUCCESS(InfpFindNextLine(ContextIn, ContextOut)); +} + + +BOOLEAN +InfFindFirstMatchLine(PINFCONTEXT ContextIn, + PCWSTR Key, + PINFCONTEXT ContextOut) +{ + return INF_SUCCESS(InfpFindFirstMatchLine(ContextIn, Key, ContextOut)); +} + + +BOOLEAN +InfFindNextMatchLine(PINFCONTEXT ContextIn, + PCWSTR Key, + PINFCONTEXT ContextOut) +{ + return INF_SUCCESS(InfpFindNextMatchLine(ContextIn, Key, ContextOut)); +} + + +LONG +InfGetLineCount(HINF InfHandle, + PCWSTR Section) +{ + return InfpGetLineCount(InfHandle, Section); +} + + +/* InfGetLineText */ + + +LONG +InfGetFieldCount(PINFCONTEXT Context) +{ + return InfpGetFieldCount(Context); +} + + +BOOLEAN +InfGetBinaryField(PINFCONTEXT Context, + ULONG FieldIndex, + PUCHAR ReturnBuffer, + ULONG ReturnBufferSize, + PULONG RequiredSize) +{ + return INF_SUCCESS(InfpGetBinaryField(Context, FieldIndex, ReturnBuffer, + ReturnBufferSize, RequiredSize)); +} + + +BOOLEAN +InfGetIntField(PINFCONTEXT Context, + ULONG FieldIndex, + PLONG IntegerValue) +{ + return INF_SUCCESS(InfpGetIntField(Context, FieldIndex, IntegerValue)); +} + + +BOOLEAN +InfGetMultiSzField(PINFCONTEXT Context, + ULONG FieldIndex, + PWSTR ReturnBuffer, + ULONG ReturnBufferSize, + PULONG RequiredSize) +{ + return INF_SUCCESS(InfpGetMultiSzField(Context, FieldIndex, ReturnBuffer, + ReturnBufferSize, RequiredSize)); +} + + +BOOLEAN +InfGetStringField(PINFCONTEXT Context, + ULONG FieldIndex, + PWSTR ReturnBuffer, + ULONG ReturnBufferSize, + PULONG RequiredSize) +{ + return INF_SUCCESS(InfpGetStringField(Context, FieldIndex, ReturnBuffer, + ReturnBufferSize, RequiredSize)); +} + + +BOOLEAN +InfGetData(PINFCONTEXT Context, + PWCHAR *Key, + PWCHAR *Data) +{ + return INF_SUCCESS(InfpGetData(Context, Key, Data)); +} + + +BOOLEAN +InfGetDataField (PINFCONTEXT Context, + ULONG FieldIndex, + PWCHAR *Data) +{ + return INF_SUCCESS(InfpGetDataField(Context, FieldIndex, Data)); +} + +VOID +InfFreeContext(PINFCONTEXT Context) +{ + InfpFreeContext(Context); +} + +/* EOF */ diff --git a/reactos/lib/newinflib/infrosput.c b/reactos/lib/newinflib/infrosput.c new file mode 100644 index 00000000000..4c6ca5a3bca --- /dev/null +++ b/reactos/lib/newinflib/infrosput.c @@ -0,0 +1,132 @@ +/* + * PROJECT: .inf file parser + * LICENSE: GPL - See COPYING in the top level directory + * COPYRIGHT: Copyright 2005 Ge van Geldorp + */ + +/* INCLUDES *****************************************************************/ + +#include "inflib.h" +#include "infros.h" + +#define NDEBUG +#include + +NTSTATUS +InfWriteFile(HINF InfHandle, + PUNICODE_STRING FileName, + PUNICODE_STRING HeaderComment) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + HANDLE FileHandle; + NTSTATUS Status; + INFSTATUS InfStatus; + PWCHAR Buffer; + ULONG BufferSize; + PWCHAR HeaderBuffer; + ULONG HeaderBufferSize; + UINT Index; + + InfStatus = InfpBuildFileBuffer((PINFCACHE) InfHandle, &Buffer, &BufferSize); + if (! INF_SUCCESS(InfStatus)) + { + DPRINT("Failed to create buffer (Status 0x%lx)\n", InfStatus); + return InfStatus; + } + + /* Open the inf file */ + InitializeObjectAttributes(&ObjectAttributes, + FileName, + 0, + NULL, + NULL); + + Status = NtOpenFile(&FileHandle, + GENERIC_WRITE | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + 0, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE); + if (!INF_SUCCESS(Status)) + { + DPRINT1("NtOpenFile() failed (Status %lx)\n", Status); + FREE(Buffer); + return Status; + } + + DPRINT("NtOpenFile() successful\n"); + + if (NULL != HeaderComment && 0 != HeaderComment->Length) + { + /* This is just a comment header, don't abort on errors here */ + HeaderBufferSize = HeaderComment->Length + 7 * sizeof(WCHAR); + HeaderBuffer = MALLOC(HeaderBufferSize); + if (NULL != HeaderBuffer) + { + wcscpy(HeaderBuffer, L"; "); + for (Index = 0; Index < HeaderComment->Length / sizeof(WCHAR); Index++) + { + HeaderBuffer[2 + Index] = HeaderComment->Buffer[Index]; + } + wcscpy(HeaderBuffer + (2 + HeaderComment->Length / sizeof(WCHAR)), + L"\r\n\r\n"); + NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + HeaderBuffer, + HeaderBufferSize, + NULL, + NULL); + FREE(HeaderBuffer); + } + } + + /* Write main contents */ + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + Buffer, + BufferSize, + NULL, + NULL); + + NtClose(FileHandle); + FREE(Buffer); + + if (!INF_SUCCESS(Status)) + { + DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); + FREE(Buffer); + return(Status); + } + + return STATUS_SUCCESS; +} + +BOOLEAN +InfFindOrAddSection(HINF InfHandle, + PCWSTR Section, + PINFCONTEXT *Context) +{ + return INF_SUCCESS(InfpFindOrAddSection((PINFCACHE) InfHandle, + Section, Context)); +} + +BOOLEAN +InfHostAddLine(PINFCONTEXT Context, PCWSTR Key) +{ + return INF_SUCCESS(InfpAddLineWithKey(Context, Key)); +} + +BOOLEAN +InfHostAddField(PINFCONTEXT Context, PCWSTR Data) +{ + return INF_SUCCESS(InfpAddField(Context, Data)); +} + +/* EOF */