⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scemfdatapprop.cpp

📁 Source code for EMFexplorer 1.0
💻 CPP
字号:
/*
*	This file is part of the EMFexplorer projet.
*	Copyright (C) 2004 Smith Charles.
*
*	This library is free software; you can redistribute it and/or
*	modify it under the terms of the GNU Lesser General Public
*	License as published by the Free Software Foundation; either
*	version 2.1 of the License, or (at your option) any later version.
*
*   This library is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*   Lesser General Public License for more details.
*
*   You should have received a copy of the GNU Lesser General Public
*   License along with this library; if not, write to the Free Software
*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
*
*	Extension: for commercial use, apply the Equity Public License, which
*	adds to the normal terms of the GLPL a condition of donation to the author.
*   If you are interested in support for this source code,
*   contact Smith Charles <smith.charles@free.fr> for more information.
*/

#include "stdafx.h"
#include "SCEMFDataPProp.h"
#include "SCEMFAxCtl.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

IMPLEMENT_DYNAMIC(CSCEMFDataPathProperty, CDataPathProperty)

/////////////////////////////////////////////////////////////////////////////
// CSCEMFDataPathProperty

CSCEMFDataPathProperty::CSCEMFDataPathProperty(COleControl* pControl) :
	CDataPathProperty(pControl),
	m_dlState(dlNone),
	m_hEMF(NULL),
	m_dwArrivedBytes(0),
	m_dwRead(0),
	m_dwNeeded(0),
	m_dwTotal(0),
	m_dwPos(0),
	m_dwNbRecs(0),
	m_bCheckZip(TRUE),
	m_bIsGZ(FALSE)
{
}

CSCEMFDataPathProperty::~CSCEMFDataPathProperty()
{
}


// Do not edit the following lines, which are needed by ClassWizard.
#if 0
BEGIN_MESSAGE_MAP(CSCEMFDataPathProperty, CDataPathProperty)
	//{{AFX_MSG_MAP(CSCEMFDataPathProperty)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif  // 0

/////////////////////////////////////////////////////////////////////////////
// CSCEMFDataPathProperty member functions

void CSCEMFDataPathProperty::OnDataAvailable(DWORD dwSize, DWORD bscfFlag)
{
	if (bscfFlag & BSCF_FIRSTDATANOTIFICATION)
		ResetData();

	CDataPathProperty::OnDataAvailable(dwSize, bscfFlag);

	if (dwSize <= m_dwArrivedBytes)
		return;

	DWORD dwArriving = dwSize - m_dwArrivedBytes;
	m_dwArrivedBytes = dwSize;

	BOOL bContinue = m_dlState != dlDone;
	while (bContinue)
	{
		switch (m_dlState)
		{
		case dlNone:
			// Try to read the EMF header.
			{
				if (m_bCheckZip &&  dwArriving>=SC_GZHEADER_MINSIZE)
				{
					m_bCheckZip = FALSE;

					BYTE buff[128];
					DWORD dwPos = this->GetPosition();
					DWORD dwRead = this->Read(buff, 128);

					m_bIsGZ = SCIsGZCandidate(buff, dwRead);
					if (m_bIsGZ)
					{
						m_MemZip.SCBeginUnzip(buff, dwRead);

						DWORD dwHdrSize = m_MemZip.SCGetHeaderSize();

						if (m_MemZip.SCGetState())
							this->Seek((LONG)dwPos, CFile::begin);
						else
						{// prepare for EMF header check
							dwArriving -= dwHdrSize;
							this->Seek((LONG)dwPos+dwHdrSize, CFile::begin);
						}
							
					} else
						this->Seek((LONG)dwPos, CFile::begin);
				}

				ENHMETAHEADER emfh;
				if (SCReadBytes(dwArriving, (LPBYTE)&emfh, sizeof(emfh))&&
					(emfh.dSignature == ENHMETA_SIGNATURE))
				{
					m_dwTotal = emfh.nBytes;
					m_dwPos = 0;
					m_dwNeeded = emfh.nSize;

					m_dlState = dlEMFBody;

					// resume reading
					dwArriving = m_dwArrivedBytes;
					if (!m_bIsGZ)
					{// Restart everything from the begining to get EMF header
						this->SeekToBegin();
						m_CacheFile.SetLength(0);
					}
					else
					{
						if (m_MemZip.SCIsAtEnd())
						{// The cache contains a complete EMF: keep it.
							dwArriving = 0;
						} else
						{// Restart everything from the begining (except zip header)
							DWORD dwHdrSize = m_MemZip.SCGetHeaderSize();
							dwArriving -= dwHdrSize;

							BYTE buff[128];
							this->SeekToBegin();
							DWORD dwRead = this->Read(buff, 128);
							m_MemZip.SCBeginUnzip(buff, dwRead);

							this->Seek(dwHdrSize, CFile::begin);
							m_CacheFile.SetLength(0);
						}
					}
					m_dwRead = m_CacheFile.GetLength(); // for control
				}
				else
				{
					bContinue = FALSE;
					break;
				}
			}
			break;

		case dlEMFBody:
			// Read some records.
			{
				bContinue = FALSE; // always quit

				LPBYTE pb = NULL;
				int nSize = SCReadRecords(dwArriving, pb);
				if (nSize > 0)
				{
					if (m_hEMF)
						DeleteEnhMetaFile(m_hEMF);
					m_hEMF = SetEnhMetaFileBits(nSize, pb);
					delete [] pb;
				}
				if (m_dwRead>=m_dwTotal)
				{
					m_dlState = dlDone;
					m_CacheFile.SetLength(0);
				}
			}
			break;
		}; //switch

		bContinue = bContinue && (m_dlState != dlDone);
	} //while

	ASSERT_KINDOF(CSCEMFAxCtrl, GetControl());
	((CSCEMFAxCtrl*)GetControl())->InformDlStatus(m_dlState);
}

void CSCEMFDataPathProperty::ResetData()
{
	CDataPathProperty::ResetData();
	m_dlState = dlNone;
	if (m_hEMF)
	{
		DeleteEnhMetaFile(m_hEMF);
		m_hEMF = NULL;
	}

	m_CacheFile.SetLength(0);
	m_dwArrivedBytes = 0;
	m_dwRead = 0;
	m_dwNeeded = 0;
	m_dwTotal = 0;
	m_dwPos = 0;
	m_dwNbRecs = 0;
}

DWORD CSCEMFDataPathProperty::SCTransferFileContent(CFile* pFrom, CFile* pTo, DWORD dwAmount)
{
	#define SC_BUFSIZE	1024*32
	DWORD dwRead = 0;

	if (m_bIsGZ && m_MemZip.SCIsAtEnd())
	{
#ifdef _DEBUG
		// You must manage to avoid calling this function in this case
		AfxMessageBox(_T("Attempt to uncompress past the end of incoming stream."));
		// And the data should be in the cache
		if (m_CacheFile.GetLength()<=m_dwArrivedBytes)
		{
			TRACE(_T("Invalid data in cache."));
		}
#endif
		return 0;
	}

	pTo->SeekToEnd();
	if (dwAmount>SC_BUFSIZE)
	{// Big chunk coming: attempt to use it in one call.
	 // Note however that we should put some limit.
		BYTE* pBuff = new BYTE[dwAmount]; // let Windows VMM do its job
		if (pBuff)
		{
			DWORD dwActual = pFrom->Read(pBuff, dwAmount);
			if (m_bIsGZ)
			{
				m_MemZip.SCUnzipChunk(pBuff, dwActual);

				CMemFile& rMemFile = m_MemZip.SCGetMemFile();
				dwActual = rMemFile.GetLength();
				delete [] pBuff;
				pBuff = rMemFile.Detach();
				if (m_MemZip.SCIsAtEnd())
					m_MemZip.SCEndUnzip();
			}

			pTo->Write(pBuff, dwActual);
			dwRead += dwActual;
			delete [] pBuff;
			return dwRead;
		}
		// fall through
	}

	// small one, or could not allocate big one
	BYTE buff[SC_BUFSIZE];
	DWORD dwActual = 1; // bogus value to enter the loop
	while ((dwAmount > 0) && (dwActual > 0))
	{
		dwActual = pFrom->Read(buff, min(dwAmount, SC_BUFSIZE));
		if (m_bIsGZ)
		{
			m_MemZip.SCUnzipChunk(buff, dwActual);
			
			CMemFile& rMemFile = m_MemZip.SCGetMemFile();
			dwActual = rMemFile.GetLength();
			LPBYTE pBuff = rMemFile.Detach();
			pTo->Write(pBuff, dwActual);
			delete [] pBuff;
			if (m_MemZip.SCIsAtEnd())
				m_MemZip.SCEndUnzip();
		} else
			pTo->Write(buff, dwActual);				
		dwAmount -= dwActual;
		dwRead += dwActual;
	}

	return dwRead;
}

BOOL CSCEMFDataPathProperty::SCReadBytes(DWORD dwArriving, LPBYTE pb, DWORD dwLen)
{
	// Cache contents.
	SCTransferFileContent(this, &m_CacheFile, dwArriving);
	m_dwRead = m_CacheFile.GetLength();

	// Do we have enough data yet?
	if (m_dwRead >= dwLen)
	{
		m_CacheFile.SeekToBegin();
		VERIFY(m_CacheFile.Read(pb, dwLen) == (UINT)dwLen);

		return TRUE;
	}
	return FALSE;
}

DWORD CSCEMFDataPathProperty::SCReadRecords(DWORD dwArriving, LPBYTE& pb)
{
	// Cache contents.
	if (dwArriving)
		SCTransferFileContent(this, &m_CacheFile, dwArriving);
#ifdef _DEBUG
	if (dwArriving &&
		m_dwRead >= m_CacheFile.GetLength())
	{// we missed something
		CString strmsg;
		strmsg.Format(_T("Error.Cache:dwArriving=%d, m_dwRead=%d, Cache.Length=%d"), dwArriving, m_dwRead, m_CacheFile.GetLength());
		AfxMessageBox(strmsg);
	}
#endif

	m_dwRead = m_CacheFile.GetLength();

	// Do we have enough data yet?
	DWORD dwFresh = m_dwRead - m_dwPos;
	if (dwFresh<m_dwNeeded)
	{ // eat fresh bytes, but we want more
#ifdef _DEBUG
		if (m_dwRead >= m_dwTotal)
		{// we are asking too much 
			CString strmsg;
			strmsg.Format(_T("Error.Waiting:dwFresh=%d, m_dwNeeded=%d, m_dwRead=%d"), dwFresh, m_dwNeeded, m_dwRead);
			AfxMessageBox(strmsg);
		}
#endif
		m_dwNeeded -= dwFresh;
		return 0;
	}

	m_CacheFile.SeekToBegin();
	
	pb = new BYTE[m_dwRead + sizeof(EMREOF)];
	UINT uiRead = m_CacheFile.Read(pb, m_dwRead);
	ASSERT(uiRead == (UINT)m_dwRead);
	
	// parse records in the block
	DWORD dwWholeRecs = 0; // size of integral records arrived
	PEMR pEmr = (PEMR)((BYTE*)pb + m_dwPos);
	
	while (m_dwPos < m_dwRead)
	{
		m_dwNeeded = pEmr->nSize;

		if (!m_dwNeeded)
		{// data error
			TRACE1("BAD RECORD AT m_dwNbRecs=%d\n", m_dwNbRecs);
			break;
		}

		if (m_dwPos + m_dwNeeded<=m_dwRead)
		{// integral record
			m_dwNbRecs++;
			// next record in same block
			m_dwPos += m_dwNeeded;
			pEmr = (PEMR)((BYTE*)pb + m_dwPos);
			m_dwNeeded = 0;
		} else
		{
			// next record in a next block
			m_dwNeeded -= (m_dwRead - m_dwPos);
			break;
		}
	}
	if (!m_dwPos)
	{// error
		delete [] pb;
		return 0;
	}
	dwWholeRecs = m_dwPos;
	
	// adjust buffer
	ENHMETAHEADER* pemfh = (ENHMETAHEADER*)pb;
	pemfh->nRecords = m_dwNbRecs;
	pemfh->nBytes = dwWholeRecs;
	if (dwWholeRecs<m_dwTotal)
	{
		pemfh->nPalEntries = 0;
		// update EOF so that the arrived data is usable
		if (pEmr->iType!=EMR_HEADER)
		{
			pEmr->iType = EMR_EOF;
			pEmr->nSize = sizeof(EMREOF);
			
			EMREOF* pRecEof = (EMREOF*)pEmr;
			pRecEof->nPalEntries = 0;
			pRecEof->offPalEntries = sizeof(EMREOF);
			pRecEof->nSizeLast = pEmr->nSize;
		}
	}

	return dwWholeRecs;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -