|
|
//depot/Lab01_N/base/ntos/config/i386/parseini.c#4 - edit change 6451 (text)
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
parseini.c
Abstract:
This modules contains routines to parse an inf file. This is based on the code from the osloader. All indices are zero based.
Author:
Santosh Jodh (santoshj) 08-Aug-1998
Environment:
Kernel mode.
Revision History:
--*/
#include "cmp.h"
#include "string.h"
#include "ctype.h"
#include "stdlib.h"
#include "parseini.h"
typedef struct _value VALUE, *PVALUE; typedef struct _line LINE, *PLINE; typedef struct _section SECTION, *PSECTION; typedef struct _inf INF, *PINF; typedef struct _cm_token CM_TOKEN,*PCM_TOKEN; typedef enum _tokentype TOKENTYPE, *PTOKENTTYPE; typedef enum _stringsSectionType STRINGSSECTIONTYPE;;
struct _value { PVALUE pNext; PCHAR pName; BOOLEAN Allocated; };
struct _line { PLINE pNext; PCHAR pName; PVALUE pValue; BOOLEAN Allocated; };
struct _section { PSECTION pNext; PCHAR pName; PLINE pLine; BOOLEAN Allocated; };
struct _inf { PSECTION pSection; PSECTION pSectionRecord; PLINE pLineRecord; PVALUE pValueRecord; STRINGSSECTIONTYPE StringsSectionType; PSECTION StringsSection; };
//
// [Strings] section types.
//
enum _stringsSectionType { StringsSectionNone, StringsSectionPlain, StringsSectionLoosePrimaryMatch, StringsSectionExactPrimaryMatch, StringsSectionExactMatch };
enum _tokentype { TOK_EOF, TOK_EOL, TOK_LBRACE, TOK_RBRACE, TOK_STRING, TOK_EQUAL, TOK_COMMA, TOK_ERRPARSE, TOK_ERRNOMEM };
struct _cm_token { TOKENTYPE Type; PCHAR pValue; BOOLEAN Allocated; };
VOID CmpFreeValueList( IN PVALUE pValue );
VOID CmpFreeLineList( IN PLINE pLine );
VOID CmpFreeSectionList( IN PSECTION pSection );
PCHAR CmpProcessForSimpleStringSub( IN PINF pInf, IN PCHAR String );
BOOLEAN CmpAppendSection( IN PINF pInf, IN PCHAR pSectionName, IN BOOLEAN Allocated );
BOOLEAN CmpAppendLine( IN PINF pInf, IN PCHAR pLineKey, IN BOOLEAN Allocated );
BOOLEAN CmpAppendValue( IN PINF pInf, IN PCHAR pValueString, IN BOOLEAN Allocated );
VOID CmpGetToken( IN OUT PCHAR *Stream, IN PCHAR MaxStream, IN OUT PULONG LineNumber, IN OUT PCM_TOKEN Token );
PINF CmpParseInfBuffer( IN PCHAR Buffer, IN ULONG Size, IN OUT PULONG ErrorLine );
PVALUE CmpSearchValueInLine( IN PLINE pLine, IN ULONG ValueIndex );
PLINE CmpSearchLineInSectionByIndex( IN PSECTION pSection, IN ULONG LineIndex );
PSECTION CmpSearchSectionByName( IN PINF pInf, IN PCHAR SectionName );
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,CmpFreeValueList)
#pragma alloc_text(INIT,CmpFreeLineList)
#pragma alloc_text(INIT,CmpFreeSectionList)
#pragma alloc_text(INIT,CmpProcessForSimpleStringSub)
#pragma alloc_text(INIT,CmpAppendSection)
#pragma alloc_text(INIT,CmpAppendLine)
#pragma alloc_text(INIT,CmpAppendValue)
#pragma alloc_text(INIT,CmpGetToken)
#pragma alloc_text(INIT,CmpParseInfBuffer)
#pragma alloc_text(INIT,CmpSearchValueInLine)
#pragma alloc_text(INIT,CmpSearchLineInSectionByIndex)
#pragma alloc_text(INIT,CmpSearchSectionByName)
#pragma alloc_text(INIT,CmpSearchInfLine)
#pragma alloc_text(INIT,CmpOpenInfFile)
#pragma alloc_text(INIT,CmpCloseInfFile)
#pragma alloc_text(INIT,CmpGetKeyName)
#pragma alloc_text(INIT,CmpSearchInfSection)
#pragma alloc_text(INIT,CmpGetSectionLineIndex)
#pragma alloc_text(INIT,CmpGetSectionLineIndexValueCount)
#pragma alloc_text(INIT,CmpGetIntField)
#pragma alloc_text(INIT,CmpGetBinaryField)
#endif
//
// Globals used by the token parser.
// String terminators are the whitespace characters (isspace: space, tab,
// linefeed, formfeed, vertical tab, carriage return) or the chars given below.
//
#ifdef ALLOC_DATA_PRAGMA
#pragma const_seg("INITCONST")
#endif
const CHAR StringTerminators[] = "[]=,\t \"\n\f\v\r"; CHAR const* const QStringTerminators = StringTerminators + 6; const CHAR EmptyValue[] = ""; const CHAR DblSpaceSection[] = "DBLSPACE_SECTION";
BOOLEAN CmpAppendSection( IN PINF pInf, IN PCHAR pSectionName, IN BOOLEAN Allocated )
/*++
Routine Description:
This routine creates a new section or merges with an existing section in the inf.
Input Parameters:
pInf - Pointer to the inf to be processed.
pSectionName - Name of the section.
Allocated - TRUE if memory was allocated for the section name.
Return Value:
TRUE iff successful.
--*/
{ PSECTION pNewSection; PLINE pLineRecord; STRINGSSECTIONTYPE type; USHORT id; USHORT threadLang; PCHAR p;
//
// Check to see if INF initialised and the parameters passed in is valid
//
if ( pInf == (PINF)NULL || pSectionName == (PCHAR)NULL) { return (FALSE); }
//
// See if we already have a section by this name. If so we want
// to merge sections.
//
for( pNewSection = pInf->pSection; pNewSection; pNewSection = pNewSection->pNext) { if(pNewSection->pName && _stricmp(pNewSection->pName,pSectionName) == 0) { break; } }
if(pNewSection) { //
// Set pLineRecord to point to the last line currently in the section.
//
for( pLineRecord = pNewSection->pLine; pLineRecord && pLineRecord->pNext; pLineRecord = pLineRecord->pNext);
pInf->pLineRecord = pLineRecord; } else { //
// Allocate memory for the new section
//
pNewSection = (PSECTION)ExAllocatePoolWithTag(PagedPool, sizeof(SECTION), CM_PARSEINI_TAG);
if (pNewSection == (PSECTION)NULL) { ASSERT(pNewSection); return (FALSE); }
//
// Initialize the new section.
//
pNewSection->pNext = NULL; pNewSection->pLine = NULL; pNewSection->pName = pSectionName; pNewSection->Allocated = Allocated;
//
// Link it in.
//
pNewSection->pNext = pInf->pSection; pInf->pSection = pNewSection;
if(_strnicmp(pSectionName, "Strings", 7) == 0) { type = StringsSectionNone;
if(pSectionName[7] == '.') { //
// The langid part must be in the form of 4 hex digits.
//
id = (USHORT)strtoul(pSectionName + 8, &p, 16); if(p == (pSectionName + 8 + 5) && *p == '\0') { threadLang = LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale);
if(threadLang == id) { type = StringsSectionExactMatch; } else { if(id == PRIMARYLANGID(threadLang)) { type = StringsSectionExactPrimaryMatch; } else { if(PRIMARYLANGID(id) == PRIMARYLANGID(threadLang)) { type = StringsSectionLoosePrimaryMatch; } } } } } else { if(!pSectionName[7]) { type = StringsSectionPlain; } }
if(type > pInf->StringsSectionType) { pInf->StringsSection = pNewSection; } }
//
// Reset the current line record.
//
pInf->pLineRecord = NULL; }
pInf->pSectionRecord = pNewSection; pInf->pValueRecord = NULL;
return (TRUE); }
BOOLEAN CmpAppendLine( IN PINF pInf, IN PCHAR pLineKey, IN BOOLEAN Allocated )
/*++
Routine Description:
This routine creates a new line and appends it to the end of the line list.
Input Parameters:
pInf - Pointer to the inf to be processed.
pLineKey - Name of the line.
Allocated - TRUE if memory was allocated for the line name.
Return Value:
TRUE iff successful.
--*/
{ PLINE pNewLine;
//
// Check to see if current section initialized.
//
if (pInf->pSectionRecord == (PSECTION)NULL) { return (FALSE); }
//
// Allocate memory for the new Line.
//
pNewLine = (PLINE)ExAllocatePoolWithTag(PagedPool, sizeof(LINE), CM_PARSEINI_TAG); if (pNewLine == (PLINE)NULL) { ASSERT(pNewLine); return (FALSE); }
//
// Link it in.
//
pNewLine->pNext = (PLINE)NULL; pNewLine->pValue = (PVALUE)NULL; pNewLine->pName = pLineKey; pNewLine->Allocated = Allocated;
if (pInf->pLineRecord == (PLINE)NULL) { pInf->pSectionRecord->pLine = pNewLine; } else { pInf->pLineRecord->pNext = pNewLine; }
pInf->pLineRecord = pNewLine;
//
// Reset the current value record
//
pInf->pValueRecord = (PVALUE)NULL;
return (TRUE); }
BOOLEAN CmpAppendValue( IN PINF pInf, IN PCHAR pValueString, IN BOOLEAN Allocated )
/*++
Routine Description:
This routine creates a new value and appends it to the end of the value list.
Input Parameters:
pInf - Pointer to the inf to be processed.
pValueString - Name of the value.
Allocated - TRUE if memory was allocated for the value name.
Return Value:
TRUE iff successful.
--*/
{ PVALUE pNewValue;
//
// Check to see if current line record has been initialised and
// the parameter passed in is valid.
//
if ( pInf->pLineRecord == (PLINE)NULL || pValueString == (PCHAR)NULL) { return (FALSE); }
//
// Allocate memory for the new value record.
//
pNewValue = (PVALUE)ExAllocatePoolWithTag(PagedPool, sizeof(VALUE), CM_PARSEINI_TAG);
if (pNewValue == (PVALUE)NULL) { ASSERT(pNewValue); return (FALSE); }
//
// Link it in.
//
pNewValue->pNext = (PVALUE)NULL; pNewValue->pName = pValueString; pNewValue->Allocated = Allocated;
if (pInf->pValueRecord == (PVALUE)NULL) { pInf->pLineRecord->pValue = pNewValue; } else { pInf->pValueRecord->pNext = pNewValue; }
pInf->pValueRecord = pNewValue;
return (TRUE); }
VOID CmpGetToken( IN OUT PCHAR *Stream, IN PCHAR MaxStream, IN OUT PULONG LineNumber, IN OUT PCM_TOKEN Token )
/*++
Routine Description:
This function returns the Next token from the configuration stream.
Arguments:
Stream - Supplies the address of the configuration stream. Returns the address of where to start looking for tokens within the stream.
MaxStream - Supplies the address of the last character in the stream.
Return Value:
None.
--*/
{
PCHAR pch; PCHAR pchStart; PCHAR pchNew; ULONG length; BOOLEAN done;
Token->Allocated = FALSE; Token->pValue = NULL;
do { done = TRUE;
//
// Skip whitespace (except for EOL).
//
for ( pch = *Stream; pch < MaxStream && *pch != '\n' && isspace(*pch); pch++);
//
// Check for comments and remove them.
//
if ( pch < MaxStream && (*pch == '#' || *pch == ';')) { while (pch < MaxStream && *pch != '\n') { pch++; } }
//
// Check to see if EOF has been reached, set the token to the right
// value.
//
if (pch >= MaxStream || *pch == 26) { *Stream = pch; Token->Type = TOK_EOF; Token->pValue = NULL;
return; }
switch (*pch) { case '[':
pch++; Token->Type = TOK_LBRACE; break;
case ']':
pch++; Token->Type = TOK_RBRACE; break;
case '=':
pch++; Token->Type = TOK_EQUAL; break;
case ',':
pch++; Token->Type = TOK_COMMA; break;
case '\n':
pch++; Token->Type = TOK_EOL; break;
case '\"':
pch++;
//
// Determine quoted string.
//
for ( pchStart = pch; pch < MaxStream && (strchr(QStringTerminators, *pch) == NULL); pch++);
if (pch >= MaxStream || *pch != '\"') { Token->Type = TOK_ERRPARSE; } else {
//
// We require a quoted string to end with a double-quote.
// (If the string ended with anything else, the if() above
// would not have let us into the else clause.) The quote
// character is irrelevent, however, and can be overwritten.
// So we'll save some heap and use the string in-place.
// No need to make a copy.
//
// Note that this alters the image of txtsetup.sif we pass
// to setupdd.sys. Thus the inf parser in setupdd.sys must
// be able to treat a nul character as if it were a terminating
// double quote.
//
*pch++ = '\0'; Token->Type = TOK_STRING; Token->pValue = pchStart; } break;
case '\\':
for ( pchNew = ++pch; pchNew < MaxStream && *pchNew != '\n' && isspace(*pchNew); pchNew++);
if (*pchNew == '\n') { pch = pchNew + 1; done = FALSE; break; }
default:
//
// Determine regular string.
//
for ( pchStart = pch; pch < MaxStream && (strchr(StringTerminators, *pch) == NULL); pch++);
if (pch == pchStart) { pch++; Token->Type = TOK_ERRPARSE; } else { length = (ULONG)(pch - pchStart); pchNew = ExAllocatePoolWithTag(PagedPool, length + 1, CM_PARSEINI_TAG); if (pchNew == NULL) { ASSERT(pchNew); Token->Type = TOK_ERRNOMEM; } else { strncpy(pchNew, pchStart, length); pchNew[length] = 0; Token->Type = TOK_STRING; Token->pValue = pchNew; Token->Allocated = TRUE; } } break; }
*Stream = pch; } while (!done);
return; }
PINF CmpParseInfBuffer( IN PCHAR Buffer, IN ULONG Size, IN OUT PULONG ErrorLine )
/*++
Routine Description:
Given a character buffer containing the INF file, this routine parses the INF into an internal form with Section records, Line records and Value records.
Arguments:
Buffer - contains to ptr to a buffer containing the INF file
Size - contains the size of the buffer.
ErrorLine - if a parse error occurs, this variable receives the line number of the line containing the error.
Return Value:
PVOID - INF handle ptr to be used in subsequent INF calls.
--*/
{ PINF pInf; ULONG state; PCHAR stream; PCHAR maxStream; PCHAR pchSectionName; PCHAR pchValue; CM_TOKEN token; BOOLEAN done; BOOLEAN error; ULONG infLine; BOOLEAN allocated;
//
// Allocate memory for the INF record.
//
pInf = (PINF)ExAllocatePoolWithTag(PagedPool, sizeof(INF), CM_PARSEINI_TAG);
if (pInf == NULL) { ASSERT(pInf); return (pInf); }
pInf->pSection = NULL; pInf->pSectionRecord = NULL; pInf->pLineRecord = NULL; pInf->pValueRecord = NULL; pInf->StringsSectionType = StringsSectionNone; pInf->StringsSection = NULL;
//
// Set initial state.
//
state = 1; stream = Buffer; maxStream = Buffer + Size; pchSectionName = NULL; pchValue = NULL; done = FALSE; error = FALSE; infLine = 1;
//
// Enter token processing loop.
//
while (!done) {
CmpGetToken(&stream, maxStream, &infLine, &token);
switch (state) { //
// STATE1: Start of file, this state remains till first
// section is found
// Valid Tokens: TOK_EOL, TOK_EOF, TOK_LBRACE
// TOK_STRING when reading Dblspace.inf
//
case 1:
switch (token.Type) { case TOK_EOL:
break;
case TOK_EOF:
done = TRUE;
break;
case TOK_LBRACE:
state = 2;
break;
case TOK_STRING:
pchSectionName = ExAllocatePoolWithTag(PagedPool, sizeof(DblSpaceSection), CM_PARSEINI_TAG); if (pchSectionName) { strcpy(pchSectionName, DblSpaceSection); pchValue = token.pValue; allocated = TRUE; token.Allocated = TRUE; if (CmpAppendSection(pInf, pchSectionName, TRUE)) { pchSectionName = NULL; state = 6; } else { error = done = TRUE; } } else { ASSERT(pchSectionName); error = done = TRUE; }
break;
default:
error = done = TRUE;
break; }
break;
//
// STATE 2: Section LBRACE has been received, expecting STRING
//
// Valid Tokens: TOK_STRING, TOK_RBRACE
//
case 2:
switch (token.Type) { case TOK_STRING:
state = 3; pchSectionName = token.pValue; allocated = token.Allocated;
break;
case TOK_RBRACE:
token.pValue = (PCHAR)EmptyValue; token.Allocated = FALSE; allocated = FALSE; state = 4;
break;
default:
error = done = TRUE;
break;
}
break;
//
// STATE 3: Section Name received, expecting RBRACE
//
// Valid Tokens: TOK_RBRACE
//
case 3:
switch (token.Type) { case TOK_RBRACE:
state = 4;
break;
default:
error = done = TRUE;
break; }
break;
//
// STATE 4: Section Definition Complete, expecting EOL
//
// Valid Tokens: TOK_EOL, TOK_EOF
//
case 4:
switch (token.Type) {
case TOK_EOL:
if (!CmpAppendSection(pInf, pchSectionName, allocated)) {
error = done = TRUE; } else { pchSectionName = NULL; state = 5; }
break;
case TOK_EOF:
if (!CmpAppendSection(pInf, pchSectionName, allocated)) { error = done = TRUE; } else { pchSectionName = NULL; done = TRUE; }
break;
default:
error = done = TRUE;
break; }
break;
//
// STATE 5: Expecting Section Lines
//
// Valid Tokens: TOK_EOL, TOK_EOF, TOK_STRING, TOK_LBRACE
//
case 5:
switch (token.Type) { case TOK_EOL:
break;
case TOK_EOF:
done = TRUE;
break;
case TOK_STRING:
pchValue = token.pValue; allocated = token.Allocated; state = 6;
break;
case TOK_LBRACE:
state = 2;
break;
default:
error = done = TRUE;
break; }
break;
//
// STATE 6: String returned, not sure whether it is key or value
//
// Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA, TOK_EQUAL
//
case 6:
switch (token.Type) {
case TOK_EOL:
if ( !CmpAppendLine(pInf, NULL, FALSE) || !CmpAppendValue(pInf, pchValue, allocated)) { error = done = TRUE; } else { pchValue = NULL; state = 5; }
break;
case TOK_EOF:
if ( !CmpAppendLine(pInf, NULL, FALSE) || !CmpAppendValue(pInf, pchValue, allocated)) { error = done = TRUE; } else { pchValue = NULL; done = TRUE; }
break;
case TOK_COMMA:
if ( !CmpAppendLine(pInf, NULL, FALSE) || !CmpAppendValue(pInf, pchValue, allocated)) { error = done = TRUE; } else { pchValue = NULL; state = 7; }
break;
case TOK_EQUAL:
if (!CmpAppendLine(pInf, pchValue, allocated)) { error = done = TRUE; } else { pchValue = NULL; state = 8; }
break;
default:
error = done = TRUE;
break; }
break;
//
// STATE 7: Comma received, Expecting another string
//
// Valid Tokens: TOK_STRING TOK_COMMA
// A comma means we have an empty value.
//
case 7:
switch (token.Type) {
case TOK_COMMA:
token.pValue = (PCHAR)EmptyValue; token.Allocated = FALSE; allocated = FALSE; if (!CmpAppendValue(pInf, token.pValue, FALSE)) { error = done = TRUE; }
//
// State stays at 7 because we are expecting a string
//
break;
case TOK_STRING:
if (!CmpAppendValue(pInf, token.pValue, token.Allocated)) { error = done = TRUE; } else { state = 9; }
break;
default:
error = done = TRUE;
break; }
break;
//
// STATE 8: Equal received, Expecting another string
// If none, assume there is a single empty string on the RHS
//
// Valid Tokens: TOK_STRING, TOK_EOL, TOK_EOF
//
case 8:
switch (token.Type) { case TOK_EOF:
token.pValue = (PCHAR)EmptyValue; token.Allocated = FALSE; allocated = FALSE; if(!CmpAppendValue(pInf, token.pValue, FALSE)) { error = TRUE; }
done = TRUE;
break;
case TOK_EOL:
token.pValue = (PCHAR)EmptyValue; token.Allocated = FALSE; allocated = FALSE; if(!CmpAppendValue(pInf, token.pValue, FALSE)) { error = TRUE; done = TRUE; } else { state = 5; }
break;
case TOK_STRING:
if (!CmpAppendValue(pInf, token.pValue, FALSE)) { error = done = TRUE; } else { state = 9; }
break;
default:
error = done = TRUE;
break; }
break;
//
// STATE 9: String received after equal, value string
//
// Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA
//
case 9:
switch (token.Type) { case TOK_EOL:
state = 5;
break;
case TOK_EOF:
done = TRUE;
break;
case TOK_COMMA:
state = 7;
break;
default:
error = done = TRUE;
break; }
break;
//
// STATE 10: Value string definitely received
//
// Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA
//
case 10:
switch (token.Type) { case TOK_EOL:
state =5;
break;
case TOK_EOF:
done = TRUE;
break;
case TOK_COMMA:
state = 7;
break;
default:
error = done = TRUE;
break; }
break;
default:
error = done = TRUE;
break;
} // END switch(state)
if (error) { *ErrorLine = infLine; if (pchSectionName != (PCHAR)NULL && allocated) { ExFreePool(pchSectionName); }
if (pchValue != (PCHAR)NULL && allocated) { ExFreePool(pchValue); }
ExFreePool(pInf);
pInf = (PINF)NULL; } else { //
// Keep track of line numbers for error reporting.
//
if (token.Type == TOK_EOL) { infLine++; } }
} // END while
if (pInf) { pInf->pSectionRecord = NULL; }
return(pInf); }
PCHAR CmpProcessForSimpleStringSub( IN PINF pInf, IN PCHAR String )
/*++
Routine Description:
This routine substitutes reference to string in the STRINGS section of the inf.
Input Parameters:
pInf - Pointer to the inf to be processed.
String - String to be substituted.
Return Value:
None.
--*/
{ ULONG len; PCHAR returnString; PSECTION pSection; PLINE pLine;
//
// Assume no substitution necessary.
//
returnString = String; len = strlen(String); pSection = pInf->StringsSection;
//
// If it starts and end with % then look it up in the
// strings section. Note the initial check before doing a
// wcslen, to preserve performance in the 99% case where
// there is no substitution.
//
if( String[0] == '%' && len > 2 && String[len - 1] == '%' && pSection) {
for(pLine = pSection->pLine; pLine; pLine = pLine->pNext) { if( pLine->pName && _strnicmp(pLine->pName, String + 1, len - 2) == 0 && pLine->pName[len - 2] == '\0') { break; } }
if(pLine && pLine->pValue && pLine->pValue->pName) { returnString = pLine->pValue->pName; } }
return(returnString); }
VOID CmpFreeValueList( IN PVALUE pValue )
/*++
Routine Description:
This routine releases memory for the list of values.
Input Parameters:
pValue - Pointer to the value list to be freed.
Return Value:
None.
--*/
{ PVALUE pNext;
while (pValue) { //
// Save the next pointer so we dont access memory after it has
// been freed.
//
pNext = pValue->pNext;
//
// Free any data inside this value.
//
if (pValue->Allocated && pValue->pName) { ExFreePool((PVOID)pValue->pName); }
//
// Free memory for this value.
//
ExFreePool(pValue);
//
// Go to the next value.
//
pValue = pNext; } }
VOID CmpFreeLineList( IN PLINE pLine )
/*++
Routine Description:
This routine releases memory for the list of lines and values under it.
Input Parameters:
pLine - Pointer to the line list to be freed.
Return Value:
None.
--*/
{ PLINE pNext;
while (pLine) { //
// Save the next pointer so we dont access memory after it has
// been freed.
//
pNext = pLine->pNext;
//
// Free any data inside this Line.
//
if (pLine->Allocated && pLine->pName) { ExFreePool((PVOID)pLine->pName); }
//
// Free the list of values inside this Line.
//
CmpFreeValueList(pLine->pValue);
//
// Free memory for this line itself.
//
ExFreePool((PVOID)pLine);
//
// Go to the next line.
//
pLine = pNext; } }
VOID CmpFreeSectionList( IN PSECTION pSection )
/*++
Routine Description:
This routine releases memory for the list of sections and lines under it.
Input Parameters:
pSection - Pointer to the section list to be freed.
Return Value:
None.
--*/
{ PSECTION pNext;
while (pSection) { //
// Save the next pointer so we dont access memory after it has
// been freed.
//
pNext = pSection->pNext;
//
// Free any data inside this Line.
//
if (pSection->Allocated && pSection->pName) { ExFreePool((PVOID)pSection->pName); }
//
// Free the list of values inside this Line.
//
CmpFreeLineList(pSection->pLine);
//
// Free memory for this line itself.
//
ExFreePool((PVOID)pSection);
//
// Go to the next line.
//
pSection = pNext; }
}
PVALUE CmpSearchValueInLine( IN PLINE pLine, IN ULONG ValueIndex )
/*++
Routine Description:
This routine searches for the specified value in the inf.
Input Parameters:
pLine - Pointer to the line to be searched.
ValueIndex - Index of the value to be searched.
Return Value:
Pointer to the value iff found. Else NULL.
--*/
{ ULONG i; PVALUE pValue = NULL;
if (pLine) { for ( i = 0, pValue = pLine->pValue; i < ValueIndex && pValue; i++, pValue = pValue->pNext); }
return (pValue); }
PSECTION CmpSearchSectionByName( IN PINF pInf, IN PCHAR SectionName )
/*++
Routine Description:
This routine searches for the specified section in the inf.
Input Parameters:
pInf - Pointer to the inf to be searched.
SectionName - Name of the section to be searched.
Return Value:
Pointer to the section iff found. Else NULL.
--*/
{ PSECTION pSection = NULL; PSECTION pFirstSearchedSection;
//
// Validate the parameters passed in.
//
if (pInf && SectionName) { //
// Traverse down the section list searching each section for the
// section name mentioned.
//
for ( pSection = pFirstSearchedSection = pInf->pSectionRecord; pSection && _stricmp(pSection->pName, SectionName); pSection = pSection->pNext);
//
// If we did not find the section, search from the beginning.
//
if (pSection == NULL) { for ( pSection = pInf->pSection; pSection && pSection != pFirstSearchedSection; pSection = pSection->pNext) { if (pSection->pName && _stricmp(pSection->pName, SectionName) == 0) { break; } }
if (pSection == pFirstSearchedSection) { pSection = NULL; } }
if (pSection) { pInf->pSectionRecord = pSection; } }
//
// Return the section at which we stopped.
//
return (pSection); }
PLINE CmpSearchLineInSectionByIndex( IN PSECTION pSection, IN ULONG LineIndex )
/*++
Routine Description:
This routine searches for the specified line in the inf.
Input Parameters:
pSection - Pointer to the section to be searched.
LineIndex - Index of the line to be searched.
Return Value:
Pointer to the line iff found. Else NULL.
--*/
{ PLINE pLine = NULL; ULONG i;
//
// Validate the parameters passed in.
//
if (pSection) {
//
// Traverse down the current line list to the LineIndex line.
//
for( i = 0, pLine = pSection->pLine; i < LineIndex && pLine; i++, pLine = pLine->pNext); }
//
// Return the Line found
//
return (pLine); }
PVOID CmpOpenInfFile( IN PVOID InfImage, IN ULONG ImageSize )
/*++
Routine Description:
This routine opens an handle to the inf.
Input Parameters:
InfImage - Pointer to the inf image read into memory.
ImageSize - Image size.
Return Value:
Returns handle to the inf iff successful. Else NULL.
--*/
{ PINF infHandle; ULONG errorLine = 0;
//
// Parse the inf buffer.
//
infHandle = CmpParseInfBuffer(InfImage, ImageSize, &errorLine);
if (infHandle == NULL) { #ifndef _CM_LDR_
DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Error on line %d in CmpOpenInfFile!\n", errorLine); #endif //_CM_LDR_
}
return (infHandle); }
VOID CmpCloseInfFile( PVOID InfHandle )
/*++
Routine Description:
This routine closes the inf handle by releasing any memory allocated for it during parsing.
Input Parameters:
InfHandle - Handle to the inf to be closed.
Return Value:
None.
--*/
{ if (InfHandle) { CmpFreeSectionList(((PINF)InfHandle)->pSection); ExFreePool(InfHandle); } }
BOOLEAN CmpSearchInfSection( IN PINF pInf, IN PCHAR Section )
/*++
Routine Description:
This routine searches for the specified section in the inf.
Input Parameters:
InfHandle - Handle to the inf to be read.
Section - Name of the section to be read.
Return Value:
TRUE iff section is found in the inf.
--*/
{ return (CmpSearchSectionByName(pInf, Section) != NULL); }
PCHAR CmpGetKeyName( IN PVOID InfHandle, IN PCHAR Section, IN ULONG LineIndex )
/*++
Routine Description:
This routine returns the name of the specified line in the inf.
Input Parameters:
InfHandle - Handle to the inf to be read.
Section - Name of the section to be read.
LineIndex - Index of the line to be read.
Return Value:
Pointer to the name of line in the inf iff successful. Else NULL.
--*/
{ PSECTION pSection; PLINE pLine;
//
// First search the section.
//
pSection = CmpSearchSectionByName((PINF)InfHandle, Section); if(pSection) { //
// Get the line in the section.
//
pLine = CmpSearchLineInSectionByIndex(pSection, LineIndex); if(pLine) { return(pLine->pName); } }
return (NULL); }
BOOLEAN CmpSearchInfLine( IN PVOID InfHandle, IN PCHAR Section, IN ULONG LineIndex )
/*++
Routine Description:
This routine searches for the specified line in the inf.
Input Parameters:
InfHandle - Handle to the inf to be read.
Section - Name of the section to be read.
LineIndex - Index of the line to be read.
Return Value:
TRUE iff line is found in the section in the inf.
--*/
{ PSECTION pSection; PLINE pLine = NULL;
//
// First search the section.
//
pSection = CmpSearchSectionByName((PINF)InfHandle, Section); if(pSection) { //
// Search the line in the section.
//
pLine = CmpSearchLineInSectionByIndex(pSection, LineIndex); }
return (pLine != NULL); }
PCHAR CmpGetSectionLineIndex ( IN PVOID InfHandle, IN PCHAR Section, IN ULONG LineIndex, IN ULONG ValueIndex )
/*++
Routine Description:
This routine returns the value at the specified location in the inf.
Input Parameters:
InfHandle - Handle to the inf to be read.
Section - Name of the section to be read.
LineIndex - Index of the line to be read.
ValueIndex - Index of the value to be read.
Return Value:
Pointer to the value iff successful. Else NULL.
--*/
{ PSECTION pSection; PLINE pLine; PVALUE pValue;
//
// Search the section in the inf.
//
pSection = CmpSearchSectionByName((PINF)InfHandle, Section); if(pSection) { //
// Search the line in the section.
//
pLine = CmpSearchLineInSectionByIndex(pSection, LineIndex); if(pLine) { //
// Search the value in the line.
//
pValue = CmpSearchValueInLine(pLine, ValueIndex); if(pValue) { //
// The value may need to be replaced by one of the strings
// from the string section.
//
return(CmpProcessForSimpleStringSub(InfHandle, pValue->pName)); } } }
return(NULL); }
ULONG CmpGetSectionLineIndexValueCount( IN PVOID InfHandle, IN PCHAR Section, IN ULONG LineIndex )
/*++
Routine Description:
This routine returns the number of values in the inf line.
Input Parameters:
InfHandle - Handle to the inf to be read.
Section - Name of the section to be read.
LineIndex - Index of the line to be read.
Return Value:
Number of values in the inf line.
--*/
{ PSECTION pSection; PLINE pLine; PVALUE pValue; ULONG count = 0;
//
// Search the section in the inf.
//
pSection = CmpSearchSectionByName((PINF)InfHandle, Section); if(pSection) { //
// Search the line in the section.
//
pLine = CmpSearchLineInSectionByIndex(pSection, LineIndex); if (pLine) { //
// Count the number of values in this line.
//
for( pValue = pLine->pValue; pValue; pValue = pValue->pNext, count++); } }
return (count); }
BOOLEAN CmpGetIntField( IN PVOID InfHandle, IN PCHAR Section, IN ULONG LineIndex, IN ULONG ValueIndex, IN OUT PULONG Data )
/*++
Routine Description:
This routine reads integer data from the inf.
Input Parameters:
InfHandle - Handle to the inf to be read.
Section - Name of the section to be read.
LineIndex - Index of the line to be read.
ValueIndex - Index of the value to be read.
Data - Receives the integer data.
Return Value:
TRUE iff successful.
--*/
{ PCHAR valueStr;
//
// Get the specified value.
//
valueStr = CmpGetSectionLineIndex( InfHandle, Section, LineIndex, ValueIndex); //
// If valid value is found, convert it to an integer.
//
if (valueStr && *valueStr) { *Data = strtoul(valueStr, NULL, 16); return (TRUE); }
return (FALSE); }
BOOLEAN CmpGetBinaryField( IN PVOID InfHandle, IN PCHAR Section, IN ULONG LineIndex, IN ULONG ValueIndex, IN OUT PVOID Buffer, IN ULONG BufferSize, IN OUT PULONG ActualSize )
/*++
Routine Description:
This routine reads binary data from the inf.
Input Parameters:
InfHandle - Handle to the inf to be read.
Section - Name of the section to be read.
LineIndex - Index of the line to be read.
ValueIndex - Index of the value to be read.
Buffer - Receives the binary data read.
BufferSize - Size of the buffer.
ActualSize - Receives the size of the data buffer required.
Return Value:
TRUE iff successful.
--*/
{ BOOLEAN result = FALSE; ULONG requiredSize; PSECTION pSection; PLINE pLine; PVALUE pValue; ULONG count; PCHAR valueStr;
//
// Compute the size of buffer required to read in the binary data.
//
requiredSize = (CmpGetSectionLineIndexValueCount( InfHandle, Section, LineIndex) - ValueIndex) * sizeof(UCHAR); //
// Validate input parameters.
//
if (Buffer && BufferSize >= requiredSize) { //
// Search the section in the inf.
//
pSection = CmpSearchSectionByName((PINF)InfHandle, Section); if(pSection) { //
// Search the line in this section.
//
pLine = CmpSearchLineInSectionByIndex(pSection, LineIndex); if (pLine) { //
// Go to the specified value.
//
for( pValue = pLine->pValue, count = 0; pValue && count < ValueIndex; pValue = pValue->pNext, count++);
//
// Read in and convert the binary data.
//
for ( ; pValue; pValue = pValue->pNext) { valueStr = CmpGetSectionLineIndex( InfHandle, Section, LineIndex, ValueIndex++); if (valueStr == NULL) { break; } *((PUCHAR)Buffer)++ = (UCHAR)strtoul(valueStr, NULL, 16); } if (valueStr) { result = TRUE; } } } }
//
// The caller wants to know the buffer size required.
//
if (ActualSize) { *ActualSize = requiredSize; result = TRUE; }
return (result); }
|