📄 inffile.c
字号:
/*
* ReactOS kernel
* Copyright (C) 2002,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: inffile.c 21339 2006-03-18 22:09:16Z peterw $
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS text-mode setup
* FILE: subsys/system/usetup/infcache.c
* PURPOSE: INF file parser that caches contents of INF file in memory
* PROGRAMMER: Royce Mitchell III
* Eric Kohl
*/
/* INCLUDES *****************************************************************/
#include <freeldr.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;
ULONG 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)
{
MmFreeMemory (Line->Key);
Line->Key = NULL;
}
/* Remove data fields */
while (Line->FirstField != NULL)
{
Field = Line->FirstField->Next;
MmFreeMemory (Line->FirstField);
Line->FirstField = Field;
}
Line->LastField = NULL;
MmFreeMemory (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;
MmFreeMemory (Section);
return Next;
}
static PINFCACHESECTION
InfpCacheFindSection (PINFCACHE Cache,
PCSTR 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)MmAllocateMemory (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)MmAllocateMemory (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)MmAllocateMemory (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)MmAllocateMemory (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,
PCSTR 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 == '\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 CHAR *pos )
{
unsigned 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 ? (CHAR)*src : L' ';
*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 = FALSE;
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 = FALSE;
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 = STATUS_WRONG_INF_STYLE;
return NULL;
}
parser->line = InfpCacheAddLine (parser->cur_section);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -