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 + -
显示快捷键?