/*++ Copyright (c) 2001 Microsoft Corporation Module Name : xmlupgrade.cxx Abstract: Classes that are used to upgrade the xml metabase and mbschema from one version to another Author: Christopher Achille (cachille) Project: Internet Services Setup Revision History: September 2001: Created --*/ #include "stdafx.h" #include "buffer.hxx" #include "xmlupgrade.hxx" #include "acl.hxx" // Constructor, initialize all the variables // CFileModify::CFileModify() { m_hReadFile = INVALID_HANDLE_VALUE; m_hWriteFile = INVALID_HANDLE_VALUE; m_buffData.Resize(CFILEMODIFY_BLOCKSIZE + 2); m_szCurrentData = (LPBYTE) m_buffData.QueryPtr(); m_dwSizeofData = 0; m_bUnicode = FALSE; *m_szReadFileName = '\0'; *m_szWriteFileName = '\0'; SetValue(m_szCurrentData, '\0'); } // Destructor, close the file // CFileModify::~CFileModify() { // Just incase it has not been closed yet, close it CloseFile(); } // function: MoveXChars // // Move the pointer the number of characters specified // // Parameters: // szCurrent - Pointer to a unicode or ansi string // (type is determined by m_m_bUnicode) // // Return: // Pointer to szCurrent + dwChars // LPBYTE CFileModify::MoveXChars(LPBYTE szCurrent, DWORD dwChars) { if ( m_bUnicode ) { return (LPBYTE) ( ( ( LPWSTR ) szCurrent ) + dwChars ); } else { return (LPBYTE) ( ( ( LPSTR ) szCurrent ) + dwChars ); } } LPBYTE CFileModify::MoveXChars(LPVOID szCurrent, DWORD dwChars) { return MoveXChars( (LPBYTE) szCurrent, dwChars ); } // function: SetValue // // Set the value at the location specified // // Parameters: // szCurrent - Pointer to a unicode or ansi string // (type is determined by m_m_bUnicode) // dwValue - The value to put in the string // dwOffset - Offset to add to szCurrent (in chars) (default of 0) // void CFileModify::SetValue(LPBYTE szCurrent, DWORD dwValue, DWORD dwOffset ) { LPBYTE szNewLocation = szCurrent; if ( dwOffset ) { szNewLocation = MoveXChars(szCurrent,dwOffset); } if ( m_bUnicode ) { * ( ( LPWSTR ) szNewLocation ) = (WCHAR) dwValue; } else { * ( ( LPSTR ) szNewLocation ) = (CHAR) dwValue; } } void CFileModify::SetValue(PVOID szCurrent, DWORD dwValue, DWORD dwOffset ) { SetValue( (LPBYTE) szCurrent,dwValue,dwOffset); } // function: CopyString // // Copy a string into the buffer void CFileModify::CopyString(LPBYTE szCurrent, LPTSTR szInsertString) { while ( *szInsertString ) { SetValue(szCurrent,*szInsertString); GetNextChar(szCurrent); szInsertString++; } } // function: AbortFile // // Abort the current file modification. So, we close the file handles, and delete the // file that we wrote to // BOOL CFileModify::AbortFile() { BOOL bRet = TRUE; if (m_hReadFile != INVALID_HANDLE_VALUE) { CloseHandle(m_hReadFile); m_hReadFile = INVALID_HANDLE_VALUE; } if (m_hWriteFile != INVALID_HANDLE_VALUE) { CloseHandle(m_hWriteFile); m_hWriteFile = INVALID_HANDLE_VALUE; bRet = DeleteFile( m_szWriteFileName ); } return bRet; } // function: CloseFile // // Close all of the files, and write all the data to disk // BOOL CFileModify::CloseFile() { BOOL bWrite = m_hWriteFile != INVALID_HANDLE_VALUE; BOOL bRet = TRUE; if ( bWrite ) { // Dump the rest of the input file to the output one. while ( ReadNextChunk() ) { // Move to the end of the block, so it will all be written m_szCurrentData = MoveXChars( m_buffData.QueryPtr(), m_dwSizeofData ); } if ( m_dwSizeofData ) { // The last ReadNextChunk failed because we could not read anymore, // lets call it one more time to flush the rest of the data in the buffer m_szCurrentData = MoveXChars( m_buffData.QueryPtr(), m_dwSizeofData ); ReadNextChunk(); } } if (m_hReadFile != INVALID_HANDLE_VALUE) { CloseHandle(m_hReadFile); m_hReadFile = INVALID_HANDLE_VALUE; } if (m_hWriteFile != INVALID_HANDLE_VALUE) { CloseHandle(m_hWriteFile); m_hWriteFile = INVALID_HANDLE_VALUE; } if ( bWrite ) { bRet = FALSE; if ( DeleteFile( m_szReadFileName ) ) { MoveFile( m_szWriteFileName, m_szReadFileName ); bRet = TRUE; } } return bRet; } // function: OpenFile // // This function opens a readonly handle to the file specified in szFileName, // also a second File handle will be opened with write only access under the // name szFileName+".tmp". This is for temporary storage for the new file // // Parameters: // szFileName - The filename of the file to read // bModify - Are we going to be modifing this file or not? // // Return // TRUE - Read and Write files we successfully opened // FALSE - Failure to open one of the files // BOOL CFileModify::OpenFile(LPTSTR szFileName, BOOL bModify) { CSecurityDescriptor AdminAcl; if ( ( _tcslen(szFileName) - _tcslen(_T(".tmp")) ) >= _MAX_PATH ) { return FALSE; } if ( !AdminAcl.CreateAdminDAcl() ) { // We could not create an admin acl, so lets exit return FALSE; } // First abort the last file, if one was opened AbortFile(); _tcscpy(m_szReadFileName,szFileName); _tcscpy(m_szWriteFileName,szFileName); _tcscat(m_szWriteFileName,_T(".tmp")); m_hReadFile = CreateFile( m_szReadFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if ( m_hReadFile == INVALID_HANDLE_VALUE ) { return FALSE; } if ( bModify ) { m_hWriteFile = CreateFile( m_szWriteFileName, GENERIC_WRITE, 0, AdminAcl.QuerySA(), CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL ); if ( m_hWriteFile == INVALID_HANDLE_VALUE ) { // Close Read File and return AbortFile(); return FALSE; } } m_szCurrentData = (LPBYTE) m_buffData.QueryPtr(); m_dwSizeofData = 0; m_bUnicode = FALSE; if ( ReadNextChunk() ) { if ( ( m_dwSizeofData > 3 ) && ( *( ( LPBYTE ) m_buffData.QueryPtr() ) == 0xEF ) && ( *( ( LPBYTE ) m_buffData.QueryPtr() + 1 ) == 0xBB ) && ( *( ( LPBYTE ) m_buffData.QueryPtr() + 2 ) == 0xBF ) ) { // It is UTF8 Encoded m_bUnicode = FALSE; m_szCurrentData = (LPBYTE) m_buffData.QueryPtr() + 3; } else if ( ( m_dwSizeofData >= 2 ) && ( *( ( LPBYTE ) m_buffData.QueryPtr() ) == 0xFF ) && ( *( ( LPBYTE ) m_buffData.QueryPtr() + 1 ) == 0xFE) ) { // It is Unicode m_bUnicode = TRUE; m_szCurrentData = (LPBYTE) m_buffData.QueryPtr() + 2; } } return TRUE; } // function: ResizeData // // Resize the data buffer to the size specified // never shrink the buffer itself, just exand it // // Parameters: // dwNewSize - The new size needed BOOL CFileModify::ResizeData(DWORD dwNewSize) { BOOL bRet = TRUE; if (m_buffData.QuerySize() < (dwNewSize + 2) ) { DWORD dwCurrentOffset = (DWORD) (DWORD_PTR) (m_szCurrentData - (LPBYTE) m_buffData.QueryPtr()); if ( !m_buffData.Resize(dwNewSize + 2) ) { // We failed to allocate the memory necessary bRet = FALSE; } if (dwCurrentOffset <= dwNewSize) { m_szCurrentData = (LPBYTE) m_buffData.QueryPtr() + dwCurrentOffset; } else { ASSERT(FALSE); m_szCurrentData = (LPBYTE) m_buffData.QueryPtr(); } } return bRet; } // function: ResizeData // // Resize Data, and move the pointer accourdingly // BOOL CFileModify::ResizeData(DWORD dwNewSize, LPBYTE *szString) { DWORD dwOffset = (DWORD) (DWORD_PTR) ( *szString - GetCurrentLocation() ); BOOL bRet; bRet = ResizeData(dwNewSize); // Move current pointer to account for possible resizing of buffer *szString = GetCurrentLocation() + dwOffset; return bRet; } // function: ReadNextChunk // // Read in the next Chunk of Data, in order to do this, take the part of // the chunck that has already been processed, and write it to the output // file. Then move the rest of the chunck over, so that you can read some // more data in. The divider between processed, and unprocessed is determined // by the location of m_szCurrentData // // Data before: // |-------------------------------------------------------------| // | Used Data | Currently using Data | Extra Space | // |-------------------------------------------------------------| // // Data after: // |-------------------------------------------------------------| // | Currently using Data | New Data | // |-------------------------------------------------------------| // // Return: // TRUE - The next piece of data was correctly read in // FASLE - Their was an error, either reading from the file, or writing the // data that we currently have to the output file. BOOL CFileModify::ReadNextChunk() { DWORD dwUsedSize; // Size of Block used and done with (in bytes) DWORD dwCurrentlyUsingSize; // Size of Data to keep DWORD dwExtraSpaceSize; // Size of Free Space DWORD dwTotalChunkSize; DWORD dwSizeofCurrentChunk; if ( m_dwSizeofData != 0 ) { dwUsedSize = (DWORD) ( ( (BYTE*) m_szCurrentData ) - ( (BYTE*) m_buffData.QueryPtr() ) ); dwCurrentlyUsingSize = m_dwSizeofData - dwUsedSize; dwExtraSpaceSize = m_buffData.QuerySize() - dwCurrentlyUsingSize - 2; // 2 for possible LPWSTR '\0' ASSERT( dwUsedSize <= m_dwSizeofData ); // Assert that the UsedSection is smaller that our overall section size } else { // We have not read anything in before, so initialize stuff dwUsedSize = 0; dwCurrentlyUsingSize = 0; dwExtraSpaceSize = m_buffData.QuerySize() - dwCurrentlyUsingSize - 2; } if ( dwUsedSize ) { // Part of this block is done with, so lets write it to disk dwTotalChunkSize = dwUsedSize; dwSizeofCurrentChunk = 0; if ( m_hWriteFile != INVALID_HANDLE_VALUE ) { LPBYTE pData = (LPBYTE) m_buffData.QueryPtr(); // If we have a file open, then lets write to it, if not then we are read only while ( dwTotalChunkSize > 0 ) { if ( ( !WriteFile(m_hWriteFile, // Handle to write file pData, // Data to send dwTotalChunkSize, // # of Bytes to write &dwSizeofCurrentChunk, // Bytes Written NULL ) ) || ( dwSizeofCurrentChunk == 0 ) ) { // We had problems writing to disk, FAIL return FALSE; } pData += dwSizeofCurrentChunk; dwTotalChunkSize -= dwSizeofCurrentChunk; } } // Move Current Block memmove( m_buffData.QueryPtr(), m_szCurrentData, dwCurrentlyUsingSize + 2 ); m_szCurrentData = ( (BYTE *) m_buffData.QueryPtr() ); m_dwSizeofData -= dwUsedSize; } else if (dwCurrentlyUsingSize) { // If there is not data to take out of the buffer, and we have data in the buffer // Double the size of the buffer ResizeData( m_buffData.QuerySize() * 2 ); dwExtraSpaceSize = m_buffData.QuerySize() - dwCurrentlyUsingSize - 2; // 2 for possible LPWSTR '\0' } if ( dwExtraSpaceSize != 0 ) { // There is space remaining in the block, so lets read the data in dwTotalChunkSize = dwExtraSpaceSize; dwSizeofCurrentChunk = 0; while ( dwTotalChunkSize > 0 ) { if ( !ReadFile( m_hReadFile, ( (BYTE *) m_buffData.QueryPtr() ) + dwCurrentlyUsingSize, dwTotalChunkSize, &dwSizeofCurrentChunk, NULL ) ) { // We could not read the chunk, so fail return FALSE; } if ( dwSizeofCurrentChunk == 0 ) { if ( dwExtraSpaceSize == dwTotalChunkSize ) { // If the extra space is the same as the totalchunksize, then we // haven't read anything yet, so return FALSE signifying that we // did not read anything from the file return FALSE; } // We are at the end of file, so break out. break; } dwTotalChunkSize -= dwSizeofCurrentChunk; dwCurrentlyUsingSize += dwSizeofCurrentChunk; } // Terminate Block m_dwSizeofData = dwCurrentlyUsingSize; SetValue(m_buffData.QueryPtr(),'\0',dwCurrentlyUsingSize / (m_bUnicode?2:1) ); } return TRUE; } // function: MoveCurrentPtr // // Move the pointer in the array // // Parameters // szCurrent - New Location // BOOL CFileModify::MoveCurrentPtr(LPBYTE szCurrent) { if ( (szCurrent < m_buffData.QueryPtr()) || (szCurrent > ( (LPBYTE) m_buffData.QueryPtr() + m_buffData.QuerySize() ) ) ) { // This is out of range, reject position ASSERT(FALSE); return FALSE; } m_szCurrentData = szCurrent; return TRUE; } // function: GetCurrentLocation // // return a pointer to the current location of the pointer LPBYTE CFileModify::GetCurrentLocation() { return m_szCurrentData; } // function: GetBaseLocation // // return a pointer to the begining of the block LPBYTE CFileModify::GetBaseLocation() { return (LPBYTE) m_buffData.QueryPtr(); } // function: GetNextChar // return the value of the next character // // Parameters: // szCurrent - Pointer to part of our m_buffData Block // // Return Value: // The unicode of ansi value for the next character // DWORD CFileModify::GetNextChar(LPBYTE &szCurrent) { DWORD dwValue; if ( m_bUnicode ) { szCurrent = (LPBYTE) ( ( LPWSTR ) szCurrent) + 1; dwValue = *( ( LPWSTR ) szCurrent); } else { szCurrent = (LPBYTE) ( ( LPSTR ) szCurrent) + 1; dwValue = *( ( LPSTR ) szCurrent); } return dwValue; } // function: GetNextWideChar // // Return the value of the next wide character // // Return Value: // The unicode equivalent of the next character // DWORD CFileModify::GetNextWideChar(LPBYTE &szCurrent) { if ( m_bUnicode ) { szCurrent = (LPBYTE) ( ( LPWSTR ) szCurrent) + 1; } else { szCurrent = (LPBYTE) CharNextA( (LPSTR) szCurrent ); } return GetWideChar( szCurrent ); } // function: GetPrevChar // return the value of pointer decremeted and dereferenced // // Parameters: // szCurrent - Pointer to part of our m_buffData Block // // Return Value: // The unicode of ansi value for the next character that is pointer at // DWORD CFileModify::GetPrevChar(LPBYTE &szCurrent) { DWORD dwValue; if ( m_bUnicode ) { szCurrent = (LPBYTE) ( ( LPWSTR ) szCurrent) - 1; dwValue = *( ( LPWSTR ) szCurrent); } else { szCurrent = (LPBYTE) ( ( LPSTR ) szCurrent) - 1; dwValue = *( ( LPSTR ) szCurrent); } return dwValue; } // function: GetChar // return the value of the current character // // Parameters: // szCurrent - Pointer to part of our m_buffData Block // // Return Value: // The unicode of ansi value for the character that is pointer at // DWORD CFileModify::GetChar(LPBYTE szCurrent) { if ( m_bUnicode ) { return *( ( LPWSTR ) szCurrent ); } else { return *( ( LPSTR ) szCurrent ); } } // function: GetWideChar // // Get the Wide Char equivalent of the current character // WCHAR CFileModify::GetWideChar(LPBYTE szCurrent) { if ( m_bUnicode ) { return (WCHAR) *( ( LPWSTR ) szCurrent ); } else { DWORD dwMBCSLen = (DWORD) ( ( (LPBYTE) CharNextA( (LPSTR) szCurrent ) ) - szCurrent ); WCHAR wChar; if ( MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, (LPSTR) szCurrent, dwMBCSLen, &wChar, sizeof(wChar)/sizeof(WCHAR) ) == 0 ) { return 0; } return wChar; } } // function: MoveData // // Expand or contract data in order to add a value or remove one // // Parameters: // szCurrent - A pointer to where the data will be removed/added // iBytes - The amount of data to remove or add // BOOL CFileModify::MoveData(LPBYTE szCurrent, INT iBytes) { DWORD dwNewSize = ( (INT) m_dwSizeofData ) + iBytes; if ( !ResizeData(dwNewSize, &szCurrent) ) { return FALSE; } if ( iBytes > 0 ) { // Move bytes forward memmove( szCurrent + iBytes, szCurrent, m_dwSizeofData - ( szCurrent - (LPBYTE) m_buffData.QueryPtr() ) + 2 ); } else if ( iBytes < 0 ) { // Move bytes back memmove( szCurrent, szCurrent - iBytes, m_dwSizeofData - ( szCurrent - iBytes - (LPBYTE) m_buffData.QueryPtr() ) + 2 ); } m_dwSizeofData = dwNewSize; return TRUE; } BOOL CFileModify::IsUnicode() { return m_bUnicode; } // function: GetBufferSize // // return the size of the buffer used in this class DWORD CFileModify::GetBufferSize() { return (m_dwSizeofData); } // function: CXMLEdit // // Constructor for XMLEditor // CXMLEdit::CXMLEdit(): m_dwItemOffset(0), m_dwPropertyOffset(0), m_dwValueOffset(0) { } // function: ~CXMLEdit // // Destructor for XMLEditor // // Close Everything open // CXMLEdit::~CXMLEdit() { XMLFile.CloseFile(); } // function: Open // // Open the file to edit // BOOL CXMLEdit::Open(LPTSTR szName, BOOL bModify ) { BOOL bRet; bRet = XMLFile.OpenFile(szName,bModify); if ( bRet ) { SetCurrentItem(XMLFile.GetCurrentLocation()); } return bRet; } // function: Close // // Close the xml file // BOOL CXMLEdit::Close() { return XMLFile.CloseFile(); } // function: MoveData // // Move the data in the CFileModify. This also means that we need to move our // pointers into it. // // Parameters: // szCurrent - A pointer to where the data will be removed/added // iBytes - The amount of data to remove or add // BOOL CXMLEdit::MoveData(LPBYTE szCurrent, INT iBytes) { return XMLFile.MoveData(szCurrent,iBytes); } // function: ReadNextChunk(); // // ReadNextChunk of Data // BOOL CXMLEdit::ReadNextChunk() { BOOL bRet; DWORD dwItemOffset = (DWORD) (DWORD_PTR) (GetCurrentItem() - XMLFile.GetCurrentLocation()); DWORD dwPropertyOffset = (DWORD) (DWORD_PTR) (GetCurrentProperty() - XMLFile.GetCurrentLocation()); DWORD dwValueOffset = (DWORD) (DWORD_PTR) (GetCurrentValue() - XMLFile.GetCurrentLocation()); bRet = XMLFile.ReadNextChunk(); // Since the CurrentLocation Pointer might have moved, move // our pointers as well! SetCurrentItem( ((LPBYTE) XMLFile.GetCurrentLocation()) + dwItemOffset ); SetCurrentProperty( ((LPBYTE) XMLFile.GetCurrentLocation()) + dwPropertyOffset ); SetCurrentValue( ((LPBYTE) XMLFile.GetCurrentLocation()) + dwValueOffset ); return bRet; } // function: LoadFullItem // // Load the full item into memory, will all of it's properties before continuing // The purpose of this is to make it much easier for other functions to scan // through the buffer. It is a lot simplier, it they can assume all the information // they need is loaded. // // Parameters: // szPointerInsideBuffer [in/out] - This is a pointer to a something side of our // file buffer. The purpose of this, is so that we can move this pointer // so that it points to the same data before we moved the buffer void CXMLEdit::LoadFullItem() { LPBYTE szCurrent = GetCurrentItem(); LPBYTE szCurrentTemp; DWORD cCurrent; BOOL bContinue = TRUE; do { cCurrent = XMLFile.GetChar( szCurrent ); szCurrentTemp = szCurrent; if ( (cCurrent == '<') || (cCurrent == '>') || ( (cCurrent == '/') && ( XMLFile.GetNextChar(szCurrentTemp) == '>' ) ) ) { // We have found the end return; } if ( cCurrent == '\0' ) { // We have found the end of the string, try to get the next chunk if (!ReadNextChunk()) { return; } // Start again at begining szCurrent = GetCurrentItem(); } else { szCurrentTemp = szCurrent; szCurrent = SkipString(szCurrent); if (szCurrent == szCurrentTemp) { XMLFile.GetNextChar( szCurrent ); } } } while (bContinue); } // function: FindNextItem // // Find the next item after the pointer that we are sent // // Parameters: // szStartLocation - A pointer to the current item // bReturnName - Return a pointer to the begining of the name // LPBYTE CXMLEdit::FindNextItem(LPBYTE szStartLocation, BOOL bReturnName) { BOOL bQuotes; LPBYTE szCurrent; DWORD dwItemOffset; if (!szStartLocation) { // We have no item to start at return NULL; } // Calculate offset for Start (incase pointer moves) dwItemOffset = (DWORD) (DWORD_PTR) (szStartLocation - XMLFile.GetCurrentLocation()); do { // Reset szCurrent to begining of current item szCurrent = XMLFile.GetCurrentLocation() + dwItemOffset; bQuotes = FALSE; while ( XMLFile.GetChar( szCurrent ) != '\0') { switch ( XMLFile.GetChar( szCurrent ) ) { case '"': bQuotes = !bQuotes; break; case '<': if (!bQuotes) { LPBYTE szTempCurrent = szCurrent; // Move past '<' XMLFile.GetNextChar(szCurrent); while ( IsWhiteSpace( XMLFile.GetChar( szCurrent ) ) ) { XMLFile.GetNextChar(szCurrent); } if (bReturnName) { szTempCurrent = szCurrent; } while ( ( XMLFile.GetChar( szCurrent ) != ' ') && ( XMLFile.GetChar( szCurrent ) != '\t') && ( XMLFile.GetChar( szCurrent ) != '\0') ) { XMLFile.GetNextChar(szCurrent); } if ( XMLFile.GetChar( szCurrent ) != '\0') { // We could not read the whole name, because we are the end of what we // read in, so lets try this whole thing again return ( szTempCurrent ); } } else { // Remove //ASSERT(FALSE); } break; default: break; } if ( XMLFile.GetChar( szCurrent ) != '\0' ) { XMLFile.GetNextChar(szCurrent); } } } while ( ReadNextChunk() ); return NULL; } // function: FindNextItem() // // find the next item. This means to start at the item we are in, and get to the // next one // // Parameters: // bReturnName - Skip the '<' at the beinging of the item, and return a pointer to the // begining of the name LPBYTE CXMLEdit::FindNextItem(BOOL bReturnName) { return FindNextItem(GetCurrentItem(),bReturnName); } // function: SkipString // // Skip over a string value, and the spaces trailing it // LPBYTE CXMLEdit::SkipString(LPBYTE szString, BOOL bSkipTrailingWhiteSpaces) { BOOL bQuotes = FALSE; while ( XMLFile.GetChar( szString ) ) { switch ( XMLFile.GetChar( szString ) ) { case '"': bQuotes = !bQuotes; break; case '<': case '>': case '=': if ( !bQuotes ) { return szString; } break; default: if ( !bQuotes ) { if ( IsWhiteSpace( XMLFile.GetChar( szString ) ) ) { if (bSkipTrailingWhiteSpaces) { while ( IsWhiteSpace( XMLFile.GetChar( szString ) ) ) { XMLFile.GetNextChar(szString); } } return szString; } } break; } XMLFile.GetNextChar(szString); } if (bSkipTrailingWhiteSpaces) { while ( IsWhiteSpace( XMLFile.GetChar( szString ) ) ) { XMLFile.GetNextChar(szString); } } return szString; } // function: FindNextProperty // // Find the next property in the current item // // Parameters: // szCurrentValue - Pointer to Value // // Return Values // NULL - Another Property was not found // not NULL - The pointer to the next property LPBYTE CXMLEdit::FindNextProperty(LPBYTE &szValue) { BOOL bQuotes; LPBYTE szCurrent; LPBYTE szCurrentProp; LPBYTE szCurrentValue; if (!GetCurrentProperty()) { // We do not have a current property return NULL; } do { // Reset szCurrent to begining of current property bQuotes = FALSE; szCurrent = SkipString(GetCurrentProperty()); if ( XMLFile.GetChar(szCurrent) == '=' ) { // We have found a value for our old property XMLFile.GetNextChar(szCurrent); szCurrent = SkipString(szCurrent); } // Set the current property szCurrentProp = szCurrent; // Try to find a value for this property szCurrent = SkipString(szCurrent); if ( XMLFile.GetChar(szCurrent) == '=' ) { // We have found a value for our new property XMLFile.GetNextChar(szCurrent); szCurrentValue = szCurrent; } else { szCurrentValue = NULL; } if ( ( XMLFile.GetChar(szCurrent) == '<' ) || ( XMLFile.GetChar(szCurrent) == '>' ) ) { // We have left the current item, so return NULL return NULL; } if ( XMLFile.GetChar(szCurrent) != '\0' ) { // We have found the next item, lets return it szValue = szCurrentValue; return szCurrentProp; } } while ( ReadNextChunk() ); // End of File, no more values are present. return NULL; } // function: MoveToNextItem // // Move to the Next Item // BOOL CXMLEdit::MovetoNextItem() { LPBYTE szTemp; LPBYTE szLastItem; szTemp = FindNextItem(); szLastItem = GetCurrentItem(); // Do this afterwards, just incase we moved the buffer if (szTemp == NULL) { return FALSE; } SetCurrentItem(szTemp); SetCurrentProperty(szTemp); SetCurrentValue(szTemp); // Always keep the last item in the buffer // The reason for this, is because on delete we want to be able // to back up to the '<' of the current item XMLFile.MoveCurrentPtr(szLastItem); return TRUE; } // function: MoveToNextProperty // // Move to the Next Property // BOOL CXMLEdit::MovetoNextProperty() { LPBYTE szTemp; LPBYTE szTempValue = NULL; szTemp = FindNextProperty(szTempValue); if (szTemp == NULL) { return FALSE; } SetCurrentProperty(szTemp); if (szTempValue) { SetCurrentValue(szTempValue); } else { SetCurrentValue(szTemp); } return TRUE; } // function: MoveToFirstProperty // // Move to the First Property // BOOL CXMLEdit::MovetoFirstProperty() { SetCurrentProperty(GetCurrentItem()); SetCurrentValue(GetCurrentProperty()); return MovetoNextProperty(); } // RetrieveCurrentValue // // Retrieve the current Value, and put it in pstrValue // BOOL CXMLEdit::RetrieveCurrentValue( TSTR *pstrValue ) { LPBYTE szBeginingofValue; LPBYTE szCurrentLocation; BOOL bInsideQuotes = FALSE; DWORD dwCurrentLen = 0; DWORD i; LoadFullItem(); szBeginingofValue = GetCurrentValue(); if ( *szBeginingofValue == '"' ) { bInsideQuotes = TRUE; XMLFile.GetNextChar(szBeginingofValue); } szCurrentLocation = szBeginingofValue; while ( TRUE ) { if ( bInsideQuotes && ( XMLFile.GetWideChar(szCurrentLocation) == '"' ) ) { // Hit end break; } if ( ( !bInsideQuotes && IsTerminator( XMLFile.GetWideChar(szCurrentLocation) ) ) || ( XMLFile.GetWideChar(szCurrentLocation) == '\0' ) ) { // We hit the end again break; } XMLFile.GetNextWideChar(szCurrentLocation); dwCurrentLen++; } if ( !pstrValue->Resize( dwCurrentLen + 1 ) ) { return FALSE; } szCurrentLocation = szBeginingofValue; for ( i = 0; i < dwCurrentLen; i++ ) { *(pstrValue->QueryStr() + i ) = ( WCHAR ) XMLFile.GetWideChar( szCurrentLocation ); XMLFile.GetNextWideChar( szCurrentLocation ); } *(pstrValue->QueryStr() + i ) = '\0'; return TRUE; } // function:IsWhiteSpace // // returns if the character is a space // BOOL CXMLEdit::IsWhiteSpace(DWORD ch) { return ( ( ch == ' ' ) || ( ch == '\t' ) || ( ch == '\r' ) || ( ch == '\n' ) ); } // function:IsWhiteSpace // // returns if the character is a xml string terminator // BOOL CXMLEdit::IsTerminator(DWORD ch) { return ( ( ch == '\0' ) || ( ch == '=' ) || IsWhiteSpace(ch) ); } // function: GetCurrentItem // // Return a pointer to the Current Item LPBYTE CXMLEdit::GetCurrentItem() { return XMLFile.GetBaseLocation() + m_dwItemOffset; } // function: GetCurrentProperty // // Return a pointer to the Current Property LPBYTE CXMLEdit::GetCurrentProperty() { return XMLFile.GetBaseLocation() + m_dwPropertyOffset; } // function: GetCurrentValue // // Return a pointer to the value for the current property LPBYTE CXMLEdit::GetCurrentValue() { return XMLFile.GetBaseLocation() + m_dwValueOffset; } // function: SetCurrentItem // // Set the location for the current item void CXMLEdit::SetCurrentItem(LPBYTE szInput) { ASSERT( ((DWORD) ( szInput - XMLFile.GetBaseLocation() ) ) < XMLFile.GetBufferSize() ); m_dwItemOffset = (DWORD) (DWORD_PTR) (szInput - XMLFile.GetBaseLocation()); } // function: SetCurrentProperty // // Set the location for the current property void CXMLEdit::SetCurrentProperty(LPBYTE szInput) { ASSERT( ((DWORD) ( szInput - XMLFile.GetBaseLocation() ) ) < XMLFile.GetBufferSize() ); m_dwPropertyOffset = (DWORD) (DWORD_PTR) (szInput - XMLFile.GetBaseLocation()); } // function: SetCurrentValue // // Set the location for the current value void CXMLEdit::SetCurrentValue(LPBYTE szInput) { ASSERT( ((DWORD) ( szInput - XMLFile.GetBaseLocation() ) ) < XMLFile.GetBufferSize() ); m_dwValueOffset = (DWORD) (DWORD_PTR) (szInput - XMLFile.GetBaseLocation()); } // function: FindBeginingofItem // // Find the begining of the current item // // Parameters: // szInput - The Location to start at // // Return: // NULL - Could not find the begining // Pointer - The begining, starting with the '<' LPBYTE CXMLEdit::FindBeginingofItem(LPBYTE szInput) { while ( ( szInput >= XMLFile.GetBaseLocation() ) && ( XMLFile.GetChar(szInput) != '\0' ) ) { if ( XMLFile.GetChar(szInput) == '<' ) { return szInput; } XMLFile.GetPrevChar(szInput); } return NULL; } // function: DeleteItem() // // Delete an item // // Note: This will not only delete the current item, but it will delete any items that // are nested inside of it. // // Return: // TRUE - Deleted successfully // FALSE - Failed to delete it BOOL CXMLEdit::DeleteItem() { LPBYTE szBegin; LPBYTE szEnd; LPBYTE szCurrentItem; DWORD dwNestedItems = 0; do { // Load the whole item LoadFullItem(); // Increment this because we are inside an item dwNestedItems++; // Initialize to the current Item szCurrentItem = GetCurrentItem(); // Scan for terminator // See if this is the end of an item if ( XMLFile.GetChar(szCurrentItem) == '/' ) { // This item is in the form , so it is the end of an item that // was opened earlier, we have to subtract 2, one for the current item // and one that was for the start of this one ASSERT(dwNestedItems >= 2); dwNestedItems -= 2; } // Move to next item szEnd = FindNextItem(szCurrentItem,TRUE); if (!szEnd) { // We could not find the end, so we couldn't delete it return FALSE; } // See if this item self terminate (ie. ) while ( ( szEnd != GetCurrentItem() ) && ( XMLFile.GetPrevChar(szEnd) != '>' ) ) { // continue on } if ( ( XMLFile.GetChar(szEnd) == '>' ) && ( szEnd != GetCurrentItem() ) && ( XMLFile.GetPrevChar(szEnd) == '/' ) ) { // We have found an item that self terminates, so we can // decrement the counter (ie. ASSERT(dwNestedItems>0); dwNestedItems--; } // Delete current item szEnd = FindNextItem(GetCurrentItem(),FALSE); if (!szEnd) { return FALSE; } szBegin = FindBeginingofItem( GetCurrentItem() ); MoveData(szBegin, (DWORD) (DWORD_PTR) (szBegin - szEnd) ); szBegin = FindNextItem(szBegin,TRUE); if (!szBegin) { return FALSE; } SetCurrentItem(szBegin); } while ( dwNestedItems > 0 ); return TRUE; } BOOL CXMLEdit::DeleteValue() { // Not yet implemented ASSERT(FALSE); return FALSE; } BOOL CXMLEdit::DeleteProperty() { LPBYTE szTemp; LoadFullItem(); szTemp = SkipString( GetCurrentProperty() ); if ( XMLFile.GetChar(szTemp) == '=' ) { // Skip the Value for this also XMLFile.GetNextChar(szTemp); szTemp = SkipString(szTemp); } if ( XMLFile.GetChar(szTemp) != '\0' ) { XMLFile.MoveData( GetCurrentProperty(), (INT) ( GetCurrentProperty() - szTemp ) ); return TRUE; } return FALSE; } // function: ReplaceString // // Replace a string at a given location, with another string // that is passed in. // // Parameters: // szLocation - The location of the variable to change // szNewValue - The new string to replace it with // // Return // TRUE - It succeeded // FLASE - It failed BOOL CXMLEdit::ReplaceString(LPBYTE szLocation, LPTSTR szNewValue) { LPBYTE szTemp; LPBYTE szOldCurrentItem = GetCurrentItem(); LoadFullItem(); if ( szOldCurrentItem != GetCurrentItem() ) { // Current Item has moved, so we must update the szLocation Pointer szLocation = szLocation - (szOldCurrentItem - GetCurrentItem()); } // Skip to the begining of the next string szTemp = SkipString( szLocation, FALSE ); if ( XMLFile.GetChar(szTemp) != '\0' ) { MoveData( szLocation, (INT) ( _tcslen(szNewValue) - ( szTemp - szLocation ) ) ); XMLFile.CopyString( szLocation, szNewValue); return TRUE; } return FALSE; } // function: ReplaceItem // // Replace a item name at the CurrentItem() // // Parameters // szNewItem - The new name item to add // BOOL CXMLEdit::ReplaceItem(LPTSTR szNewItem) { return ReplaceString(GetCurrentItem(),szNewItem); } // function: ReplaceProperty // // Replace a property name at the property CurrentProperty() // // Parameters // szProp - The new name for the property // BOOL CXMLEdit::ReplaceProperty(LPTSTR szNewProp) { return ReplaceString(GetCurrentProperty(),szNewProp); } // function: ReplaceValue // // Replace a property name at the property CurrentProperty() // // Parameters // szNewValueProp - The new name for the property // BOOL CXMLEdit::ReplaceValue(LPTSTR szNewValue) { if (GetCurrentProperty() == GetCurrentValue()) { // There is no value, so we will not replace the property // by mistkae return FALSE; } if (*szNewValue != '"') { BUFFER buffValue; if (buffValue.Resize((_tcslen(szNewValue) + 3) * sizeof(TCHAR))) // 3 chars = '"' + '"' + '\0' { // Copy the string with quotes around it. _tcscpy((LPTSTR) buffValue.QueryPtr(), _T("\"")); _tcscat((LPTSTR) buffValue.QueryPtr(), szNewValue); _tcscat((LPTSTR) buffValue.QueryPtr(), _T("\"")); return ReplaceString(GetCurrentValue(),(LPTSTR) buffValue.QueryPtr()); } return FALSE; } else { return ReplaceString(GetCurrentValue(),szNewValue); } } // function: IsEqual // // Compares a Unicode and ANSI String to see if they are equal // // Note: This works on ANSI Strings, but will not work on DBCS // Strings! // Note: Termination character for this function is either a // '\0', ' ', or '\t' // // Parameters: // szWideString - Wide Char String // szAnsiString - An Ansi String // // Return: // TRUE - They are equal // FALSE - They are not equal BOOL CXMLEdit::IsEqual(LPCWSTR szWideString, LPCSTR szAnsiString) { if (*szWideString == '"') { // If the string is inside quotes, do not use that in the comparison szWideString++; } if (*szAnsiString == '"') { // If the string is inside quotes, do not use that in the comparison szAnsiString++; } while ( *szWideString && *szAnsiString && (*szWideString == *szAnsiString) ) { szWideString++; // Increment 1 character (2 bytes) szAnsiString++; // Increment 1 character (1 byte ) } if ( ( IsTerminator ( *szWideString ) || ( *szWideString == '"' ) ) && ( IsTerminator ( *szAnsiString ) || ( *szAnsiString == '"' ) ) ) { // We have made it throught the string, and all the // chars were equal return TRUE; } return FALSE; } // function: IsEqual // // Compares two unicode strings, or two ansi strings // // Note: This works on ANSI Strings, but will not work on DBCS // Strings! // Note: Termination character for this function is either a // '\0', ' ', or '\t' // // Parameters: // szString1 - String to Compare // szString2 - String to Compare // // Return: // TRUE - They are equal // FALSE - They are not equal BOOL CXMLEdit::IsEqual(LPCTSTR szString1, LPCTSTR szString2) { if (*szString1 == '"') { // If the string is inside quotes, do not use that in the comparison szString1++; } if (*szString2 == '"') { // If the string is inside quotes, do not use that in the comparison szString2++; } while ( *szString1 && *szString2 && (*szString1 == *szString2) ) { szString1++; // Increment 1 character (2 bytes) szString2++; // Increment 1 character (1 byte ) } if ( ( IsTerminator ( *szString1 ) || ( *szString1 == '"' ) ) && ( IsTerminator ( *szString2 ) || ( *szString2 == '"' ) ) ) { // We have made it throught the string, and all the // chars were equal return TRUE; } return FALSE; } // function: IsEqual // // Compare a LPBYTE string of type XMLFile.IsUnicode() with // a LPTSTR // // Parameters: // szGenericString - The string from our internal buffer // szTCHARString - The string to compare with from the user // // Return: // TRUE - They are the same // FALSE - They are different // BOOL CXMLEdit::IsEqual(LPBYTE szGenericString, LPCTSTR szTCHARString) { if ( (!szGenericString) || (!szTCHARString) ) { // No item to compare it with return FALSE; } #if defined(UNICODE) || defined(_UNICODE) // For UNICODE, szItemName is Unicode if ( XMLFile.IsUnicode() ) { // Both are Unicode return ( IsEqual( szTCHARString, (LPWSTR) szGenericString ) == 0 ); } else { // szGenericString is Unicode, szCurrentItem is ANSI return ( IsEqual( szTCHARString , (LPSTR) szGenericString ) ); } #else // For !UNICODE, szItemName is ANSI if ( XMLFile.IsUnicode() ) { // szGenericString is ANSI, szCurrentItem is Unicode return ( IsEqual( (LPWSTR) szGenericString, szTCHARString ) ); } else { // Both are ANSI return ( IsEqual( (LPSTR) szGenericString, szTCHARString ) == 0 ); } #endif } // function: IsEqualItem // // Compares the CurrentItem Name to the one passed in // // Paramters: // szItemName - The ItemName to compare with // BOOL CXMLEdit::IsEqualItem(LPCTSTR szItemName) { return IsEqual( GetCurrentItem(), szItemName ); } // function: IsPropertyItem // // Compares the CurrentProperty Name to the one passed in // // Paramters: // szItemName - The ItemName to compare with // BOOL CXMLEdit::IsEqualProperty(LPCTSTR szPropertyName) { return IsEqual( GetCurrentProperty(), szPropertyName ); } // function: IsEqualValue // // Compares the CurrentValue to the one passed in // // Paramters: // szValue - The value to coompare with // BOOL CXMLEdit::IsEqualValue(LPCTSTR szValue) { return IsEqual( GetCurrentValue(), szValue ); } // function: CXML_Metabase_Upgrade::MethodName // LPTSTR CXML_Metabase_Upgrade::GetMethodName() { return _T("XML_Metabase_Upgrade"); } // function: CXML_Base::ParseFile // // Upgrade the XML Metabase/Schema to a format that the new // Configuration store will be happy with, and not report // any errors to the pesky Event Log // // Parameters // szFile - The file to parse // ciList - The parameters to use, they consist of: // 0 - The name of the Item // 1 - Items==2 -> New name of item | Items > 2 -> Name of Property // 2 - Items==3 -> New name of property | Items > 3 -> Value to look for // 3 - Items==4 -> New Value | Items > 4 -> Name of Next Property to Check // 4 - Items==5 -> New Value for last prop | Items > 5 -> Name of the Next Value to look for // etc. // // Note: // 1) A '*' as an item name, property name, or value means to replace no matter // what it is // 2) A '*' for a replacement character means to remove that item/property/value // 3) A '**' for a replacement character means to remove the whole item // // Return Value: // TRUE - It worked correctly // FALSE - It failed BOOL CXML_Base::ParseFile(LPTSTR szFile, CItemList &ciList) { CXMLEdit XMLFile; CItemList *pList; DWORD i; // Create array of ItemLists pList = new (CItemList[ciList.GetNumberOfItems()]); if ( pList == NULL ) { // Could not allocation memory needed for ItemList return FALSE; } for (i = 0; i < ciList.GetNumberOfItems(); i++) { if ( ( !pList[i].LoadSubList( ciList.GetItem(i) ) ) || ( pList[i].GetNumberOfItems() < 2 ) ) { // Could not load one of the items delete [] pList; return FALSE; } } // Open the metabase, to modify it if (!XMLFile.Open(szFile,TRUE)) { delete [] pList; return FALSE; } while (XMLFile.MovetoNextItem()) { // Look for Item in replace list for (i = 0; i < ciList.GetNumberOfItems(); i++) { // Is the item equal to this if ( XMLFile.IsEqualItem( pList[i].GetItem(0) ) || ( ( *pList[i].GetItem(0) == '*' ) && ( *(pList[i].GetItem(0)+1) == '\0' ) ) ) { if ( pList[i].GetNumberOfItems() == 2 ) { // There is only 2 items, so the second item is the new name for the item, so replace/delete it if ( ( *pList[i].GetItem(1) == '*' ) && ( *(pList[i].GetItem(1)+1) == '\0' ) ) { XMLFile.DeleteItem(); } else { XMLFile.ReplaceItem( pList[i].GetItem(1) ); } } else { // The item is found, check the properties... XMLFile.MovetoFirstProperty(); do { if ( XMLFile.IsEqualProperty( pList[i].GetItem(1) ) || ( ( *pList[i].GetItem(1) == '*' ) && ( *(pList[i].GetItem(1)+1) == '\0' ) ) ) { // We have found a match of the property also if ( pList[i].GetNumberOfItems() == 3 ) { // There are 3 items, so replace/delete the property name with this if ( ( *pList[i].GetItem(2) == '*' ) && ( *(pList[i].GetItem(2)+1) == '\0' ) ) { XMLFile.DeleteProperty(); } else if ( ( *pList[i].GetItem(2) == '*' ) && ( *(pList[i].GetItem(2)+1) == '*' ) && ( *(pList[i].GetItem(2)+2) == '\0' ) ) { XMLFile.DeleteItem(); // Since we removed the item, we must jump out of the property checking break; } else { XMLFile.ReplaceProperty( pList[i].GetItem(2) ); } } else { // Check value to make sure it is the same if ( XMLFile.IsEqualValue( pList[i].GetItem(2) ) || ( ( *pList[i].GetItem(2) == '*' ) && ( *(pList[i].GetItem(2)+1) == '\0' ) ) ) { DWORD dwCurrentProp = 3; BOOL bContinue = TRUE; while ( (pList[i].GetNumberOfItems() > (dwCurrentProp + 1) ) && ( bContinue ) ) { XMLFile.MovetoFirstProperty(); bContinue = FALSE; do { // compare the current property and value if ( ( ( ( *pList[i].GetItem(dwCurrentProp) == '*' ) && ( *(pList[i].GetItem(dwCurrentProp)+1) == '\0' ) ) || // Compare Property XMLFile.IsEqualProperty( pList[i].GetItem(dwCurrentProp) ) ) && ( ( ( *pList[i].GetItem(dwCurrentProp+1) == '*' ) && ( *(pList[i].GetItem(dwCurrentProp+1)+1) == '\0' ) ) || // Compare Value XMLFile.IsEqualValue( pList[i].GetItem(dwCurrentProp+1) ) ) ) { // If we have found a match for both property and value, then lets continue bContinue = TRUE; break; } } while (XMLFile.MovetoNextProperty()); dwCurrentProp += 2; } if (bContinue) { // The item, property, and value are correct, so replace/delete it if ( ( *pList[i].GetItem(dwCurrentProp) == '*' ) && ( *(pList[i].GetItem(dwCurrentProp)+1) == '\0' ) ) { XMLFile.DeleteValue(); } else if ( ( *pList[i].GetItem(dwCurrentProp) == '*' ) && ( *(pList[i].GetItem(dwCurrentProp)+1) == '*' ) && ( *(pList[i].GetItem(dwCurrentProp)+2) == '\0' ) ) { XMLFile.DeleteItem(); // Since we removed the item, we must jump out of the property checking break; } else { XMLFile.ReplaceValue( pList[i].GetItem(dwCurrentProp) ); } } break; } } // if ( pList[i]->GetNumberofItems() == 3 ) } // if ( XMLFile.IsEqualProperty( pList[i]->GetItem(1) ) || } while (XMLFile.MovetoNextProperty()); } // if ( pList[i]->GetNumberofItems() == 2 ) } // if ( XMLFile.IsEqualItem( pList[i]->GetItem(0) ) || } // for (i = 0; i < ciList.GetNumberOfItems(); i++) } // while (XMLFile.MovetoNextItem()) XMLFile.Close(); delete [] pList; return TRUE; } // function: CXML_Metabase_Upgrade::DoInternalWork // // Upgrade the XML Metabase to a format that the new // Configuration store will be happy with, and not report // any errors to the pesky Event Log // // Return Value: // TRUE - It worked correctly // FALSE - It failed // BOOL CXML_Metabase_Upgrade::DoInternalWork(CItemList &ciList) { TSTR strMetabasePath; if ( !GetMetabasePath( &strMetabasePath ) ) { return FALSE; } return ParseFile( strMetabasePath.QueryStr() , ciList); } // function: CXML_MBSchema_Upgrade::DoInternalWork // // Upgrade the XML MBSchema to a format that the new // Configuration store will be happy with, and not report // any errors to the pesky Event Log // // Return Value: // TRUE - It worked correctly // FALSE - It failed // BOOL CXML_MBSchema_Upgrade::DoInternalWork(CItemList &ciList) { TSTR strMBSchemaPath; if ( !GetSchemaPath( &strMBSchemaPath ) ) { return FALSE; } return ParseFile( strMBSchemaPath.QueryStr() , ciList); } // function: CXML_MBSchema_Upgrade::MethodName // LPTSTR CXML_MBSchema_Upgrade::GetMethodName() { return _T("XML_MBSchema_Upgrade"); } // function: GetMetabasePath // // Retrieve the path to the metabase // // Parameters // pstrPath - [OUT] The complete path to the metabase. (assumed to be og // _MAX_PATH size) BOOL CXML_Base::GetMetabasePath(TSTR *pstrPath) { DWORD dwReturn; if ( !pstrPath->Resize( MAX_PATH ) ) { return FALSE; } dwReturn = GetSystemDirectory( pstrPath->QueryStr(), pstrPath->QuerySize() ); if ( ( dwReturn == 0 ) || ( dwReturn > pstrPath->QuerySize() ) ) { // Function failed, or path was too long to append filename return FALSE; } if ( !pstrPath->Append( CXMLBASE_METABASEPATH ) ) { return FALSE; } return TRUE; } // function: GetSchemaPath // // Retrieve the path to the metabase schema // // Parameters // pstrPath - [OUT] The complete path to the metabase. (assumed to be og // _MAX_PATH size) BOOL CXML_Base::GetSchemaPath(TSTR *pstrPath) { DWORD dwReturn; if ( !pstrPath->Resize( MAX_PATH ) ) { return FALSE; } dwReturn = GetSystemDirectory( pstrPath->QueryStr(), pstrPath->QuerySize() ); if ( ( dwReturn == 0 ) || ( dwReturn > pstrPath->QuerySize() ) ) { // Function failed, or path was too long to append filename return FALSE; } if ( !pstrPath->Append( CXMLBASE_MBSCHEMAPATH ) ) { return FALSE; } return TRUE; } // function: GetMethodName // // Return the method name for this class LPTSTR CXML_Metabase_VerifyVersion::GetMethodName() { return ( _T("XML_Metabase_VerifyVersion") ); } // function: GetMethodName // // Return the method name for this class LPTSTR CXML_MBSchema_VerifyVersion::GetMethodName() { return ( _T("XML_MBSchema_VerifyVersion") ); } // function: VerifyParameters: // // Verify that the parameters are correct fo VerifyVersion BOOL CXML_Metabase_VerifyVersion::VerifyParameters(CItemList &ciParams) { if ( ( ciParams.GetNumberOfItems() == 2 ) && ciParams.IsNumber(0) && ciParams.IsNumber(1) ) { return TRUE; } return FALSE; } // function: VerifyParameters: // // Verify that the parameters are correct fo VerifyVersion BOOL CXML_MBSchema_VerifyVersion::VerifyParameters(CItemList &ciParams) { if ( ( ciParams.GetNumberOfItems() == 2 ) && ciParams.IsNumber(0) && ciParams.IsNumber(1) ) { return TRUE; } return FALSE; } // function: IsFileWithinVersion // // Verify the a file is with a certain version. This is done by paring the xml of the file, // extrapulation the verion, and making sure it is withing the bounds // // Parameters // szFileName - The name of the xml file // szItemName - The name of the item to search for // szPropName - The name of the property that contains the version // dwMinVer - The minimum version for it to return true // dwMaxVer - The maximum version for it to return true BOOL CXML_Base::IsFileWithinVersion(LPTSTR szFileName, LPTSTR szItemName, LPTSTR szPropName, DWORD dwMinVer, DWORD dwMaxVer) { CXMLEdit XMLFile; BOOL bFound = FALSE; BOOL bRet = FALSE; if (!XMLFile.Open(szFileName, FALSE)) { return FALSE; } while ( XMLFile.MovetoNextItem() && !bFound ) { // Look for the configuration tag if (XMLFile.IsEqualItem( szItemName )) { XMLFile.MovetoFirstProperty(); do { // Look for the xmlns tag that mentions the version # if (XMLFile.IsEqualProperty( szPropName ) ) { DWORD dwVersion = XMLFile.ExtractVersion( XMLFile.GetCurrentValue() ); bFound = TRUE; if ( ( dwMinVer >= dwMinVer ) && ( dwMaxVer <= dwMaxVer ) ) { bRet = TRUE; } } } while ( XMLFile.MovetoNextProperty() && !bFound ); } } XMLFile.Close(); return bRet; } // function: CXML_Metabase_VerifyVersion::DoInternalWork // // Verify the versions are within the bounds that are sent in, so we // know wether we should execure the next command or not, by returning // TRUE or FALSE // // Parameters: // ciList - // 0 -Minimum Bound // 1- Max Bound BOOL CXML_Metabase_VerifyVersion::DoInternalWork(CItemList &ciList) { TSTR strMetabasePath; if ( !GetMetabasePath( &strMetabasePath ) ) { return FALSE; } return IsFileWithinVersion( strMetabasePath.QueryStr(), // Filename _T("configuration"), // Item name _T("xmlns"), // Property Name ciList.GetNumber(0), // Min ciList.GetNumber(1) // Max ); } // function: CXML_MBSchema_VerifyVersion::DoInternalWork // // Verify the versions are within the bounds that are sent in, so we // know wether we should execure the next command or not, by returning // TRUE or FALSE // // Parameters: // ciList - // 0 -Minimum Bound // 1- Max Bound BOOL CXML_MBSchema_VerifyVersion::DoInternalWork(CItemList &ciList) { TSTR strSchemaPath; if ( !GetSchemaPath( &strSchemaPath ) ) { return FALSE; } return IsFileWithinVersion( strSchemaPath.QueryStr(), // Filename _T("MetaData"), // Item name _T("xmlns"), // Property Name ciList.GetNumber(0), // Min ciList.GetNumber(1) // Max ); } // function: ExtractVersion // // Extract the Version number out of a string extracted from the metabase // // Parameters // szVersion - String version, such as "urn:microsoft-catalog:XML_Metabase_V1_0" // // RETURN // A Verison # DWORD CXMLEdit::ExtractVersion(LPBYTE szVersion) { DWORD dwVer = 0; if (!szVersion) { return 0; } while ( !IsTerminator(XMLFile.GetChar(szVersion)) ) { if ( XMLFile.GetChar(szVersion) == '_' ) { XMLFile.GetNextChar(szVersion); if ( XMLFile.GetChar(szVersion) == 'V' ) { XMLFile.GetNextChar(szVersion); break; } } else { XMLFile.GetNextChar(szVersion); } } if (IsTerminator(XMLFile.GetChar(szVersion)) ) { return FALSE; } while ( ( XMLFile.GetChar(szVersion) >= '0' ) && ( XMLFile.GetChar(szVersion) <= '9' ) ) { dwVer = dwVer + ( XMLFile.GetChar(szVersion) - '0' ); XMLFile.GetNextChar(szVersion); } return dwVer; }