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
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;
|
|
}
|
|
|
|
|
|
|
|
|