// -------------------------------------------------------------------------------- // Binxhex.h // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved // Steven J. Bailey // // Copied from \\tdsrc\src1911\mapi\src\imail2\decoder.cpp // Copied from \\tdsrc\src1911\mapi\src\imail2\encoder.cpp // Copied from \\tdsrc\src1911\mapi\src\imail2\_encoder.h // -------------------------------------------------------------------------------- #include "pch.hxx" #include "binhex.h" #include // -------------------------------------------------------------------------------- // Module data // -------------------------------------------------------------------------------- #ifdef MAC const CHAR szBINHEXHDRLINE[] = "(This file must be converted with BinHex 4.0)\n\r\n\r"; #else // !MAC const CHAR szBINHEXHDRLINE[] = "(This file must be converted with BinHex 4.0)\r\n\r\n"; #endif // MAC const ULONG cbBINHEXHDRLINE = lstrlen( szBINHEXHDRLINE ); static BOOL g_bCreatorTypeInit = FALSE; // TRUE ->array initialized sCreatorType * g_lpCreatorTypes = NULL; // ptr.to Creator-Type pairs static int g_cCreatorTypes = 0; // # of Creator-Type pairs // -------------------------------------------------------------------------------- // Prototypes // -------------------------------------------------------------------------------- void CalcCRC16(LPBYTE lpbBuff, ULONG cBuff, WORD * wCRC); BOOL bIsMacFile(DWORD dwCreator, DWORD dwType); VOID ReadCreatorTypes(void); //----------------------------------------------------------------------------- // Name: CBinhexEncoder::CBinhexEncoder // // Description: // Ctor // // Parameters: // Returns: // Effects: // Notes: // Revision: // Initial:9/5/1996 //----------------------------------------------------------------------------- CBinhexEncoder::CBinhexEncoder(void) { m_fConfigured = FALSE; m_cbLineLength = cbLineLengthUnlimited; m_cbLeftOnLastLine = m_cbLineLength; m_cMaxLines = 0; m_cLines = 0; } //----------------------------------------------------------------------------- // Name: CBinhexEncoder::~CBinhexEncoder // Description: // // Parameters: // Returns: // Effects: // Notes: // Revision: // Initial:9/5/1996 //----------------------------------------------------------------------------- CBinhexEncoder::~CBinhexEncoder( void ) { #if defined (DEBUG) && defined (BINHEX_TRACE) if ( m_lpstreamEncodeRLE ) { m_lpstreamEncodeRLE->Commit( 0 ); m_lpstreamEncodeRLE->Release(); } if ( m_lpstreamEncodeRAW ) { m_lpstreamEncodeRAW->Commit( 0 ); m_lpstreamEncodeRAW->Release(); } #endif } //----------------------------------------------------------------------------- // Name: CBinhexEncoder::HrConfig // Description: // // Parameters: // Returns: // Effects: // Notes: // Revision: // Initial:9/5/1996 //----------------------------------------------------------------------------- HRESULT CBinhexEncoder::HrConfig( IN CB cbLineLength, IN C cMaxLines, IN void * pvParms ) { // Is this a repeat call? if (m_fConfigured) { return ERROR_ALREADY_INITIALIZED; } // Objects of this class may have pvParms point to a various additional // configuration values to consider when encoding. if ( pvParms == NULL) { return ERROR_INVALID_PARAMETER; } m_cbLineLength = cbLineLength; m_lpmacbinHdr = (LPMACBINARY)pvParms; m_ulAccum = 0; m_cAccum = 0; m_cbRepeat = 0; m_bRepeat = BINHEX_INVALID; m_wCRC = 0; m_cbFork = 0; m_cbLeftInFork = 0; m_eBinHexStateEnc = sHEADER; m_cbProduced = 0; m_cbConsumed = 0; m_pbWrite = NULL; m_cbLeftInOutputBuffer = 0; m_cbLeftInInputBuffer = 0; m_bPrev = BINHEX_INVALID; m_cbWrite = 0; m_cbLine = 0; m_fHandledx90 = FALSE; m_cbPad = 0; #if defined (DEBUG) && defined (BINHEX_TRACE) { CHAR szFilePath[MAX_PATH]; CHAR szPath[MAX_PATH]; ULONG ulDirLen = 0; HRESULT hr = hrSuccess; ulDirLen = GetPrivateProfileString( "IMAIL2 ITP", "InboundFilePath", "", (LPSTR) szFilePath, sizeof( szFilePath ), "mapidbg.ini"); if ( ulDirLen == 0 ) { // Default to %TEMP%\IMAIL ulDirLen = GetTempPath( sizeof( szFilePath ), szFilePath ); AssertSz( ulDirLen < sizeof( szFilePath), "Temp directory name too long" ); StrCatBuff(szFilePath, "imail", ARRAYSIZE(szFilePath)); ulDirLen = lstrlen(szFilePath); } // Open stream on file for input file StrCatBuff(szFilePath, "\\", ARRAYSIZE(szFilePath)); StrCpyN( szPath, szFilePath, ARRAYSIZE(szPath)); StrCatBuff( szFilePath, "enc_rle.rpt", ARRAYSIZE(szFilePath)); hr = OpenStreamOnFile( MAPIAllocateBuffer, MAPIFreeBuffer, STGM_READWRITE | STGM_CREATE, szFilePath, NULL, &m_lpstreamEncodeRLE ); if ( hr ) AssertSz( FALSE, "Debug encode stream failed to initialize\n" ); StrCpyN (szFilePath, szPath, ARRAYSIZE(szFilePath)); StrCatBuff(szFilePath, "enc_raw.rpt", ARRAYSIZE(szFilePath)); hr = OpenStreamOnFile( MAPIAllocateBuffer, MAPIFreeBuffer, STGM_READWRITE | STGM_CREATE, szFilePath, NULL, &m_lpstreamEncodeRAW ); if ( hr ) AssertSz( FALSE, "Debug encode stream failed to initialize\n" ); } #endif m_fConfigured = fTrue; return ERROR_SUCCESS; } //----------------------------------------------------------------------------- // Name: CBinhexEncoder::HrEmit // Description: // // Parameters: // Returns: // Effects: // // Notes: // Handle Data Fork // Resource fork. // // Revision: // Initial:9/5/1996 //----------------------------------------------------------------------------- HRESULT CBinhexEncoder::HrEmit( IN PB pbRead, IN OUT CB * pcbRead, OUT PB pbWrite, IN OUT CB * pcbWrite ) { HRESULT hr = ERROR_SUCCESS; CB cbHeader = 0; CB cbToProcess; CB cbInputCheckPoint = 0; CB cbOut; CB cb; BYTE rgbHeader[ cbMIN_BINHEX_HEADER_SIZE + 64 ]; m_cbConsumed = 0; m_cbProduced = 0; m_cbLeftInOutputBuffer = 0; m_cbLeftInInputBuffer = 0; // Have to be initialized first if ( !m_fConfigured ) { return ERROR_BAD_COMMAND; } // Handle common 'bad parameter' errors if ( !pbRead || !pbWrite || !pcbRead || !pcbWrite ) { return ERROR_INVALID_PARAMETER; } // Repeated calls after maximum number of output lines were generated // will not go through if ( FMaxLinesReached() ) { *pcbRead = *pcbWrite = 0; return ERROR_SUCCESS; } // If line length is unlimited, set m_cbLeftOnLastLine to be equal to // the length of the input buffer if ( !FLineLengthLimited() ) { m_cbLeftOnLastLine = *pcbWrite; } m_pbWrite = pbWrite; m_cbWrite = *pcbWrite; while ( TRUE ) { m_cbLeftInInputBuffer = *pcbRead - m_cbConsumed; m_cbLeftInOutputBuffer = *pcbWrite - m_cbProduced; // If we have room in the output buffer keep going if in sEnd and no input left if ( 0 == m_cbLeftInOutputBuffer || (0 == m_cbLeftInInputBuffer && sEND != m_eBinHexStateEnc) ) { goto Cleanup; } switch ( m_eBinHexStateEnc ) { case sHEADER: { // Output BinHex Header line CopyMemory( pbWrite, szBINHEXHDRLINE, cbBINHEXHDRLINE ); m_cbProduced += cbBINHEXHDRLINE; m_cLines += 2; // Output leading ':' m_pbWrite[m_cbProduced++] = ':'; ++m_cbLine; // Output MACBIN Header; Header filename length rgbHeader[cbHeader++] = m_lpmacbinHdr->cchFileName; // Header filename CopyMemory( rgbHeader + cbHeader, m_lpmacbinHdr->rgchFileName, m_lpmacbinHdr->cchFileName ); cbHeader += m_lpmacbinHdr->cchFileName; // Null terminate filename rgbHeader[cbHeader++] = '\0'; // Macfile TYPE CopyMemory( rgbHeader + cbHeader, (LPBYTE)&m_lpmacbinHdr->dwType, sizeof(DWORD) ); cbHeader += sizeof(DWORD); // Macfile CREATOR CopyMemory( rgbHeader + cbHeader, (LPBYTE)&m_lpmacbinHdr->dwCreator, sizeof(DWORD) ); cbHeader += sizeof(DWORD); // Macfile FLAGS rgbHeader[cbHeader++] = m_lpmacbinHdr->bFinderFlags; rgbHeader[cbHeader++] = m_lpmacbinHdr->bFinderFlags2; // Macfile Fork lengths CopyMemory( rgbHeader + cbHeader, (LPBYTE)&m_lpmacbinHdr->lcbDataFork, sizeof(DWORD) ); cbHeader += sizeof(DWORD); CopyMemory( rgbHeader + cbHeader, (LPBYTE)&m_lpmacbinHdr->lcbResourceFork, sizeof(DWORD) ); cbHeader += sizeof(DWORD); // Calculate the binhex header CRC CalcCRC16( rgbHeader, cbHeader, &m_wCRC ); CalcCRC16( (LPBYTE)&wZero, sizeof(WORD), &m_wCRC ); rgbHeader[cbHeader++] = HIBYTE( m_wCRC ); rgbHeader[cbHeader++] = LOBYTE( m_wCRC ); // BinHex the header into pbWrite. The initial assumption is that // the buffer is going to big enough to encode the header. // Output goes into m_pbWrite. cbOut = 0; hr = HrBinHexBuffer( rgbHeader, cbHeader, &cbOut ); // setup for the data fork m_eBinHexStateEnc = sDATA; m_cbFork = NATIVE_LONG_FROM_BIG( (LPBYTE)&m_lpmacbinHdr->lcbDataFork ); m_cbLeftInFork = m_cbFork; m_wCRC = 0; } break; case sDATA: { // determine how much we can process cbToProcess = m_cbLeftInFork < m_cbLeftInInputBuffer ? m_cbLeftInFork : m_cbLeftInInputBuffer; cbInputCheckPoint = m_cbConsumed; hr = HrBinHexBuffer( pbRead + cbInputCheckPoint, cbToProcess, &m_cbConsumed ); CalcCRC16( pbRead + cbInputCheckPoint, m_cbConsumed - cbInputCheckPoint, &m_wCRC ); m_cbLeftInFork -= m_cbConsumed - cbInputCheckPoint; // flush output buffer if ( hr ) goto Cleanup; if ( !m_cbLeftInFork ) { // write out the last CRC CalcCRC16( (LPBYTE)&wZero, sizeof(WORD), &m_wCRC ); cbHeader = 0; rgbHeader[cbHeader++] = HIBYTE( m_wCRC ); rgbHeader[cbHeader++] = LOBYTE( m_wCRC ); cbOut = 0; hr = HrBinHexBuffer( rgbHeader, 2, &cbOut ); // discard padding if ( m_cbFork % 128 ) { cb = 128 - ( m_cbFork % 128 ); if ( *pcbRead - m_cbConsumed < cb ) { DebugTrace( "Note: Support refilling input buffer to remove padding for Data\n" ); // need to pull in more data m_cbPad = cb - (*pcbRead - m_cbConsumed); m_cbConsumed -= (*pcbRead - m_cbConsumed); } else { m_cbConsumed = cb; } } // Set up for resource for if there is one and reset counters m_cbFork = NATIVE_LONG_FROM_BIG( (LPBYTE)&m_lpmacbinHdr->lcbResourceFork ); m_cbLeftInFork = m_cbFork; if ( !m_cbFork ) { // handle 0 byte resource fork m_eBinHexStateEnc = sEND; // write out crc for 0 length cbOut = 0; hr = HrBinHexBuffer( (LPBYTE)&wZero, sizeof(WORD), &cbOut ); } else { m_eBinHexStateEnc = sRESOURCE; } m_wCRC = 0; } } break; case sRESOURCE: { if ( m_cbPad ) { m_cbConsumed -= m_cbPad; m_cbPad = 0; } // determine how much we can process cbToProcess = m_cbLeftInFork < m_cbLeftInInputBuffer ? m_cbLeftInFork : m_cbLeftInInputBuffer; cbInputCheckPoint = m_cbConsumed; hr = HrBinHexBuffer( pbRead + cbInputCheckPoint, cbToProcess, &m_cbConsumed ); CalcCRC16( pbRead + cbInputCheckPoint, m_cbConsumed - cbInputCheckPoint, &m_wCRC ); m_cbLeftInFork -= m_cbConsumed - cbInputCheckPoint; // flush output buffer if ( hr ) goto Cleanup; if ( !m_cbLeftInFork ) { // write out the last CRC CalcCRC16( (LPBYTE)&wZero, sizeof(WORD), &m_wCRC ); cbHeader = 0; rgbHeader[cbHeader++] = HIBYTE( m_wCRC ); rgbHeader[cbHeader++] = LOBYTE( m_wCRC ); cbOut = 0; hr = HrBinHexBuffer( rgbHeader, 2, &cbOut ); // discard padding if ( m_cbFork % 128 ) { cb = 128 - ( m_cbFork % 128 ); if ( *pcbRead - m_cbConsumed < cb ) { DebugTrace( "Note: Support refilling input buffer to remove padding for Resource\n" ); // need to pull in more data m_cbPad = cb - (*pcbRead - m_cbConsumed); m_cbConsumed -= (*pcbRead - m_cbConsumed); } else { m_cbConsumed = cb; } } // set up to terminate m_eBinHexStateEnc = sEND; } } break; case sEND: { if ( m_cbPad ) { m_cbConsumed -= m_cbPad; m_cbPad = 0; } if ( (*pcbWrite - m_cbProduced) == 0 ) break; // flush out any repeated chars if ( m_cbRepeat ) { if ( m_cbRepeat > 1 ) { // bump up the repeat count so it reflects actual number of chars to repeat. m_cbRepeat++; // encode the repeat code char // note that we've already emitted the char that we're supplying // the repeat info for. hr = HrBinHexByte( BINHEX_REPEAT ); m_bPrev = BINHEX_REPEAT; Assert( m_cbRepeat <= 255 ); // encode repeat count hr = HrBinHexByte( (BYTE)(m_cbRepeat) ); m_bPrev = (BYTE)(m_cbRepeat); } else { hr = HrBinHexByte( m_bRepeat ); m_bPrev = m_bRepeat; } } // check to see if we have bits in the accumulator if ( m_cAccum ) { switch( m_cAccum ) { case 1: m_pbWrite[m_cbProduced++] = g_rgchBinHex8to6[((m_bPrev & 0x03) << 4)]; break; case 2: m_pbWrite[m_cbProduced++] = g_rgchBinHex8to6[((m_bPrev & 0x0f) << 2)]; break; case 3: m_pbWrite[m_cbProduced++] = g_rgchBinHex8to6[m_bCurr & 0x3f]; break; default: AssertSz( FALSE, "HrBinHexByte: bad shift state\n" ); hr = ERROR_INVALID_PARAMETER; goto Cleanup; } } // tack on terminating ':' m_pbWrite[m_cbProduced++] = ':'; m_cbConsumed = *pcbRead; // probably not so we would have to flush the // bits out. goto Cleanup; } } } Cleanup: if (hr == ERROR_SUCCESS || hr == ERROR_MORE_DATA) { // Check that at least some processing was done. // Also this error is returned if we've exhausted the output // buffer. if ( (m_cbProduced == 0) || (m_cbLeftInInputBuffer > m_cbLeftInOutputBuffer) || (0 == m_cbLeftInOutputBuffer && sEND == m_eBinHexStateEnc) ) { hr = ERROR_INSUFFICIENT_BUFFER; } else if ( m_cbConsumed < *pcbRead ) { // Was all input processed? // Note that it is okay to encode only part of the input buffer // if maximum number of output lines was exceeded. hr = ERROR_MORE_DATA; } } // Report the new sizes to the caller. Assert( m_cbConsumed <= *pcbRead ); Assert( m_cbProduced <= *pcbWrite ); *pcbRead = m_cbConsumed; *pcbWrite = m_cbProduced; return hr; } //----------------------------------------------------------------------------- // Name: CBinhexEncoder::HrBinHexBuffer // // Description: // Output goes into m_pbWrite // // Parameters: // Returns: // Effects: // Notes: // // Revision: // Initial:9/5/1996 //----------------------------------------------------------------------------- HRESULT CBinhexEncoder::HrBinHexBuffer( IN LPBYTE lpbIn, IN CB cbIn, CB * lpcbConsumed ) { HRESULT hr = ERROR_SUCCESS; BOOL fEndRepeat = FALSE; CB cbInUsed = 0; #if defined (DEBUG) && defined (BINHEX_TRACE) CB cbOrigCbIn = cbIn; #endif while ( cbIn && m_cbProduced + 5 < m_cbWrite ) { // process the next char in input buffer m_bCurr = lpbIn[cbInUsed++]; --cbIn; // check to see if we've seen this char before. Don't repeat // if we just added a literal 0x90. if ( m_bCurr == m_bPrev && !m_fHandledx90 ) { // m_cbRepeat is the count of repeat chars after the initial char. // e.g., if there are two repeating chars, m_cbRepeat will be 1. // Note that we've already emitted the char after which to add the repeat // code and count. if ( m_cbRepeat < 254 ) { m_cbRepeat++; m_bRepeat = m_bCurr; continue; } } m_fHandledx90 = FALSE; // we were counting repeating characters and the run stopped. if ( m_cbRepeat > 1 ) { // set up to emit the run length encoding fEndRepeat = TRUE; } // Are we in repeat mode... if ( m_cbRepeat > 1 && fEndRepeat == TRUE ) { // bump up the repeat count so it reflects actual number of chars to repeat. m_cbRepeat++; // if we're repeating 0x90 tack on the trailing 0x00 if ( m_bRepeat == BINHEX_REPEAT ) { hr = HrBinHexByte( '\0' ); } // encode the repeat code char // note that we've already emitted the char that we're supplying // the repeat info for. hr = HrBinHexByte( BINHEX_REPEAT ); Assert( m_cbRepeat <= 255 ); // encode repeat count hr = HrBinHexByte( (BYTE)(m_cbRepeat) ); fEndRepeat = FALSE; m_cbRepeat = 0; } else if ( m_cbRepeat ) // check if we've got two chars to encode. { // encode the one char since we've already emitted // the first one. hr = HrBinHexByte( m_bRepeat ); if ( m_bRepeat == BINHEX_REPEAT ) { hr = HrBinHexByte( '\0' ); } m_cbRepeat = 0; } // special handling for 0x90 chars in stream but 0x90 can repeat if ( m_bCurr == BINHEX_REPEAT && m_bPrev != BINHEX_REPEAT ) { hr = HrBinHexByte( BINHEX_REPEAT ); hr = HrBinHexByte( '\0' ); m_fHandledx90 = TRUE; continue; } // encode the char hr = HrBinHexByte( m_bCurr ); if ( hr ) goto exit; } // Check if we filled the output buffer if ( cbIn && m_cbProduced + 5 >= m_cbWrite ) { hr = ERROR_INSUFFICIENT_BUFFER; } exit: #if defined (DEBUG) && defined (BINHEX_TRACE) m_lpstreamEncodeRAW->Write( lpbIn, cbOrigCbIn - cbIn, NULL ); #endif *lpcbConsumed += cbInUsed; return hr; } //----------------------------------------------------------------------------- // Name: CBinhexEncoder::HrBinHexByte // Description: // // Parameters: // Returns: // Effects: // Notes: // Revision: // Initial:9/5/1996 //----------------------------------------------------------------------------- HRESULT CBinhexEncoder::HrBinHexByte( IN BYTE b ) { HRESULT hr = ERROR_SUCCESS; #if defined (DEBUG) & defined (BINHEX_TRACE) hr = m_lpstreamEncodeRLE->Write( &b, 1, NULL ); #endif switch( m_cAccum++ ) { case 0: m_pbWrite[m_cbProduced++] = g_rgchBinHex8to6[b >> 2]; ++m_cbLine; break; case 1: m_pbWrite[m_cbProduced++] = g_rgchBinHex8to6[((m_bPrev & 0x03) << 4) | (b >> 4)]; ++m_cbLine; break; case 2: m_pbWrite[m_cbProduced++] = g_rgchBinHex8to6[((m_bPrev & 0x0f) << 2) | (b >> 6)]; ++m_cbLine; if ( m_cbLine >= 64 ) { m_pbWrite[m_cbProduced++] = chCR; m_pbWrite[m_cbProduced++] = chLF; m_cbLine = 0; ++m_cLines; } m_pbWrite[m_cbProduced++] = g_rgchBinHex8to6[b & 0x3f]; ++m_cbLine; m_cAccum = 0; break; default: AssertSz( FALSE, "HrBinHexByte: bad shift state\n" ); hr = ERROR_INVALID_PARAMETER; goto exit; } if ( m_cbLine >= 64 ) { m_pbWrite[m_cbProduced++] = chCR; m_pbWrite[m_cbProduced++] = chLF; m_cbLine = 0; ++m_cLines; } m_bPrev = b; exit: return hr; } //----------------------------------------------------------------------------- // // CBinhexDecoder class implementation // //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // Name: CalcCRC16 // Description: // Used to calculate a 16 bit CRC using the // CCITT polynomial 0x1021. // // Parameters: // Returns: // Effects: // Notes: // Revision: // Initial:7/30/1996 //----------------------------------------------------------------------------- void CalcCRC16( LPBYTE lpbBuff, ULONG cBuff, WORD * wCRC ) { LPBYTE lpb; BYTE b; WORD uCRC; WORD fWrap; ULONG i; uCRC = *wCRC; for ( lpb = lpbBuff; lpb < lpbBuff + cBuff; lpb++ ) { b = *lpb; for ( i = 0; i < 8; i++ ) { fWrap = uCRC & 0x8000; uCRC = (uCRC << 1) | (b >> 7); if ( fWrap ) { uCRC = uCRC ^ 0x1021; } b = b << 1; } } *wCRC = uCRC; } //----------------------------------------------------------------------------- // Name: bIsMacFile // Description: // // Parameters: // Returns: // FALSE: if the given dwCreator/dwType matches one of the // pairs in g_lpCreatorTypes; // // TRUE: otherwise // // Effects: // Notes: // Revision: // Initial:10/15/1996 //----------------------------------------------------------------------------- BOOL bIsMacFile(DWORD dwCreator, DWORD dwType) { BOOL bRet = TRUE; int i; char szCreator[5] = { 0 }; char szType[5] = { 0 }; if ( dwType == 0 && dwCreator == 0 ) { bRet = FALSE; goto exit; } if ( g_bCreatorTypeInit != TRUE ) { ReadCreatorTypes(); } if ( g_lpCreatorTypes == NULL ) goto exit; // Convert dwCreator & dwType to strings CopyMemory( szCreator, &dwCreator, 4 ); CopyMemory( szType, &dwType, 4 ); for ( i = 0; i < g_cCreatorTypes; i ++ ) { if ( g_lpCreatorTypes[i].szCreator[0] == 0 && g_lpCreatorTypes[i].szType[0] == 0 ) { bRet = FALSE; break; } else if ( g_lpCreatorTypes[i].szCreator[0] == 0 && lstrcmpi( g_lpCreatorTypes[i].szType, szType ) == 0 ) { bRet = FALSE; break; } else if( g_lpCreatorTypes[i].szType[0] == 0 && lstrcmpi( g_lpCreatorTypes[i].szCreator, szCreator ) == 0 ) { bRet = FALSE; break; } else if( lstrcmpi( g_lpCreatorTypes[i].szCreator, szCreator ) == 0 && lstrcmpi( g_lpCreatorTypes[i].szType, szType ) == 0 ) { bRet = FALSE; break; } } exit: return bRet ; } //----------------------------------------------------------------------------- // Name: ReadCreatorTypes // // Description: // // Read "NonMacCreatorTypes" registry key (REG_MULTI_SZ type) // from the registry & build an array of Creator-Type pairs // // Parameters: // Returns: // Effects: // Notes: // Revision: // Initial:10/15/1996 //----------------------------------------------------------------------------- VOID ReadCreatorTypes( VOID ) { #ifdef MAC g_bCreatorTypeInit = TRUE; #else // !MAC DWORD dwStatus; DWORD dwType; DWORD cbData; char * lpData = NULL; char * lpCurrent = NULL; char * lpNext = NULL; int i; LONG lRet; HKEY hKey = 0; SCODE sc = S_OK; g_bCreatorTypeInit = TRUE; // Open IMC parameter registry lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\MSExchangeIS\\ParametersSystem\\InternetContent", 0, KEY_READ, &hKey ); if ( lRet != ERROR_SUCCESS ) goto exit; // read the registry key dwStatus = RegQueryValueEx( hKey, "NonMacCreatorTypes", 0, &dwType, (LPBYTE)NULL, &cbData ); if ( dwStatus != ERROR_SUCCESS // key missing || dwType != REG_MULTI_SZ // wrong type || cbData <= 4 ) // invalid size { goto exit; } if (FAILED(HrAlloc((LPVOID *)&lpData, cbData))) goto exit; ZeroMemory( (LPVOID)lpData, cbData ); dwStatus = RegQueryValueEx( hKey, "NonMacCreatorTypes", NULL, &dwType, (LPBYTE)lpData, &cbData ); if ( dwStatus != ERROR_SUCCESS ) goto exit; // Determine # of pairs read: g_cCreatorTypes = 0; for ( i= 0; i < (LONG)cbData-1; i++ ) { if ( lpData[i] == '\0' ) g_cCreatorTypes ++; } if (FAILED(HrAlloc((LPVOID *)&g_lpCreatorTypes, sizeof(sCreatorType) * g_cCreatorTypes))) goto exit; ZeroMemory( (LPVOID)g_lpCreatorTypes, sizeof(sCreatorType) * g_cCreatorTypes ); // Build the Creator-Type array lpCurrent = lpData; i = 0; while ( lpCurrent < (lpData + cbData -1) ) { lpNext = StrChr( lpCurrent, ':' ); if( lpNext == NULL ) { //no ':' found; skip to next string lpCurrent = StrChr( lpCurrent, '\0' ) + 1; continue; } *lpNext = '\0'; if ( StrChr( lpCurrent, '*' ) == NULL ) CopyMemory( &g_lpCreatorTypes[i].szCreator, lpCurrent, MIN(4, lpNext-lpCurrent) ); lpCurrent = lpNext + 1; lpNext = StrChr( lpCurrent, '\0' ); if ( lpNext == NULL ) break; if ( StrChr( lpCurrent, '*' ) == NULL ) { CopyMemory( &g_lpCreatorTypes[i].szType, lpCurrent, MIN( 4, lpNext-lpCurrent) ); } lpCurrent = lpNext + 1; i++; } g_cCreatorTypes = i; exit: if ( hKey != 0 ) RegCloseKey( hKey ); SafeMemFree(lpData); if ( g_cCreatorTypes == 0 && g_lpCreatorTypes != NULL ) { SafeMemFree(g_lpCreatorTypes); } #endif // !MAC }