Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1041 lines
23 KiB

/*++
Copyright (c) 2002 Microsoft Corporation
Module Name :
parseini.cpp
Abstract:
Class used to parse the ini file
Author:
Christopher Achille (cachille)
Project:
URLScan Update
Revision History:
March 2002: Created
--*/
#include "stdafx.h"
#include "windows.h"
#include "parseini.h"
#include "stdio.h"
#include "malloc.h"
// Constructor
//
CIniFileLine::CIniFileLine()
{
m_szLine[0] = '\0';
m_szStrippedLineContents[0] = '\0';
}
// CopyLine
//
// Copy the specific line into both our buffers
//
BOOL
CIniFileLine::CopyLine(LPWSTR szNewLineContents)
{
if ( _tcslen( szNewLineContents ) >= ( MAX_PATH - 1 ) )
{
// Right now we only support loading Lines of MAX_PATH
// chars or less
return FALSE;
}
// Copy String into both buffers
_tcscpy(m_szLine, szNewLineContents);
_tcscpy(m_szStrippedLineContents, szNewLineContents);
// Strip off \r\n
StripOffEOL( m_szLine );
StripOffEOL( m_szStrippedLineContents );
// Strip off Comments
StripOffComments( m_szStrippedLineContents );
// Stipp off trailing white
StripOffTrailingWhite( m_szStrippedLineContents );
return TRUE;
}
// CopyLine
//
// Copy the specific line into both our buffers
//
BOOL
CIniFileLine::CopyLine(LPSTR szNewLineContents)
{
WCHAR szBuffer[MAX_PATH];
if ( !MultiByteToWideChar( CP_ACP, //CP_THREAD_ACP doesn't work on NT4
MB_ERR_INVALID_CHARS,
szNewLineContents, // Input String
-1, // Null terminated
szBuffer,
MAX_PATH ) )
{
return FALSE;
}
return CopyLine( szBuffer );
}
// StripOffEOL
//
// Strip off the EOL markers
//
void
CIniFileLine::StripOffEOL(LPTSTR szString)
{
LPTSTR szCurrent;
szCurrent = _tcsstr( szString, L"\r" );
if ( szCurrent )
{
*szCurrent = '\0';
return;
}
szCurrent = _tcsstr( szString, L"\n" );
if ( szCurrent )
{
// we won't hit this case, unless it was terminated with
// just \n
*szCurrent = '\0';
}
}
// StripOffComments
//
// Strip off any comments that are in the line
//
void
CIniFileLine::StripOffComments(LPTSTR szString)
{
LPTSTR szCurrent;
szCurrent = _tcsstr( szString, L";" );
if ( szCurrent )
{
*szCurrent = '\0';
}
}
// Strip Off TrailingWhite
//
// strip off all the trailing while stuff in the line
//
void
CIniFileLine::StripOffTrailingWhite(LPTSTR szString)
{
// Set szCurrent at Null Terminator
LPTSTR szCurrent = szString + _tcslen( szString );
if ( ( *szCurrent == '\0' ) &&
( szCurrent != szString ) )
{
// Backup one character to start on the last char
szCurrent--;
}
while ( ( szCurrent != szString ) &&
( ( *szCurrent == ' ' ) ||
( *szCurrent == '\t' ) )
)
{
szCurrent--;
}
if ( *szCurrent != '\0' )
{
*( szCurrent + 1 ) = '\0';
}
}
// QueryLine
//
// Query the contents of the line, before formatting
//
LPTSTR
CIniFileLine::QueryLine()
{
return m_szLine;
}
// QueryStrippedLine
//
// Query the line that has the comments, EOL, and
// white spaces removed
//
LPTSTR
CIniFileLine::QueryStrippedLine()
{
return m_szStrippedLineContents;
}
// Constructor
//
CIniFile::CIniFile()
{
// Initialize everything to empty
m_pIniLines = NULL;
m_dwNumberofLines = 0;
m_dwLinesAllocated = 0;
m_dwCurrentLine = 0;
m_bUnicodeFile = FALSE;
}
// Destructor
//
CIniFile::~CIniFile()
{
ClearIni();
}
// ClearIni
//
// Clear all of the data in the ini file class
//
void
CIniFile::ClearIni()
{
DWORD dwCurrent;
if ( m_pIniLines )
{
for ( dwCurrent = 0;
dwCurrent < m_dwLinesAllocated;
dwCurrent ++ )
{
if ( m_pIniLines[dwCurrent] )
{
// Free memory, and reset to NULL
delete m_pIniLines[dwCurrent];
m_pIniLines[dwCurrent] = NULL;
}
}
m_dwNumberofLines = 0;
// Free Ini Table Altogether
delete m_pIniLines;
m_pIniLines = NULL;
m_dwLinesAllocated = 0;
}
}
// CreateMoreLines
//
// Create Room for more lines on the array. This allows us to
// stretch the array
BOOL
CIniFile::CreateRoomForMoreLines()
{
CIniFileLine **pNewLines = NULL;
DWORD dwNewNumberofLinesAllocated = m_dwLinesAllocated ?
m_dwLinesAllocated * 2 :
INIFILE_INITIALNUMBEROFLINES;
DWORD dwCurrent;
// Enlarge buffer
pNewLines = (CIniFileLine **) realloc( m_pIniLines,
sizeof( CIniFileLine * ) * dwNewNumberofLinesAllocated );
if ( pNewLines == NULL )
{
// Failure to enlarge.
// Do not need to worry about old memory, since it is still valid in m_pIniLines
return FALSE;
}
for ( dwCurrent = m_dwLinesAllocated;
dwCurrent < dwNewNumberofLinesAllocated;
dwCurrent++ )
{
// Initialize to Null
pNewLines[ dwCurrent ] = NULL;
}
m_pIniLines = pNewLines;
m_dwLinesAllocated = dwNewNumberofLinesAllocated;
return TRUE;
}
// AddLine
//
// Add a line at a specific location
//
// Parameters:
// dwLineNumber - The line number where it should be inserted
//
// Return
// NULL - Failure
// Pointer - A pointer to the CIniFileLine for the new line
//
CIniFileLine *
CIniFile::AddLine( DWORD dwLocation )
{
CIniFileLine *pNewLine;
DWORD dwCurrentLine;
if ( dwLocation > m_dwNumberofLines )
{
// Fail if we try to insert in a number to big
return FALSE;
}
if ( ( m_dwNumberofLines == m_dwLinesAllocated ) &&
!CreateRoomForMoreLines() )
{
// Could not create new lines for us
return FALSE;
}
pNewLine = new (CIniFileLine);
if ( !pNewLine )
{
// Failure to create new line
return FALSE;
}
// Move all the lines after it down, to make room for this one
if ( m_dwNumberofLines != 0 )
{
for ( dwCurrentLine = m_dwNumberofLines - 1;
dwCurrentLine >= dwLocation;
dwCurrentLine-- )
{
m_pIniLines[ dwCurrentLine + 1 ] = m_pIniLines[ dwCurrentLine ];
}
}
m_pIniLines[ dwLocation ] = pNewLine;
m_dwNumberofLines++;
return pNewLine;
}
// FindSectionNumber
//
// Find a section by a specific name
//
// Parameters
// szSectionName - [in] Section to look for
// pdwSection - [out] The Line #
//
// Return:
// TRUE - Found
// FALSE - Not found
//
BOOL
CIniFile::FindSectionNumber(LPTSTR szSectionName, DWORD *pdwSection)
{
DWORD dwCurrentIndex;
// ASSERT( pdwSection );
for ( dwCurrentIndex = 0; dwCurrentIndex < m_dwNumberofLines; dwCurrentIndex++ )
{
if ( IsSameSection( szSectionName,
m_pIniLines[dwCurrentIndex]->QueryStrippedLine() ) )
{
*pdwSection = dwCurrentIndex;
return TRUE;
}
}
return FALSE;
}
// IsSameSection
//
// Returns if the section is the same of not
//
// Parameters
// szSectionName - [in] The name of the Section (ie. TestSection)
// szLines - [in] The line in the file (ie. [TheSection])
//
// Return Values:
// TRUE - The same
// FALSE - Not the same
//
BOOL
CIniFile::IsSameSection(LPTSTR szSectionName, LPTSTR szLine)
{
LPTSTR szSectionCurrent;
LPTSTR szLineCurrent;
if ( szLine[0] != '[' )
{
// If the first character is not a '[', then
// it is not een a section
return FALSE;
}
szSectionCurrent = szSectionName;
szLineCurrent = szLine + 1; // Skip preceding '['
while ( ( towlower( *szSectionCurrent ) == towlower( *szLineCurrent ) ) &&
( *szSectionCurrent != '\0' )
)
{
szSectionCurrent++;
szLineCurrent++;
}
if ( ( *szSectionCurrent == '\0' ) &&
( *szLineCurrent == ']' ) &&
( *(szLineCurrent + 1) == '\0' )
)
{
// They match
return TRUE;
}
return FALSE;
}
// function: IsSameItem
//
// Is the Item Passed in, and the line, the same?
// Since items have nothing else on the line, this should
// be a simple _tcsicmp
//
// Parameters:
// szItemName - [in] The Item Name
// szLine - [in] The Line that is passed in
//
BOOL
CIniFile::IsSameItem(LPTSTR szItemName, LPTSTR szLine)
{
return _tcsicmp( szItemName, szLine) == 0;
}
// function: IsSameSetting
//
// Is the setting that is passed in, the same on
// that is on this specific line
//
// Parameters:
// szSettingName - [in] The Name of the setting (ie. MaxPath)
// szLine - [in] The Line to comapre (ie. MaxPath=30)
//
// Return Values:
// TRUE == same
// FALSE == no same
BOOL
CIniFile::IsSameSetting(LPTSTR szSettingName, LPTSTR szLine)
{
LPTSTR szSettingCurrent;
LPTSTR szLineCurrent;
szSettingCurrent = szSettingName;
szLineCurrent = szLine;
while ( ( towlower( *szSettingCurrent ) == towlower( *szLineCurrent ) ) &&
( *szSettingCurrent != '\0' )
)
{
szSettingCurrent++;
szLineCurrent++;
}
if ( ( *szSettingCurrent == '\0' ) &&
( *szLineCurrent == '=' )
)
{
// They match
return TRUE;
}
return FALSE;
}
// DoesSectionExist
//
// Does the specified section exist?
//
BOOL
CIniFile::DoesSectionExist(LPTSTR szSectionName)
{
DWORD dwLineNumber;
return FindSectionNumber( szSectionName, &dwLineNumber );
}
// GetLine
//
// Return a pointer to a particular line number
//
CIniFileLine *
CIniFile::GetLine(DWORD dwLineNumber)
{
return m_pIniLines[ dwLineNumber ];
}
// FindSection
//
// Find a specific section, and set the current pointer to
// that section, then user FindNextLineInSection to parse
// through that section
//
// Parameters
// szSectionName - [in] The Name of the Section
//
BOOL
CIniFile::FindSection( LPTSTR szSectionName )
{
if ( !FindSectionNumber( szSectionName, &m_dwCurrentLine ) )
{
// Could not find section
return FALSE;
}
return TRUE;
}
// FindNextLineInSection
//
// Find the next Line in the section, if any are left
//
BOOL
CIniFile::FindNextLineInSection( CIniFileLine **ppCurrentLine )
{
// Increment Line number
m_dwCurrentLine++;
if ( ( m_dwCurrentLine >= m_dwLinesAllocated ) ||
( GetLine( m_dwCurrentLine ) == NULL ) )
{
// We have either gone past the last line,
// or it does not exist, so return FALSE
return FALSE;
}
if ( GetLine( m_dwCurrentLine )->QueryStrippedLine()[0] == '[' )
{
// We have hit the begining of another section, so exit
return FALSE;
}
*ppCurrentLine = GetLine( m_dwCurrentLine );
return TRUE;
}
// DoesItemInSectionExist
//
// Does an Item in a particular section exist
//
// Parameters:
// szSectionName - [in] The section to search
// szItem - [in] The Item to find
//
// Return Values:
// TRUE - It exists
// FALSE - It does not exist
//
BOOL
CIniFile::DoesItemInSectionExist(LPTSTR szSectionName, LPTSTR szItem)
{
CIniFileLine *pCurrentLine;
if ( !FindSection( szSectionName ) )
{
// Could not find section, forget about the item
return FALSE;
}
while ( FindNextLineInSection( &pCurrentLine ) )
{
if ( IsSameItem( szItem, pCurrentLine->QueryStrippedLine() ) )
{
// We have found the item
return TRUE;
}
}
return FALSE;
}
// DoesSettingInSectionExist
//
// Does an Setting in a particular section exist
//
// Parameters:
// szSectionName - [in] The section to search
// szSetting - [in] The Setting to find
//
// Return Values:
// TRUE - It exists
// FALSE - It does not exist
//
BOOL
CIniFile::DoesSettingInSectionExist(LPTSTR szSectionName, LPTSTR szSetting)
{
CIniFileLine *pCurrentLine;
if ( !FindSection( szSectionName ) )
{
// Could not find section, forget about the item
return FALSE;
}
while ( FindNextLineInSection( &pCurrentLine ) )
{
if ( IsSameSetting( szSetting, pCurrentLine->QueryStrippedLine() ) )
{
// We have found the item
return TRUE;
}
}
return FALSE;
}
// GetNumberofLines
//
// Return the number of lines in the ini file
//
DWORD
CIniFile::GetNumberofLines()
{
return m_dwNumberofLines;
}
// AddSection
//
// Add a Section to the File
// (it inserts at end)
//
BOOL
CIniFile::AddSection(LPTSTR szNewSectionName)
{
TCHAR szBuffer[MAX_PATH];
CIniFileLine *pNewLine;
if ( _tcslen( szNewSectionName ) >= ( MAX_PATH - 3 ) ) // Leave room for [,],\0
{
return FALSE;
}
// Add a new line at the end
pNewLine = AddLine( GetNumberofLines() );
if ( !pNewLine )
{
// Failed to Add
return FALSE;
}
_tcscpy(szBuffer, L"[");
_tcscat(szBuffer, szNewSectionName);
_tcscat(szBuffer, L"]");
if ( !pNewLine->CopyLine( szBuffer ) )
{
// Failed to copy data
return FALSE;
}
// It has now been added, and updated with text
return TRUE;
}
// SetStartforSectionIterator
//
// Set the current line for the Section Iterator,
// this is so that you can start at anyline in the file you want
// and iterate through that section
//
BOOL
CIniFile::SetStartforSectionIterator( DWORD dwIndex )
{
if ( dwIndex >= m_dwNumberofLines )
{
return FALSE;
}
m_dwCurrentLine = dwIndex;
return TRUE;
}
// GetCurrentSectionIteratorLine
//
// Get current line that the iterator has
//
DWORD
CIniFile::GetCurrentSectionIteratorLine()
{
return m_dwCurrentLine;
}
// AddLinesToSection
//
// Add Lines to a specific section
// This is what we use to update the ini files with the new options
//
// Note: This will not create the section for you, so do that before
// you call this function
// Note2: If this function fails, it is possible to have part of your
// data in the file, so in essence, it is probably corrupted
//
// Parameters:
// szSectionName - The name of the section to update
// dwNumLines - The number of Lines in **szLines
// szLines - An array of lines to add (Null terminated)
// (no \r\n's are needed)
//
// Return Values:
// TRUE - Added Successfully
// FALSE - Failed to Add
//
BOOL
CIniFile::AddLinesToSection(LPTSTR szSectionName, DWORD dwNumLines, LPTSTR *szLines)
{
CIniFileLine *pCurrentLine;
DWORD dwCurrentLineinFile;
DWORD dwCurrentLineinInput;
if ( !FindSection( szSectionName ) )
{
// Failed to find section, bail now
return FALSE;
}
while ( FindNextLineInSection( &pCurrentLine ) )
{
// Do nothing, just iterate through the section
}
dwCurrentLineinFile = GetCurrentSectionIteratorLine();
for ( dwCurrentLineinInput = 0;
dwCurrentLineinInput < dwNumLines;
dwCurrentLineinInput++, dwCurrentLineinFile++ )
{
pCurrentLine = AddLine( dwCurrentLineinFile );
if ( !pCurrentLine ||
!pCurrentLine->CopyLine( szLines[ dwCurrentLineinInput ] )
)
{
// We failed to add the line, or to add contents to
// it, so we must bail
return FALSE;
}
}
return TRUE;
}
// LoadFile
//
// Load the ini file from the OS
//
BOOL
CIniFile::LoadFile( LPTSTR szFileName )
{
HANDLE hFile;
BOOL bRet;
hFile = CreateFile( szFileName,
GENERIC_READ, // Read
0, // No sharing
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL );
if ( hFile == INVALID_HANDLE_VALUE )
{
// Could not open file, Doh!
return FALSE;
}
bRet = ReadFileContents( hFile );
// Close File
CloseHandle( hFile );
return bRet;
}
// ReadFileContents
//
// Read all of the FileContents into memory
//
BOOL
CIniFile::ReadFileContents( HANDLE hFile )
{
BYTE pBuffer[INIFILE_READ_CHUNK_SIZE + 2]; // For \0\0
DWORD dwCurrentLocation = 0;
DWORD dwBytesRead;
BOOL bRet = TRUE;
m_bUnicodeFile = FALSE;
if ( ReadFile( hFile, pBuffer, 2, &dwCurrentLocation, NULL ) &&
( dwCurrentLocation == 2 ) &&
( pBuffer[0] == 0xFF ) &&
( pBuffer[1] == 0xFE )
)
{
// Since there is the 0xFF, 0xFE we will assume it is unicode
m_bUnicodeFile = TRUE;
// Reset Pointer, so we ignore the FFFE.
dwCurrentLocation = 0;
}
while ( ReadFile( hFile,
pBuffer + dwCurrentLocation,
INIFILE_READ_CHUNK_SIZE - dwCurrentLocation,
&dwBytesRead,
NULL ) &&
( dwBytesRead != 0 ) )
{
dwCurrentLocation += dwBytesRead;
pBuffer[dwCurrentLocation] = '\0';
pBuffer[dwCurrentLocation + 1 ] = '\0';
if ( !LoadChunk( pBuffer, &dwCurrentLocation, FALSE ) )
{
bRet = FALSE;
break;
}
}
if ( bRet )
{
if ( !LoadChunk( pBuffer, &dwCurrentLocation, TRUE) )
{
bRet = FALSE;
}
}
return bRet;
}
// LoadChunk
//
// Load the Chunk of Data from this buffer, into the ini
// class lines
//
// Parameters
// pData - [in/out] Buffer of Bytes to be loaded
// pdwCurrentLocation - [in/out] Location of end of buffer
// bIsLastChunck - [in] Flag to tells us if this is the last chunk
BOOL
CIniFile::LoadChunk( LPBYTE pData, DWORD *pdwCurrentLocation, BOOL bIsLastChunk )
{
LPBYTE szEndofLine;
LPBYTE szNextLine;
CIniFileLine *pCurrentLine;
while ( *pdwCurrentLocation > 0 )
{
szEndofLine = m_bUnicodeFile ? (LPBYTE) wcsstr( (LPWSTR) pData, L"\r" ) :
(LPBYTE) strstr( (LPSTR) pData, "\r" );
if ( szEndofLine == NULL )
{
szEndofLine = m_bUnicodeFile ? (LPBYTE) wcsstr( (LPWSTR) pData, L"\n" ) :
(LPBYTE) strstr( (LPSTR) pData, "\n" );
// Move to next line (this is \n, so it is only 1 char away)
szNextLine = szEndofLine + ( m_bUnicodeFile ? 2 : 1 );
}
else
{
// \r was found
if ( m_bUnicodeFile )
{
// Jump past \r, or \r\n
szNextLine = szEndofLine + ( *( (LPWSTR) szEndofLine + 1 ) == '\n' ?
4 : 2 );
}
else
{
// Jump past \r, or \r\n
szNextLine = szEndofLine + ( *( (LPSTR) szEndofLine + 1) == '\n' ?
2 : 1 );
}
if ( !bIsLastChunk &&
( m_bUnicodeFile ? *( (LPWSTR) szEndofLine + 1) == '\0' :
*( (LPSTR) szEndofLine + 1) == '\0' ) )
{
// This is a \r with a \0 imediately after it, this might mean that we have
// not read enough, so lets return and lets read another chunk
return TRUE;
}
}
if ( !szEndofLine )
{
if ( bIsLastChunk )
{
szEndofLine = pData + *pdwCurrentLocation;
szNextLine = szEndofLine;
}
else
{
// Can not find another line, so exit
return TRUE;
}
}
// Null Terminate Here
if ( m_bUnicodeFile )
{
wcscpy( (LPWSTR) szEndofLine, L"\0" );
}
else
{
strcpy( (LPSTR) szEndofLine, "\0" );
}
if ( ( ( pCurrentLine = AddLine( GetNumberofLines() ) ) == NULL ) ||
!( m_bUnicodeFile ? pCurrentLine->CopyLine( (LPWSTR) pData ) :
pCurrentLine->CopyLine( (LPSTR) pData ) )
)
{
// Error Adding Line
return FALSE;
}
// Remove that part of the line
memmove( pData, szNextLine, *pdwCurrentLocation - (szNextLine - pData) + 2 ); // +2 for \0\0
*pdwCurrentLocation -= (DWORD) (szNextLine - pData);
}
return TRUE;
}
// SaveFile
//
// Save the ini file to disk
//
BOOL
CIniFile::SaveFile( LPTSTR szFileName )
{
HANDLE hFile;
BOOL bRet;
hFile = CreateFile( szFileName,
GENERIC_WRITE, // Read
0, // No sharing
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL );
if ( hFile == INVALID_HANDLE_VALUE )
{
// Could not create the file
return FALSE;
}
bRet = WriteFileContents( hFile );
// Close File
CloseHandle( hFile );
return bRet;
}
// WriteFileContents
//
// Write the ini contents to the file
//
BOOL
CIniFile::WriteFileContents( HANDLE hFile )
{
DWORD dwCurrent;
CHAR szLine[MAX_PATH];
DWORD dwBytesWritten;
if ( m_bUnicodeFile )
{
// If this file is unicode, lets write the prefix 0xFF,0xFE right now
BYTE pData[2] = { 0xFF, 0xFE };
if ( !WriteFile( hFile, pData, sizeof( pData ),
&dwBytesWritten, NULL ) )
{
// Failed to write to file
return FALSE;
}
}
for ( dwCurrent = 0; dwCurrent < GetNumberofLines(); dwCurrent++ )
{
if ( !m_bUnicodeFile )
{
// If not unicode, then we need to translate back to Ansi
if ( !WideCharToMultiByte( CP_ACP, //CP_THREAD_ACP doesn't work on NT4
0,
GetLine( dwCurrent )->QueryLine(),
-1, // Null terminated
szLine,
MAX_PATH,
NULL,
NULL) )
{
// Line could not be converted, so lets fail
return FALSE;
}
}
// Write line to file
if ( !WriteFile( hFile,
m_bUnicodeFile ? (LPBYTE) GetLine( dwCurrent )->QueryLine():
(LPBYTE) szLine,
m_bUnicodeFile ? (DWORD) wcslen( GetLine( dwCurrent )->QueryLine() ) * sizeof( WCHAR ):
(DWORD) strlen( szLine ) * sizeof( CHAR),
&dwBytesWritten,
NULL ) )
{
// Failed to write Line
return FALSE;
}
// Line Terminators
if ( !WriteFile( hFile,
m_bUnicodeFile ? (LPBYTE) L"\r\n":
(LPBYTE) "\r\n",
m_bUnicodeFile ? (DWORD) wcslen( L"\r\n" ) * sizeof( WCHAR ) :
(DWORD) strlen( "\r\n") * sizeof( CHAR) ,
&dwBytesWritten,
NULL ) )
{
// Failed to write Line
return FALSE;
}
} // for
return TRUE;
}