?? csink.cpp
字號(hào):
/*! \file
\brief Implementation of AxPipe::CSink base class for sinks
@(#) $Id: CSink.cpp,v 1.3 2004/02/02 12:10:47 svante Exp $
AxPipe - Binary Stream Framework
Copyright (C) 2003 Svante Seleborg/Axon Data, All rights reserved.
This program is free software; you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License along with this program;
if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
The author may be reached at mailto:axpipe@axondata.se and http://axpipe.sourceforge.net
Why is this framework released as GPL and not LGPL? See http://www.gnu.org/philosophy/why-not-lgpl.html
----
\verbatim
CSink.cpp Implementation of CSink base class for sinks
E-mail YYYY-MM-DD Reason
axpipe@axondata.se 2003-12-01 Initial
\endverbatim
*/
#include "stdafx.h"
#include "AxAssert.h"
#define AXLIB_ASSERT_FILE "CSink.cpp"
namespace AxPipe {
/// Helper function that is also called by derived classes that want slightly
/// different Work() logic, but can leverage this common base.
/// Checks for special AxPipe::eSegType types, and calls the appropriate OutOpen(),
/// OutClose(), OutFlush() and Out() functions depending on the case.
/// Only in the case of Out() does the actual data segment get passed on. Any custom
/// AxPipe::eSegType segment types gets passed as normal segments to Out().
/// Ensures that the pipe is Open() at this stage before sending data etc.
/// \return true if the caller should propagate the segment. The pSeg is never CSeg::Release()'d here. Caller must.
bool
CSink::DoSegWork(CSeg *pSeg) {
bool fPropagate; // true if we propagate in band signals
switch (pSeg->Type()) {
case eSegTypeOpen:
fPropagate = OutOpen();
// Can't set this false before we've closed properly
m_fIsOpen = true;
return fPropagate;
break;
case eSegTypeFlush:
return OutFlush();
break;
case eSegTypeClose:
if (m_fIsOpen) {
fPropagate = OutClose();
// Can't set this false before we've closed properly
m_fIsOpen = false;
} else {
// If we're not open doesn't make sense to propagate close
fPropagate = false;
}
return fPropagate;
break;
case eSegTypePlug:
// Set the exit so we can end if it's a thread etc.
OutPlug(); // Call this class's Plug-function
fPropagate = m_fExit = true;
return fPropagate;
break;
case 0:
if (!m_fIsOpen) {
SetError(ERROR_CODE_NOTOPEN, ERROR_MSG_NOTOPEN);
break;
}
// Ignore zero-length segments.
if (pSeg->Len()) {
// non-zero length data segment.
// Out() will not be called with anything else. CFilter derived classes have slightly
// different rules.
Out(pSeg->AddRef());
}
break;
default:
// It's an special/unknown segment type, call the handler (even with zero-length)
// Note that we auto propagate special segments, even if they are semantially similar
// to normal data segments.
// CSeg::AddRef() it since the OutSpecial() handler is expected to CSeg::Release() it - as will the caller of DoSegWork()
return OutSpecial(pSeg->AddRef());
break;
}
return false;
}
/// Called with CSink::m_pSeg set to whatever needs to be processed.
/// Work guarantees to never call Out() with anything but a valid, non-zero-length
/// data segment. Other cases are handled by OutOpen(), OutClose() and OutFlush().
/// A Plug() request causes nothing to be sent to Out().
void
CSink::Work() {
CSeg *pSeg = m_pSeg;
m_pSeg = NULL;
(void)DoSegWork(pSeg);
// DoSegWork() never releases, so we must.
pSeg->Release();
}
/// Unless we're already exited, end processing and wait for it to reach
/// idle state. Should not be called from Work() or Out(). Finally, we
/// wait for the worker thread, if any, to actually exit, thus assuring
/// that when Plug() returns, it is safe to call the destructor.
/// The purpose of Plug is to finalize all processing and to ensure that
/// any errors are found and reported. Final error checking for processing should
/// thus not be done before Plug() is called. After Plug() is called, the
/// only thing that should be done with the object and the pipe line is
/// to destruct it.
void
CSink::OutPlug() {
AxLib::OutputDebugStringF(_T("CSink::OutPlug() m_fExit=%d\n"), m_fExit);
}
/// Allocate a new segment, possibly from the next section of the pipe.
///
/// Callable from user code in derived classes.
///
/// Call this to get a segment if you suspect the next in line is a sink that
/// might provide an efficient segment, such as for a memory mapped file.
/// \return A writeable CSeg of the requested size, or NULL on error.
CSeg *
CSink::GetSeg(size_t cb) {
return new CSeg(cb);
}
/// \brief Send Out-of-band signal. Callable from user code in derived classes.
///
/// Does nothing, this is a CSink.
/// \see CPipe::Signal()
void
CSink::Signal(void *vId, void *p) {
}
/// Callable from user code in derived classes.
///
/// \return The maximum output size in bytes. -1 if unknown or unlimited.
/// \see OutSizeMax() The corresponding overrideable
longlong
CSink::SizeMax() {
return OutSizeMax();
}
/// Do not call from user code, only from derived framework classes.
/// The normal usage is to have the previous section up the line
/// call this via it's CPipe::m_pSink pointer, the roundabout way is
/// to enable seamless threading.
/// Is frequently called from other library-internal classes, therefore public
/// \param pSeg The segment to send off to Work(). Don't use it afterwards unless you've CSeg::AddRef()'d it.
void
CSink::OutPump(CSeg *pSeg) {
WorkStart();
m_pSeg = pSeg;
WorkSignal();
}
/// Override this in user derived classes to return the maximum size
/// of the sink, or -1 for expandable. The default CSink implementation
/// always returns -1.
/// \return The maximum output size in bytes. -1 if unknown or unlimited.
/// \see SizeMax()
longlong
CSink::OutSizeMax() {
return -1;
}
/// Override in user derived classes to provide an efficient memory segment
/// output from a CSink, especially for memory mapped files.
/// \see GetSeg() The User callable function.
/// \return A writeable segment.
CSeg *
CSink::OutGetSeg(size_t cb) {
CSeg *pSeg = new CSeg(cb);
ASSPTR(pSeg);
return pSeg;
}
/// Override in user derived classes to receive a out-of band signal sent from upstream.
/// This will be called synchronized with the data stream, so previously sent
/// data will have reached this section, unless some intermediate section buffers.
/// No automatic Flush() request is sent though. This CSink default implementation
/// does nothing and returns false to stop propagation, since it's CSink.
/// \return false to stop the signal-propagation, true to continue it.
/// \param vId A unique value identifying the signal, suggested is ClassId().
/// \param p An opaque pointer value, interpretable by the receiver.
/// \see CPipe::OutSignal()
/// \sse CPipe::OutSpecial()
bool
CSink::OutSignal(void *vId, void *p) {
return false;
}
/// Override in user derived classes. Called by the framework as a result of an
/// Open() call here or upstream. Prepare for processing of a new stream, it must
/// support being called again after a Close() call. No data may be processed by
/// the stream without an Open() call.
///
/// The default implementation for a CSink returns false, as it does not make
/// sense to propagate downstream from a CSink()
/// \return true if the framework should propagate the Open() request downstream.
bool
CSink::OutOpen() {
return false;
};
/// You are not required to honor the request.
/// \return true if the framework should propagate the Flush() request downstream.
bool
CSink::OutFlush() {
return false;
};
/// The code should handle multiple (extra) calls to an already closed stream with
/// no ill effects, i.e. silently ignore them. This default implementation returns
/// false to stop propagation, since it's a CSink.
/// \return true if the framework should propagate the Close() request downstream.
bool
CSink::OutClose() {
return false;
};
/// Segments may be marked as special with a non-zero value based on AxPipe::eSegType types. These are
/// filtered out of the stream by the framework and presented here instead of to Out(). Use
/// this in derived classes to provide in band signalling and for other custom needs. Start
/// numbering from AxPipe::eSegTypeDerived.
///
/// The default implementation here just calls CSeg::Release() on the provided CSeg .
///
/// These segements may be zero-length.
/// \return false, since we're at the end of the line. No more propagation.
/// \see AxPipe::eSegType
bool
CSink::OutSpecial(CSeg *pSeg) {
pSeg->Release();
return false;
}
/// Initialize member variables.
CSink::CSink() {
m_pSeg = NULL;
m_fIsOpen = false;
}
/// Plug the pipe, destroy the sink and release remaining m_pSeg if any
CSink::~CSink() {
OutputDebugStringF(_T("CSink::~CSink() Initating... this=%p\n"), this);
ASSCHK(m_fExit, _T("CSink::~CSink() called without Plug()"));
if (CSeg::IsSeg(m_pSeg)) m_pSeg->Release();
OutputDebugStringF(_T("CSink::~CSink() ...Done. this=%p\n"), this);
}
/// You can't append a CSink to a CSink, so this implements code to catch
/// that error.
void
CSink::AppendSink(CSink *pSink, bool fAutoDelete) {
SetError(ERROR_CODE_GENERIC, _T("Attempt to append to a sink"));
}
/// Synchronize all work downstream, ensuring
/// that there is no work in progress.
void
CSink::Sync() {
WaitForIdle();
// Do no more, this is a CSink - It's the end of the line.
}
/// Called by the virtual destructor, the default implementation for CSink
/// does nothing. The purpose of DestructSink() is to ensure that the
/// whole chain gets destructed, also depending on if they should be
/// auto deleted. It should be called by the destructor before it
/// does the remaining destructing.
void
CSink::DestructSink() {
OutputDebugString(_T("CSink::DestructSink()\n"));
}
};
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -