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.
462 lines
13 KiB
462 lines
13 KiB
#include <iostream.h>
|
|
#include <assert.h>
|
|
#include <windows.h>
|
|
#include "types.h"
|
|
#include "array.hxx"
|
|
|
|
extern bool g_fWriteToStdOut;
|
|
|
|
//
|
|
//
|
|
//
|
|
bool
|
|
CompareBuffer(char* pBuff1, char* pBuff2, unsigned long nLen)
|
|
{
|
|
for ( unsigned long i=0; i<nLen; i++ )
|
|
if (pBuff1[i] != pBuff2[i])
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
CompareBufferNoCase( char* pBuff1, char* pBuff2, unsigned long nLen)
|
|
{
|
|
// or ing with 0x20 always gives the lower case for ASCII characters.
|
|
// this way we can compare case insensitive.
|
|
for ( unsigned long i=0; i<nLen; i++ )
|
|
if ( (pBuff1[i]|0x20) != (pBuff2[i]|0x20) )
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
void
|
|
WriteLine(HANDLE file, char* pBuff, int nLen)
|
|
{
|
|
DWORD dwSize;
|
|
char szBuff[2] = {0x0d, 0x0a};
|
|
|
|
if (-1 == nLen)
|
|
{
|
|
nLen = lstrlen( pBuff );
|
|
}
|
|
|
|
WriteFile(file, pBuff, nLen, &dwSize, NULL);
|
|
WriteFile(file, &szBuff, 2, &dwSize, NULL);
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
unsigned long
|
|
FindEndOfLine( char* pBuff )
|
|
{
|
|
char* pWalk = pBuff;
|
|
|
|
while ( *pWalk != 0x0d )
|
|
pWalk++;
|
|
|
|
return ((unsigned long)(pWalk-pBuff));
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
bool
|
|
GetLine(HANDLE file, char** ppTarget)
|
|
{
|
|
//buffer
|
|
char* pchBuff;
|
|
unsigned long ulBuffIdx;
|
|
unsigned long ulBuffSize = SZ;
|
|
|
|
// Read variables
|
|
DWORD dwRead=0;
|
|
BOOL bRes;
|
|
|
|
//allocate the initial buffer
|
|
pchBuff = new char[ulBuffSize];
|
|
|
|
//if we are currently positioned at wherever the previous
|
|
//operation left us, skip the carriage returns and
|
|
//get to the real data.
|
|
pchBuff[0] = 0x0d;
|
|
while (( pchBuff[0] == 0x0d ) || ( pchBuff[0] == 0x0a ))
|
|
{
|
|
bRes = ReadFile( (HANDLE)file, pchBuff, 1, &dwRead, NULL);
|
|
if ( !bRes || !dwRead )
|
|
return false;
|
|
}
|
|
|
|
|
|
//get the buffer until you reach the terminating character.
|
|
//the first character of the buffer is filled. ulBuffIdx always points
|
|
//to the char. to be read.
|
|
ulBuffIdx = 1;
|
|
|
|
BOOL fContinue = true;
|
|
|
|
while( fContinue )
|
|
{
|
|
bRes = ReadFile( (HANDLE)file, &pchBuff[ulBuffIdx], 1, &dwRead, NULL);
|
|
|
|
if ( !bRes || !dwRead )
|
|
return false;
|
|
|
|
//was this the terminating character?
|
|
if ( pchBuff[ulBuffIdx] == 0x0A )
|
|
{
|
|
fContinue = false;
|
|
}
|
|
|
|
ulBuffIdx++; //always point to the character to be read.
|
|
|
|
//did we reach the end of the buffer? If so, enlarge buffer
|
|
if ( 0 == (ulBuffIdx % SZ) )
|
|
{
|
|
//allocate new memory chunk
|
|
char* pTmp = new char[ulBuffSize+SZ];
|
|
|
|
//copy data
|
|
memcpy( pTmp, pchBuff, ulBuffSize);
|
|
|
|
//release old memory
|
|
delete [] pchBuff;
|
|
|
|
//make the new chunk the current one
|
|
pchBuff = pTmp;
|
|
ulBuffSize += SZ;
|
|
}
|
|
}
|
|
|
|
pchBuff[ulBuffIdx-2] = 0;
|
|
|
|
//if there is a receiving pointer and it is
|
|
//initialized to NULL properly
|
|
if ((ppTarget) && (*ppTarget==NULL))
|
|
{
|
|
*ppTarget = pchBuff;
|
|
}
|
|
else
|
|
{
|
|
//since there are no valid receivers of the buffer,
|
|
//we can delete it.
|
|
delete [] pchBuff;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function : GetBlockType
|
|
// Description : Get a block of memory that is the first line
|
|
// of a block, and determine the block type, by
|
|
// checking the first characters on the line
|
|
// Parameters :
|
|
// char* : pointer to the buf. that contains the line
|
|
//
|
|
// Returns : Returns the type of the block ( enumeration BLOCK_TYPE)
|
|
//----------------------------------------------------------------------------
|
|
BLOCK_TYPE
|
|
GetBlockType( char* pchData, char* pchTerm )
|
|
{
|
|
assert( pchData );
|
|
assert( pchTerm );
|
|
|
|
switch (*pchData)
|
|
{
|
|
case 'd':
|
|
*pchTerm = '}'; //end of block
|
|
return BLK_DISPINT;
|
|
break;
|
|
|
|
case 'i':
|
|
*pchTerm = '}'; //end of block
|
|
return BLK_INTERFACE;
|
|
break;
|
|
|
|
case 'c':
|
|
*pchTerm = '}'; //end of block
|
|
return BLK_COCLASS;
|
|
break;
|
|
|
|
case 't':
|
|
*pchTerm = ';'; //end of type definition
|
|
return BLK_TYPEDEF;
|
|
break;
|
|
|
|
case '[':
|
|
*pchTerm = ']'; //end of attribute
|
|
return BLK_ATTR;
|
|
break;
|
|
|
|
default:
|
|
*pchTerm = 0x0a; //end of line
|
|
return BLK_NONE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
bool
|
|
GetBlock(HANDLE file, INDEX* pIdx, char** ppTarget = NULL, unsigned long* pulBlockBase = NULL )
|
|
{
|
|
char * pchBuff; //buffer
|
|
unsigned long ulBuffIdx; //walking pointer
|
|
unsigned long ulBuffBase; //end of the last memory chunk.
|
|
unsigned long ulBlockBase; //beginning of the actual block,
|
|
|
|
//after the funny characters are skipped
|
|
unsigned long ulBuffSize = SZ+1; // the extra character is for the NULL termination.
|
|
unsigned long ulLines = 0;
|
|
BOOL fContinue = TRUE;
|
|
|
|
//read variables
|
|
DWORD dwRead=0;
|
|
BOOL bRes;
|
|
char chTerm;
|
|
|
|
assert(pIdx);
|
|
|
|
if ( ppTarget )
|
|
*ppTarget = NULL; //reset the pointer to be returned.
|
|
|
|
//allocate the initial buffer
|
|
pchBuff = new char[ulBuffSize];
|
|
ulBuffBase = ulBuffIdx = ulBlockBase = 0;
|
|
|
|
//we are currently positioned at wherever the previous
|
|
//operation left us. learn where we are and start to read.
|
|
pIdx->ulStartPos = SetFilePointer( (HANDLE)file, 0, NULL, FILE_CURRENT);
|
|
|
|
while( fContinue )
|
|
{
|
|
//read a block from the file.
|
|
bRes = ReadFile( (HANDLE)file, &pchBuff[ulBuffIdx], SZ, &dwRead, NULL);
|
|
|
|
//if there was a failure or we had reached the end of the file.
|
|
if ( !bRes || !dwRead )
|
|
return false;
|
|
|
|
//skip the possible 0d 0a sequences at the beginning and process the rest of
|
|
//the message.
|
|
if ( ulBuffIdx== 0 )
|
|
{
|
|
while((pchBuff[ulBuffIdx] == 0x0D ) ||
|
|
( pchBuff[ulBuffIdx] == 0x0A ) ||
|
|
( pchBuff[ulBuffIdx] == 0x20 ))
|
|
{
|
|
ulBuffIdx++; //read position in the buffer
|
|
ulBlockBase++; //increment the buffer base position.
|
|
pIdx->ulStartPos++; //start position in the file.
|
|
}
|
|
|
|
//if we reached the end of file by doing this, return. There is nothing left.
|
|
if (dwRead==ulBuffIdx)
|
|
return false;
|
|
|
|
//now we are pointing to the actual data, learn the terminating
|
|
//character and terminate this loop.
|
|
pIdx->blockType = GetBlockType(&pchBuff[ulBuffIdx], &chTerm);
|
|
}
|
|
|
|
//walk until you reach the terminating character or the end of the read buffer
|
|
while ((ulBuffIdx<(ulBuffBase+dwRead)) && (pchBuff[ulBuffIdx] != chTerm))
|
|
{
|
|
//check for the 0x0A to determine the number of lines
|
|
//the linefeed after the chTerm is found is taken care of
|
|
//in the spin routine for the empty lines.
|
|
if (pchBuff[ulBuffIdx] == 0x0A )
|
|
ulLines++;
|
|
|
|
ulBuffIdx++;
|
|
}
|
|
|
|
//did we reach the end of the buffer or found the chTerm character
|
|
if (ulBuffIdx == ulBuffSize - 1)
|
|
{
|
|
char* pTmp = new char[ulBuffSize+SZ]; //allocate new memory chunk
|
|
memcpy( pTmp, pchBuff, ulBuffSize); //copy data
|
|
delete [] pchBuff; //release old memory
|
|
pchBuff = pTmp; //make the new chunk the current one
|
|
ulBuffSize += SZ; //adjust the buffer size
|
|
ulBuffBase = ulBuffIdx; //reset the base to the current limit
|
|
}
|
|
else
|
|
{
|
|
//we found the terminating character.
|
|
ulBuffIdx++; //always point to the character to be read next.
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Subtract the block base, If there were 0d0a pairs, we incremented both
|
|
// ulStartPos and ulBuffIdx, and doubled the effect of the skipping these
|
|
// characters. Compensation is provided by -ulBlockBase ...
|
|
pIdx->ulEndPos = pIdx->ulStartPos + ulBuffIdx - ulBlockBase;
|
|
|
|
// If the terminating character was a line break, we don't want it to go
|
|
// into the record as a part of this line
|
|
if ( chTerm == 0x0a )
|
|
{
|
|
pIdx->ulEndPos -= 2;
|
|
ulBuffIdx -= 2;
|
|
}
|
|
|
|
// Reset the pointer to the end of this block.
|
|
SetFilePointer( (HANDLE)file, pIdx->ulEndPos, NULL, FILE_BEGIN);
|
|
|
|
// Terminate the buffer, since the index always shows the next
|
|
// position available, subtract 1 from the index.
|
|
pchBuff[ulBuffIdx] = 0;
|
|
|
|
// If there is a receiving pointer and it is
|
|
// initialized to NULL properly
|
|
if ((ppTarget) && (*ppTarget==NULL) && (pulBlockBase))
|
|
{
|
|
*ppTarget = pchBuff;
|
|
*pulBlockBase = ulBlockBase;
|
|
}
|
|
else
|
|
{
|
|
// Since there are no valid receivers of the buffer,
|
|
// we can delete it.
|
|
delete [] pchBuff;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Compare two attribute blocks. Attribute blocks are placed before interface descriptions
|
|
// and coclass descriptions.
|
|
// dual --> breaker for both coclass and interface if added/removed
|
|
// uuid(...) --> breaker for interfaces of all kinds if the contents of the uuid is changed
|
|
//
|
|
// Return Value:
|
|
// The return value from this function 0 if there are no differences between these two blocks
|
|
// otherwise an error code is returned.
|
|
|
|
long
|
|
CompareAttributeBlock( char * pRefBuf,
|
|
CAutoArray<ATTRINFO>* pRefList,
|
|
char * pCurBuf,
|
|
CAutoArray<ATTRINFO>* pCurList)
|
|
{
|
|
char szDual[] = {"dual"};
|
|
char szUuid[] = {"uuid"};
|
|
char * pszAttr;
|
|
ATTRINFO attrCur, attrRef;
|
|
int i, j, k;
|
|
long lErr;
|
|
|
|
|
|
// For all of the attributes that are in the reference list, if the attribute is one of
|
|
// the attributes that we care about, we will make sure that the current list contains
|
|
// the same attribute.
|
|
for ( i=0; i < pRefList->Size(); i++ )
|
|
{
|
|
pRefList->GetAt(i, &attrRef);
|
|
|
|
if (attrRef.ulAttrLength == 4)
|
|
{
|
|
pszAttr = szDual;
|
|
lErr = CHANGE_DUALATTRREMOVED;
|
|
}
|
|
else if (attrRef.ulAttrLength == 42)
|
|
{
|
|
pszAttr = szUuid;
|
|
lErr = CHANGE_UUIDHASCHANGED;
|
|
}
|
|
else
|
|
continue;
|
|
|
|
assert(pszAttr);
|
|
|
|
// is this attribute one of those that we want to check for?
|
|
for (j=0; j<4; j++)
|
|
if( pszAttr[j] != pRefBuf[attrRef.ulAttrStart+j])
|
|
break;
|
|
|
|
// We don't want to compare this attribute.
|
|
if (j != 4)
|
|
continue;
|
|
|
|
// we care about this attribute. It MUST be in the current attribute block
|
|
for (k=0; k < pCurList->Size(); k++)
|
|
{
|
|
pCurList->GetAt(k, &attrCur);
|
|
|
|
if ((!attrCur.fUsed) &&
|
|
(0 == memcmp( pRefBuf+attrRef.ulAttrStart,
|
|
pCurBuf+attrCur.ulAttrStart,
|
|
attrRef.ulAttrLength)))
|
|
{
|
|
// if the attribute is found, then mark the current list so we skip
|
|
// over this one next time.
|
|
attrCur.fUsed = true;
|
|
pCurList->Set(k, attrCur);
|
|
|
|
// shortcut...
|
|
break;
|
|
}
|
|
}
|
|
|
|
// if we did not find the same attribute, return the error code that is in lErr
|
|
if (k == pCurList->Size())
|
|
return lErr;
|
|
}
|
|
|
|
// check for things that are added to the current list,
|
|
// but don't exist in the reference list. If something we check for is added, this is a breaker.
|
|
for ( i=0; i < pCurList->Size(); i++)
|
|
{
|
|
pCurList->GetAt(i, &attrCur);
|
|
|
|
if (!attrCur.fUsed)
|
|
{
|
|
// only check for "dual" here.
|
|
pszAttr = szDual;
|
|
|
|
for (j=0; j<4; j++)
|
|
if( pszAttr[j] != pCurBuf[attrCur.ulAttrStart+j])
|
|
break;
|
|
|
|
if (j==4)
|
|
return CHANGE_DUALATTRADDED;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
TokenizeAttributes( char* pBuf, unsigned long nCnt, CAutoArray<ATTRINFO>* pList )
|
|
{
|
|
unsigned long i,j;
|
|
ATTRINFO attrInfo;
|
|
|
|
attrInfo.ulAttrStart = 0;
|
|
|
|
// the first attribute is always at 0
|
|
for ( i=0, j=0; i<= nCnt; i++, j++ )
|
|
{
|
|
if ( ( pBuf[i] == ',' ) || (i==nCnt) )
|
|
{
|
|
attrInfo.ulAttrLength = i- attrInfo.ulAttrStart;
|
|
attrInfo.fUsed = false;
|
|
|
|
pList->Append( attrInfo );
|
|
|
|
i += 2;
|
|
|
|
attrInfo.ulAttrStart = i;
|
|
}
|
|
}
|
|
}
|