axpipe.h
来自「研读AxCrypt对加解密的处理方法」· C头文件 代码 · 共 1,103 行 · 第 1/4 页
H
1,103 行
*/
/*! \page PageDef Definitions of Terms
- Pipe, Pipe line: The code that processes a data stream using the
AxPipe framework. It is built from at
least 2 to an unlimited number of sections. All pipe lines generally
begin with a AxPipe::CSource, and end with a AxPipe::CSink.
- Source: AxPipe::CSource's are intended to provide data for the pipe (stream), for
example by reading from a file.
- Section: In between, there can be many processing steps based on AxPipe::CPipe and AxPipe::CFilter,
and also some more elaborate constuctions such as multi-pipe AxPipe::CJoin:s and AxPipe::CSplit:s.
- Sink: AxPipe::CSink's are intended to store the data that is the result of the
processing, for example into a file.
\section DataMovement Data Movement
The native model for data movement is the push model. This means that data is read from
the AxPipe::CSource, and then pushed down the pipe, i.e. the subsequent sections are called
with each respective segment as they are read. This model is suited for simple processing
with few or no input states.
The pull model is also supported in AxPipe::CFilter derived classes. In this model your code will
request data by a member function call, which returns with requested data when available. This is suitable
for more complex parsing where perhaps many possible input states exist.
\section DataUnit Data Unit
The basic unit of data is a AxPipe::CSeg object, which is a reference counted memory buffer
object of (size_t limited) arbitrary size. Code written for AxPipe should usually not depend on
CSeg objects being of any particular size, except in derived classes where such guarantees
are provided.
\see \ref PageIntro "Introduction", \ref PageInstall "Installation", \ref PageSample1 "A First Example",
\ref PageSample2 "A Second Examle",
\ref PageDef "Definitions of Terms", \ref PageStock "Stock Transformations", \ref PageUtil "Utilities and Overrides"
*/
/*! \page PageSample1 A First Example
This is almost the smallest complete AxPipe program possible, sort of the equivalent of the
standard 'Hello World' first program.
It does nothing, except move data from one source, through a pipe section, to a destination.
But even so, it's probably a fair performing file copier, since the source and destination
are memory mapped files, and execute in different threads in this example. What will happen
is that the source file is mapped into memory, section by section, and a pointer to that
memory mapping is passed to the destination, where it is copied into the correspondingly
mapped section of the destination file. Thus, the file copy is reduced to one more more
memcpy() calls + actually mapping them to memory.
\include HelloWorld.cpp
\see \ref PageIntro "Introduction", \ref PageInstall "Installation", \ref PageSample1 "A First Example",
\ref PageSample2 "A Second Examle",
\ref PageDef "Definitions of Terms", \ref PageStock "Stock Transformations", \ref PageUtil "Utilities and Overrides"
*/
/*! \page PageSample2 A Second Example
The following is a sample program with some patterns to re-use.
It will build a pipe
reading from a file, and process the input in three stages, demonstrating
three different basic models.
It will also join two sources, and then split them up again, just to demonstrate
the use of that functionality.
The assumption is that the input data is ASCII, just to make it clear.
The first stage changes all spaces (' ') to dashes ('-')<BR>
The second stage changes all dashes ('-') to plus ('+')<BR>
The third stage changes all plus ('+') to equal ('=')<BR>
The join, just simply takes one segment from each source and output it, in a round-
robin fashion.
The split finally, will take every other character and pass them to two different
sinks, one being standard output, the other being a file.
Not very useful perhaps, but it demonstrates the principles involved. Actually, for regular
text streams, the iostream library may be a better bet (although it does not support
threading).
<HR>
First we define a new type of source, reading from standard input.
\dontinclude Demo.cpp
\skip CSourceStdin
\until // CSourceStdin
Here we just override CSource::In() and read in suitable chunks, passing
it onwards by returning the a CSeg with the data. That's the basic
source. For files, use the included CSourceMemFile.
<HR>
Then we define a new type of sink, writing to standard output.
\skip CSinkStdout
\until // CSinkStdout
This is almost trivial, override CSink::Out and write the CSeg segment
passed.
<HR>
The first sample uses a segment oriented push model.
It demonstrate how to build the basic type of AxPipe::CPipe derived
push-model stream processor.<BR>
\skip CPipeReplace1
\until // CPipeReplace1
The heart of the example is in the override of CPipe::Out. Segments are
passed to it as they arrive, a new segment is allocated, and is used to
create the processed result. This is then sent onwards with CPipe::Pump.
The input segment, which now is no longer needed, is CSeg::Release'd.
<HR>
The second examle uses the pull-model instead, where the code requests
segments instead until the end of stream is detected.
\skip CPipeReplace2
\until // CPipeReplace2
Here we override CFilter::InFilter, and request segments with CFilter::Read.
In other respects, it's the same as the previous example.<BR>
Do note that a CFilter-derived class in it's CFilter::InFilter, must
explicitly call CFilter::Open and CFilter::Close. This can be changed
by overriding the default CFilter::OutOpen and CFilter::OutClose, which
do nothing but stop the propagation of the open and close signals from
the source in the default versions. More about open and close in the
description of the main code.
<HR>
The final example here illustrates the use of a further derivation of the
filter model, providing a byte at a time.
\skip CPipeReplace3
\until // CPipeReplace3
It's the same override of CFilterByte::InFilter, but now the CFilterByte::ReadByte
function is called, providing a byte at a time, or -1 at the end of the
stream. Here also we need to call CFilterByte::Open and CFilterByte::Close.
<HR>
A rudimentary join, which will just intermix any number of streams, on a segment
by segment basis, round-robin fashion. This is not very useful either, as the
segmentation will depend on the previous stages and is not known here.
\skip CJoinInterMix
\until // CJoinInterMix
Note that to actually get anything to join, you must use the CJoin::GetSink() member
and CSource::Append() that to a pipe.
<HR>
A class used in the splitting, but also serves as yet another example of a simple
push-model processing stage. This takes either the odd-numbered or the even-numbered
bytes of a stream and passes them on, dropping the other bytes.
\skip CEvenOdd
\until // CEvenOdd
See the code in _tmain() below for an example of how to use AxPipe::CSplit together
with this kind of class.
<HR>
Finally, the main program tying it all together.
\skip _tmain
\until // _tmain
First, note the definition of a CGlobalInit object. You need one, and only one,
such object to be defined in your program before using ::AxPipe. The constructor
of this object will initialize various global data.<BR>
The second thing to note is the Open()->Drain()->Close()->Plug() sequence.<BR>
The CSource::Drain() call causes data to be read from the CSource and passed along
the pipe to the CSink. But before that, you must call CSource::Open(). This causes
a signal to be passed down the line, enabling sources, pipe sections and
sinks to prepare. After the source signals end of stream, the CSource::Close() call
is necessary to give the different parts a chance to flush final data etc.
Also note how the extra AxPipe::CSource derived objects are setup to drain
in threads of their own. This is necessary for the CJoinInterMix to work, as it
otherwise will simply wait for data. Do remember thus, that using a AxPipe::CJoin
derived class entails many threads by definition.
It's possible to re-open a pipe-line by calling CSource::Open() again, if the
sections support it. This is suitable for situations where a single
stream contains of separate concatenated parts for example.
The final CSource::Plug call close the pipe-line for good.
A check for errors is done by calling CSource::GetErrorCode, any error
signalled with CError::SetError will be passed back to the source and
thus be checked here. If there is an error, the CSource::GetErrorMsg will
get the text representation of it.
<HR>
Do follow the links provided for explanation of the different framework calls.
\see CSeg, CThread, CSource, CSink, CPipe, CFilter, CFilterByte, CFilterBlock
CPipeBlock, CJoin, CSplit, AxPipe::CSourceFileMap, AxPipe::CSinkFileMap
\see \ref PageIntro "Introduction", \ref PageInstall "Installation", \ref PageSample1 "A First Example",
\ref PageSample2 "A Second Examle",
\ref PageDef "Definitions of Terms", \ref PageStock "Stock Transformations", \ref PageUtil "Utilities and Overrides"
*/
/*! \page PageUtil Utility and Overrideable Functions
Use the basic components and then derive
custom classes to perform whatever data transformation, condensation
or generation needed.
\section Utility Utility functions
The framework provides a number of functions that are intended to be called by
code in user derived classes. You should normally not override these implementions,
but just call them when appropriate. See the section on Overrides below.
The most important are:
- AxPipe::CPipe::Open() A data stream must be opened before processing. It may be opened
and closed any number of times from construction to destruction via AxPipe::CSource::Plug().
- AxPipe::CPipe::Flush() Send a voluntary request to flush buffered data downstream.
- AxPipe::CPipe::Close() Ends the current processing of data, and prepares for a Open() call again.
- AxPipe::CPipe::Signal() Send an out of band signal to downstream objects.
- AxPipe::CPipe::Pump() Send data downstream after processing.
- AxPipe::CFilter::Read() Get data for processing in pull model AxPipe::CFilter based derived classes.
- AxPipe::CError::SetError() Report an error, also causing processing to end and the CSource to
simulate and end of stream situation to end processing.
\section Overrides Overrideable functions
Most utility functions above have a corresponding overrideable virtual implementation. The
utility function calls really just wrap the actual implementations and handle propagation
downstream or upstream in the case of errors.
Most overrides have the same name as the utility function, but prefixed with Out, such as:
- AxPipe::CPipe::Out() The actual processing in a push model AxPipe::CPipe derived class.
- AxPipe::CPipe::OutOpen() Actually do what is required to open the stream.
- AxPipe::CPipe::OutFlush() Actually do what is required to flush buffered data.
- AxPipe::CPipe::OutClose() Close the stream, prepare for new AxPipe::CPipe::OutOpen().
- AxPipe::CPipe::OutSignal() Receive an out of band signal, and check if it's relevant to this object.
- AxPipe::CFilter::InFilter() The actual processing in a AxPipe::CFilter derived class.
In most cases you should call the base class implementation as part of the derived implementation.
\section Constructors Non-default Constructors
Due to the way the framework is to be used, you should not provide anything but
elaborations on the default constructor in your derived classes. When you neeed
further initialization, please use and call a separate member function like
the following:
\code
public:
CPipeMyDerivation *Init(...) {
...
return this;
}
\endcode
\section Threading
To enable threading any CSink or CSource-derived class, use the template CThread
as a wrapper, for example:
\code
pipe->Append(new CThread<CPipeReplace>); // Run in a separate thread
\endcode
Note that the threaded class and all that follow it down the pipe are run in the
same thread, unless a new threaded class is appended to the chain.
\section Naming Naming Conventions
A convention is to name derived classes with the prefix CPipe, CSplit, CJoin, CSink
or CSource before the rest of the name. CPipe is used for all kinds of intermediate
transformations. If it's a threading version, and you define the class explicitly,
name it CTPipe, CTSplit etc.
AxPipe::CSeg pointers are usually named pSeg or variants thereof.
\see \ref PageIntro "Introduction", \ref PageInstall "Installation", \ref PageSample1 "A First Example",
\ref PageSample2 "A Second Examle",
\ref PageDef "Definitions of Terms", \ref PageStock "Stock Transformations", \ref PageUtil "Utilities and Overrides"
*/
} // namespace AxPipe
#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?