Blame libdjvu/DataPool.h

Packit df99a1
//C-  -*- C++ -*-
Packit df99a1
//C- -------------------------------------------------------------------
Packit df99a1
//C- DjVuLibre-3.5
Packit df99a1
//C- Copyright (c) 2002  Leon Bottou and Yann Le Cun.
Packit df99a1
//C- Copyright (c) 2001  AT&T
Packit df99a1
//C-
Packit df99a1
//C- This software is subject to, and may be distributed under, the
Packit df99a1
//C- GNU General Public License, either Version 2 of the license,
Packit df99a1
//C- or (at your option) any later version. The license should have
Packit df99a1
//C- accompanied the software or you may obtain a copy of the license
Packit df99a1
//C- from the Free Software Foundation at http://www.fsf.org .
Packit df99a1
//C-
Packit df99a1
//C- This program is distributed in the hope that it will be useful,
Packit df99a1
//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit df99a1
//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit df99a1
//C- GNU General Public License for more details.
Packit df99a1
//C- 
Packit df99a1
//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library from
Packit df99a1
//C- Lizardtech Software.  Lizardtech Software has authorized us to
Packit df99a1
//C- replace the original DjVu(r) Reference Library notice by the following
Packit df99a1
//C- text (see doc/lizard2002.djvu and doc/lizardtech2007.djvu):
Packit df99a1
//C-
Packit df99a1
//C-  ------------------------------------------------------------------
Packit df99a1
//C- | DjVu (r) Reference Library (v. 3.5)
Packit df99a1
//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
Packit df99a1
//C- | The DjVu Reference Library is protected by U.S. Pat. No.
Packit df99a1
//C- | 6,058,214 and patents pending.
Packit df99a1
//C- |
Packit df99a1
//C- | This software is subject to, and may be distributed under, the
Packit df99a1
//C- | GNU General Public License, either Version 2 of the license,
Packit df99a1
//C- | or (at your option) any later version. The license should have
Packit df99a1
//C- | accompanied the software or you may obtain a copy of the license
Packit df99a1
//C- | from the Free Software Foundation at http://www.fsf.org .
Packit df99a1
//C- |
Packit df99a1
//C- | The computer code originally released by LizardTech under this
Packit df99a1
//C- | license and unmodified by other parties is deemed "the LIZARDTECH
Packit df99a1
//C- | ORIGINAL CODE."  Subject to any third party intellectual property
Packit df99a1
//C- | claims, LizardTech grants recipient a worldwide, royalty-free, 
Packit df99a1
//C- | non-exclusive license to make, use, sell, or otherwise dispose of 
Packit df99a1
//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the 
Packit df99a1
//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU 
Packit df99a1
//C- | General Public License.   This grant only confers the right to 
Packit df99a1
//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to 
Packit df99a1
//C- | the extent such infringement is reasonably necessary to enable 
Packit df99a1
//C- | recipient to make, have made, practice, sell, or otherwise dispose 
Packit df99a1
//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to 
Packit df99a1
//C- | any greater extent that may be necessary to utilize further 
Packit df99a1
//C- | modifications or combinations.
Packit df99a1
//C- |
Packit df99a1
//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
Packit df99a1
//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
Packit df99a1
//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
Packit df99a1
//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
Packit df99a1
//C- +------------------------------------------------------------------
Packit df99a1
Packit df99a1
#ifndef _DATAPOOL_H
Packit df99a1
#define _DATAPOOL_H
Packit df99a1
#ifdef HAVE_CONFIG_H
Packit df99a1
#include "config.h"
Packit df99a1
#endif
Packit df99a1
#if NEED_GNUG_PRAGMAS
Packit df99a1
# pragma interface
Packit df99a1
#endif
Packit df99a1
Packit df99a1
Packit df99a1
#include "GThreads.h"
Packit df99a1
#include "GString.h"
Packit df99a1
#include "GURL.h"
Packit df99a1
Packit df99a1
#ifdef HAVE_NAMESPACES
Packit df99a1
namespace DJVU {
Packit df99a1
# ifdef NOT_DEFINED // Just to fool emacs c++ mode
Packit df99a1
}
Packit df99a1
#endif
Packit df99a1
#endif
Packit df99a1
Packit df99a1
class ByteStream;
Packit df99a1
Packit df99a1
/** @name DataPool.h
Packit df99a1
    Files #"DataPool.h"# and #"DataPool.cpp"# implement classes \Ref{DataPool}
Packit df99a1
    and \Ref{DataRange} used by DjVu decoder to access data.
Packit df99a1
Packit df99a1
    The main goal of class \Ref{DataPool} is to provide concurrent access
Packit df99a1
    to the same data from many threads with a possibility to add data
Packit df99a1
    from yet another thread. It is especially important in the case of the
Packit df99a1
    Netscape plugin when data is not immediately available, but decoding
Packit df99a1
    should be started as soon as possible. In this situation it is vital
Packit df99a1
    to provide transparent access to the data from many threads possibly
Packit df99a1
    blocking readers that try to access information that has not been
Packit df99a1
    received yet.
Packit df99a1
Packit df99a1
    When the data is local though, it can be accessed directly using
Packit df99a1
    standard IO mechanism. To provide a uniform interface for decoding
Packit df99a1
    routines, \Ref{DataPool} supports file mode as well.
Packit df99a1
Packit df99a1
    @memo Thread safe data storage
Packit df99a1
    @author Andrei Erofeev <eaf@geocities.com>
Packit df99a1
*/
Packit df99a1
Packit df99a1
//@{
Packit df99a1
Packit df99a1
/** Thread safe data storage.
Packit df99a1
    The purpose of #DataPool# is to provide a uniform interface for
Packit df99a1
    accessing data from decoding routines running in a multi-threaded
Packit df99a1
    environment. Depending on the mode of operation it may contain the
Packit df99a1
    actual data, may be connected to another #DataPool# or may be mapped
Packit df99a1
    to a file. Regardless of the mode, the class returns data in a
Packit df99a1
    thread-safe way, blocking reading threads if there is no data of
Packit df99a1
    interest available. This blocking is especially useful in the
Packit df99a1
    networking environment (plugin) when there is a running decoding thread,
Packit df99a1
    which wants to start decoding as soon as there is just one byte available
Packit df99a1
    blocking if necessary.
Packit df99a1
Packit df99a1
    Access to data in a #DataPool# may be direct (Using \Ref{get_data}()
Packit df99a1
    function) or sequential (See \Ref{get_stream}() function).
Packit df99a1
Packit df99a1
    If the #DataPool# is not connected to anything, that is it contains
Packit df99a1
    some real data, this data can be added to it by means of two
Packit df99a1
    \Ref{add_data}() functions. One of them adds data sequentially maintaining
Packit df99a1
    the offset of the last block of data added by it. The other can store
Packit df99a1
    data anywhere. Thus it's important to realize, that there may be "white
Packit df99a1
    spots" in the data storage.
Packit df99a1
Packit df99a1
    There is also a way to test if data is available for some given data
Packit df99a1
    range (See \Ref{has_data}()). In addition to this mechanism, there are
Packit df99a1
    so-called {\em trigger callbacks}, which are called, when there is
Packit df99a1
    all data available for a given data range.
Packit df99a1
Packit df99a1
    Let us consider all modes of operation in details:
Packit df99a1
Packit df99a1
    \begin{enumerate}
Packit df99a1
       \item {\bf Not connected #DataPool#}. In this mode the #DataPool#
Packit df99a1
             contains some real data. As mentioned above, it may be added  
Packit df99a1
             by means of two functions \Ref{add_data}() operating independent
Packit df99a1
	     of each other and allowing to add data sequentially and
Packit df99a1
	     directly to any place of data storage. It's important to call
Packit df99a1
	     function \Ref{set_eof}() after all data has been added.
Packit df99a1
Packit df99a1
	     Functions like \Ref{get_data}() or \Ref{get_stream}() can
Packit df99a1
	     be used to obtain direct or sequential access to the data. As
Packit df99a1
	     long as \Ref{is_eof}() is #FALSE#, #DataPool# will block every
Packit df99a1
	     reader, which is trying to read unavailable data until it
Packit df99a1
	     really becomes available. But as soon as \Ref{is_eof}() is
Packit df99a1
	     #TRUE#, any attempt to read non-existing data will read #0# bytes.
Packit df99a1
Packit df99a1
	     Taking into account the fact, that #DataPool# was designed to
Packit df99a1
	     store DjVu files, which are in IFF formats, it becomes possible
Packit df99a1
	     to predict the size of the #DataPool# as soon as the first
Packit df99a1
	     #32# bytes have been added. This is invaluable for estimating
Packit df99a1
	     download progress. See function \Ref{get_length}() for details.
Packit df99a1
	     If this estimate fails (which means, that stored data is not
Packit df99a1
	     in IFF format), \Ref{get_length}() returns #-1#.
Packit df99a1
Packit df99a1
	     Triggers may be added and removed by means of \Ref{add_trigger}()
Packit df99a1
	     and \Ref{del_trigger}() functions. \Ref{add_trigger}() takes
Packit df99a1
	     a data range. As soon as all data in that data range is
Packit df99a1
	     available, the trigger callback will be called.
Packit df99a1
Packit df99a1
	     All trigger callbacks will be called when #EOF# condition
Packit df99a1
	     has been set.
Packit df99a1
Packit df99a1
       \item {\bf #DataPool# connected to another #DataPool#}. In this
Packit df99a1
             {\em slave} mode you can map a given #DataPool# to any offsets
Packit df99a1
	     range inside another #DataPool#. You can connect the slave
Packit df99a1
	     #DataPool# even if there is no data in the master #DataPool#.
Packit df99a1
	     Any \Ref{get_data}() request will be forwarded to the master
Packit df99a1
	     #DataPool#, and it will be responsible for blocking readers
Packit df99a1
	     trying to access unavailable data.
Packit df99a1
Packit df99a1
	     The usage of \Ref{add_data}() functions is prohibited for
Packit df99a1
	     connected #DataPool#s.
Packit df99a1
Packit df99a1
	     The offsets range used to map a slave #DataPool# can be fully
Packit df99a1
	     specified (both start offset and length are positive numbers)
Packit df99a1
	     or partially specified (the length is negative). In this mode
Packit df99a1
	     the slave #DataPool# is assumed to extend up to the end
Packit df99a1
	     of the master #DataPool#.
Packit df99a1
Packit df99a1
	     Triggers may be used with slave #DataPool#s as well as with
Packit df99a1
	     the master ones.
Packit df99a1
Packit df99a1
	     Calling \Ref{stop}() function of a slave will stop only the slave
Packit df99a1
	     (and any other slave connected to it), but not the master.
Packit df99a1
Packit df99a1
	     \Ref{set_eof}() function is meaningless for slaves. They obtain
Packit df99a1
	     the #ByteStream::EndOfFile# status from their master.
Packit df99a1
Packit df99a1
	     Depending on the offsets range passed to the constructor,
Packit df99a1
	     \Ref{get_length}() returns different values. If the length
Packit df99a1
	     passed to the constructor was positive, then it is returned
Packit df99a1
	     by \Ref{get_length}() all the time. Otherwise the value returned
Packit df99a1
	     is either #-1# if master's length is still unknown (it didn't
Packit df99a1
	     manage to parse IFF data yet) or it is calculated as
Packit df99a1
	     #masters_length-slave_start#.
Packit df99a1
Packit df99a1
       \item {\bf #DataPool# connected to a file}. This mode is quite similar
Packit df99a1
             to the case, when the #DataPool# is connected to another
Packit df99a1
	     #DataPool#. Similarly, the #DataPool# stores no data inside.
Packit df99a1
	     It just forwards all \Ref{get_data}() requests to the underlying
Packit df99a1
	     source (a file in this case). Thus these requests will never
Packit df99a1
	     block the reader. But they may return #0# if there is no data
Packit df99a1
	     available at the requested offset.
Packit df99a1
Packit df99a1
	     The usage of \Ref{add_data}() functions is meaningless and
Packit df99a1
	     is prohibited.
Packit df99a1
Packit df99a1
	     \Ref{is_eof}() function always returns #TRUE#. Thus \Ref{set_eof}()
Packit df99a1
	     us meaningless and does nothing.
Packit df99a1
Packit df99a1
	     \Ref{get_length}() function always returns the file size.
Packit df99a1
Packit df99a1
	     Calling \Ref{stop}() function will stop this #DataPool# and
Packit df99a1
	     any other slave connected to it.
Packit df99a1
Packit df99a1
	     Trigger callbacks passed through \Ref{add_trigger}() function
Packit df99a1
	     are called immediately.
Packit df99a1
Packit df99a1
	     This mode is useful to read and decode DjVu files without reading
Packit df99a1
	     and storing them in full in memory.
Packit df99a1
    \end{enumerate}
Packit df99a1
*/
Packit df99a1
Packit df99a1
class DJVUAPI DataPool : public GPEnabled
Packit df99a1
{
Packit df99a1
public: // Classes used internally by DataPool
Packit df99a1
	// These are declared public to support buggy C++ compilers.
Packit df99a1
   class Incrementor;
Packit df99a1
   class Reader;
Packit df99a1
   class Trigger;
Packit df99a1
   class OpenFiles;
Packit df99a1
   class OpenFiles_File;
Packit df99a1
   class BlockList;
Packit df99a1
   class Counter;
Packit df99a1
protected:
Packit df99a1
   DataPool(void);
Packit df99a1
Packit df99a1
public:
Packit df99a1
      /** @name Initialization */
Packit df99a1
      //@{
Packit df99a1
      /** Default creator. Will prepare #DataPool# for accepting data
Packit df99a1
	  added through functions \Ref{add_data}(). Use \Ref{connect}()
Packit df99a1
	  functions if you want to map this #DataPool# to another or
Packit df99a1
	  to a file. */
Packit df99a1
   static GP<DataPool> create(void);
Packit df99a1
Packit df99a1
      /** Creates and initialized the #DataPool# with data from stream #str#.
Packit df99a1
	  The constructor will read the stream's contents and add them
Packit df99a1
	  to the pool using the \Ref{add_data}() function. Afterwards it
Packit df99a1
	  will call \Ref{set_eof}() function, and no other data will be
Packit df99a1
	  allowed to be added to the pool. */
Packit df99a1
   static GP<DataPool> create(const GP<ByteStream> & str);
Packit df99a1
Packit df99a1
      /** Initializes the #DataPool# in slave mode and connects it
Packit df99a1
	  to the specified offsets range of the specified master #DataPool#.
Packit df99a1
	  It is equivalent to calling default constructor and function
Packit df99a1
	  \Ref{connect}().
Packit df99a1
Packit df99a1
	  @param master_pool Master #DataPool# providing data for this slave
Packit df99a1
	  @param start Beginning of the offsets range which the slave is
Packit df99a1
	         mapped into
Packit df99a1
          @param length Length of the offsets range. If negative, the range
Packit df99a1
	         is assumed to extend up to the end of the master #DataPool#.
Packit df99a1
      */
Packit df99a1
   static GP<DataPool> create(const GP<DataPool> & master_pool, int start=0, int length=-1);
Packit df99a1
Packit df99a1
      /** Initializes the #DataPool# in slave mode and connects it
Packit df99a1
	  to the specified offsets range of the specified file.
Packit df99a1
	  It is equivalent to calling default constructor and function
Packit df99a1
	  \Ref{connect}().
Packit df99a1
	  @param url Name of the file to connect to.
Packit df99a1
	  @param start Beginning of the offsets range which the #DataPool# is
Packit df99a1
	         mapped into
Packit df99a1
          @param length Length of the offsets range. If negative, the range
Packit df99a1
	         is assumed to extend up to the end of the file.
Packit df99a1
      */
Packit df99a1
   static GP<DataPool> create(const GURL &url, int start=0, int length=-1);
Packit df99a1
Packit df99a1
   virtual ~DataPool();
Packit df99a1
Packit df99a1
      /** Switches the #DataPool# to slave mode and connects it to the
Packit df99a1
	  specified offsets range of the master #DataPool#.
Packit df99a1
	  @param master_pool Master #DataPool# providing data for this slave
Packit df99a1
	  @param start Beginning of the offsets range which the slave is
Packit df99a1
	         mapped into
Packit df99a1
          @param length Length of the offsets range. If negative, the range
Packit df99a1
	         is assumed to extend up to the end of the master #DataPool#.
Packit df99a1
      */
Packit df99a1
   void		connect(const GP<DataPool> & master_pool, int start=0, int length=-1);
Packit df99a1
      /** Connects the #DataPool# to the specified offsets range of
Packit df99a1
	  the named #url#.
Packit df99a1
	  @param url Name of the file to connect to.
Packit df99a1
	  @param start Beginning of the offsets range which the #DataPool# is
Packit df99a1
	         mapped into
Packit df99a1
          @param length Length of the offsets range. If negative, the range
Packit df99a1
	         is assumed to extend up to the end of the file.
Packit df99a1
      */
Packit df99a1
   void		connect(const GURL &url, int start=0, int length=-1);
Packit df99a1
      //@}
Packit df99a1
Packit df99a1
      /** Tells the #DataPool# to stop serving readers.
Packit df99a1
Packit df99a1
	  If #only_blocked# flag is #TRUE# then only those requests will
Packit df99a1
	  be processed, which would not block. Any attempt to get non-existing
Packit df99a1
	  data would result in a #STOP# exception (instead of blocking until
Packit df99a1
	  data is available).
Packit df99a1
Packit df99a1
	  If #only_blocked# flag is #FALSE# then any further attempt to read
Packit df99a1
	  from this #DataPool# (as well as from any #DataPool# connected
Packit df99a1
	  to this one) will result in a #STOP# exception. */
Packit df99a1
   void		stop(bool only_blocked=false);
Packit df99a1
Packit df99a1
      /** @name Adding data.
Packit df99a1
	  Please note, that these functions are for not connected #DataPool#s
Packit df99a1
	  only. You can not add data to a #DataPool#, which is connected
Packit df99a1
	  to another #DataPool# or to a file.
Packit df99a1
	*/
Packit df99a1
      //@{
Packit df99a1
      /** Appends the new block of data to the #DataPool#. There are two
Packit df99a1
	  \Ref{add_data}() functions available. One is for adding data
Packit df99a1
	  sequentially. It keeps track of the last byte position, which has
Packit df99a1
	  been stored {\bf by it} and always appends the next block after
Packit df99a1
	  this position. The other \Ref{add_data}() can store data anywhere.
Packit df99a1
	  
Packit df99a1
	  The function will unblock readers waiting for data if this data
Packit df99a1
	  arrives with this block. It may also trigger some {\em trigger
Packit df99a1
	  callbacks}, which may have been added by means of \Ref{add_trigger}()
Packit df99a1
	  function.
Packit df99a1
Packit df99a1
	  {\bf Note:} After all the data has been added, it's necessary
Packit df99a1
	  to call \Ref{set_eof}() to tell the #DataPool# that nothing else
Packit df99a1
	  is expected.
Packit df99a1
Packit df99a1
	  {\bf Note:} This function may not be called if the #DataPool#
Packit df99a1
	  has been connected to something.
Packit df99a1
Packit df99a1
	  @param buffer data to append
Packit df99a1
	  @param size length of the {\em buffer}
Packit df99a1
      */
Packit df99a1
   void		add_data(const void * buffer, int size);
Packit df99a1
Packit df99a1
      /** Stores the specified block of data at the specified offset.
Packit df99a1
	  Like the function above this one can also unblock readers
Packit df99a1
	  waiting for data and engage trigger callbacks. The difference
Packit df99a1
	  is that {\bf this} function can store data anywhere.
Packit df99a1
Packit df99a1
	  {\bf Note:} After all the data has been added, it's necessary
Packit df99a1
	  to call \Ref{set_eof}() to tell the #DataPool# that nothing else
Packit df99a1
	  is expected.
Packit df99a1
Packit df99a1
	  {\bf Note:} This function may not be called if the #DataPool#
Packit df99a1
	  has been connected to something.
Packit df99a1
Packit df99a1
	  @param buffer data to store
Packit df99a1
	  @param offset where to store the data
Packit df99a1
	  @param size length of the {\em buffer} */
Packit df99a1
   void		add_data(const void * buffer, int offset, int size);
Packit df99a1
Packit df99a1
      /** Tells the #DataPool# that all data has been added and nothing else
Packit df99a1
	  is anticipated. When #EOF# is true, any reader attempting to read
Packit df99a1
	  non existing data will not be blocked. It will either read #ZERO#
Packit df99a1
	  bytes or will get an #ByteStream::EndOfFile# exception (see \Ref{get_data}()).
Packit df99a1
	  Calling this function will also activate all registered trigger
Packit df99a1
	  callbacks.
Packit df99a1
Packit df99a1
	  {\bf Note:} This function is meaningless and does nothing
Packit df99a1
	  when the #DataPool# is connected to another #DataPool# or to
Packit df99a1
	  a file. */
Packit df99a1
   void		set_eof(void);
Packit df99a1
      //@}
Packit df99a1
Packit df99a1
      /** @name Accessing data.
Packit df99a1
	  These functions provide direct and sequential access to the
Packit df99a1
	  data of the #DataPool#. If the #DataPool# is not connected
Packit df99a1
	  (contains some real data) then it handles the requests itself.
Packit df99a1
	  Otherwise they are forwarded to the master #DataPool# or the file.
Packit df99a1
	*/
Packit df99a1
      //@{
Packit df99a1
      /** Attempts to return a block of data at the given #offset#
Packit df99a1
	  of the given #size#.
Packit df99a1
Packit df99a1
	  \begin{enumerate}
Packit df99a1
	     \item If the #DataPool# is connected to another #DataPool# or
Packit df99a1
	           to a file, the request will just be forwarded to them.
Packit df99a1
	     \item If the #DataPool# is not connected to anything and
Packit df99a1
	           some of the data requested is in the internal buffer,
Packit df99a1
		   the function copies available data to #buffer# and returns
Packit df99a1
		   immediately.
Packit df99a1
Packit df99a1
		   If there is no data available, and \Ref{is_eof}() returns
Packit df99a1
		   #FALSE#, the reader (and the thread) will be {\bf blocked}
Packit df99a1
		   until the data actually arrives. Please note, that since
Packit df99a1
		   the reader is blocked, it should run in a separate thread
Packit df99a1
		   so that other threads have a chance to call \Ref{add_data}().
Packit df99a1
		   If there is no data available, but \Ref{is_eof}() is #TRUE#
Packit df99a1
		   the behavior is different and depends on the #DataPool#'s
Packit df99a1
		   estimate of the file size:
Packit df99a1
		   \begin{itemize}
Packit df99a1
		      \item If #DataPool# learns from the IFF structure of the
Packit df99a1
		            data, that its size should be greater than it
Packit df99a1
			    really is, then any attempt to read non-existing
Packit df99a1
			    data in the range of {\em valid} offsets will
Packit df99a1
			    result in an #ByteStream::EndOfFile# exception. This is done to
Packit df99a1
			    indicate, that there was an error in adding data,
Packit df99a1
			    and the data requested is {\bf supposed} to be
Packit df99a1
			    there, but has actually not been added.
Packit df99a1
		      \item If #DataPool#'s expectations about the data size
Packit df99a1
		            coincide with the reality then any attempt to
Packit df99a1
			    read data beyond the legal range of offsets will
Packit df99a1
			    result in #ZERO# bytes returned.
Packit df99a1
		   \end{itemize}.
Packit df99a1
          \end{enumerate}.
Packit df99a1
Packit df99a1
	  @param buffer Buffer to be filled with data
Packit df99a1
	  @param offset Offset in the #DataPool# to read data at
Packit df99a1
	  @param size Size of the {\em buffer}
Packit df99a1
	  @return The number of bytes actually read
Packit df99a1
	  @exception STOP The stream has been stopped
Packit df99a1
	  @exception EOF The requested data is not there and will not be added,
Packit df99a1
	             although it should have been.
Packit df99a1
      */
Packit df99a1
   int		get_data(void * buffer, int offset, int size);
Packit df99a1
Packit df99a1
      /** Returns a \Ref{ByteStream} to access contents of the #DataPool#
Packit df99a1
	  sequentially. By reading from the returned stream you basically
Packit df99a1
          call \Ref{get_data}() function. Thus, everything said for it
Packit df99a1
	  remains true for the stream too. */
Packit df99a1
   GP<ByteStream>	get_stream(void);
Packit df99a1
      //@}
Packit df99a1
Packit df99a1
      /** @name State querying functions. */
Packit df99a1
      //@{
Packit df99a1
      /** Returns #TRUE# if this #DataPool# is connected to another #DataPool#
Packit df99a1
	  or to a file. */
Packit df99a1
   bool		is_connected(void) const;
Packit df99a1
   
Packit df99a1
      /** Returns #TRUE# if all data available for offsets from
Packit df99a1
	  #start# till #start+length-1#. If #length# is negative, the
Packit df99a1
          range is assumed to extend up to the end of the #DataPool#.
Packit df99a1
	  This function works both for connected and not connected #DataPool#s.
Packit df99a1
	  Once it returned #TRUE# for some offsets range, you can be
Packit df99a1
	  sure that the subsequent \Ref{get_data}() request will not block.
Packit df99a1
      */
Packit df99a1
   bool		has_data(int start, int length);
Packit df99a1
Packit df99a1
      /* Returns #TRUE# if no more data is planned to be added.
Packit df99a1
Packit df99a1
	 {\bf Note:} This function always returns #TRUE# when the #DataPool#
Packit df99a1
	 has been initialized with a file name. */
Packit df99a1
   bool		is_eof(void) const {return eof_flag;}
Packit df99a1
Packit df99a1
      /** Returns the {\em length} of data in the #DataPool#. The value
Packit df99a1
	  returned depends on the mode of operation:
Packit df99a1
	  \begin{itemize}
Packit df99a1
	     \item If the #DataPool# is not connected to anything then
Packit df99a1
	           the length returned is either calculated by interpreting
Packit df99a1
		   the IFF structure of stored data (if successful) or
Packit df99a1
		   by calculating the real size of data after \Ref{set_eof}()
Packit df99a1
		   has been called. Otherwise it is #-1#.
Packit df99a1
	     \item If the #DataPool# is connected to a file, the length
Packit df99a1
	           is calculated basing on the length passed to the
Packit df99a1
		   \Ref{connect}() function and the file size.
Packit df99a1
	     \item If the #DataPool# is connected to a master #DataPool#,
Packit df99a1
	           the length is calculated basing on the value returned
Packit df99a1
		   by the master's #get_length()# function and the length
Packit df99a1
		   passed to the \Ref{connect}() function.
Packit df99a1
	  \end{itemize}. */
Packit df99a1
   int		get_length(void) const;
Packit df99a1
      /** Returns the number of bytes of data available in this #DataPool#.
Packit df99a1
	  Contrary to the \Ref{get_length}() function, this one doesn't try
Packit df99a1
	  to interpret the IFF structure and predict the file length.
Packit df99a1
	  It just returns the number of bytes of data really available inside
Packit df99a1
	  the #DataPool#, if it contains data, or inside its range, if it's
Packit df99a1
	  connected to another #DataPool# or a file. */
Packit df99a1
   int		get_size(void) const {return get_size(0, -1);}
Packit df99a1
      //@}
Packit df99a1
Packit df99a1
      /** @name Trigger callbacks.
Packit df99a1
	  {\em Trigger callbacks} are special callbacks called when
Packit df99a1
	  all data for the given range of offsets has been made available.
Packit df99a1
	  Since reading unavailable data may result in a thread block,
Packit df99a1
	  which may be bad, the usage of {\em trigger callbacks} appears
Packit df99a1
	  to be a convenient way to signal availability of data.
Packit df99a1
Packit df99a1
	  You can add a trigger callback in two ways:
Packit df99a1
	  \begin{enumerate}
Packit df99a1
	     \item By specifying a range. This is the most general case
Packit df99a1
	     \item By providing just one {\em threshold}. In this case
Packit df99a1
	           the range is assumed to start from offset #ZERO# and
Packit df99a1
		   last for {\em threshold}+1 bytes.
Packit df99a1
	  \end{enumerate}
Packit df99a1
	*/
Packit df99a1
      //@{
Packit df99a1
      /** Associates the specified {\em trigger callback} with the
Packit df99a1
	  given data range.
Packit df99a1
Packit df99a1
	  {\bf Note:} The callback may be called immediately if all
Packit df99a1
	  data for the given range is already available or #EOF# is #TRUE#.
Packit df99a1
Packit df99a1
	  @param start The beginning of the range for which all data
Packit df99a1
	         should be available
Packit df99a1
	  @param length If the {\em length} is not negative then the callback
Packit df99a1
	         will be called when there is data available for every
Packit df99a1
		 offset from {\em start} to {\em start+length-1}.
Packit df99a1
	         If {\em thresh} is negative, the callback is called after
Packit df99a1
		 #EOF# condition has been set.
Packit df99a1
	  @param callback Function to call
Packit df99a1
	  @param cl_data Argument to pass to the callback when it's called. */
Packit df99a1
   void		add_trigger(int start, int length,
Packit df99a1
			    void (* callback)(void *), void * cl_data);
Packit df99a1
Packit df99a1
      /** Associates the specified {\em trigger callback} with the
Packit df99a1
	  specified threshold.
Packit df99a1
Packit df99a1
	  This function is a simplified version of the function above.
Packit df99a1
	  The callback will be called when there is data available for
Packit df99a1
	  every offset from #0# to #thresh#, if #thresh# is positive, or
Packit df99a1
	  when #EOF# condition has been set otherwise. */
Packit df99a1
Packit df99a1
   void		add_trigger(int thresh, 
Packit df99a1
                            void (* callback)(void *), void * cl_data);
Packit df99a1
Packit df99a1
      /** Use this function to unregister callbacks, which are no longer
Packit df99a1
	  needed. {\bf Note!} It's important to do it when the client
Packit df99a1
	  is about to be destroyed. */
Packit df99a1
   void		del_trigger(void (* callback)(void *), void *  cl_data);
Packit df99a1
Packit df99a1
      //@}
Packit df99a1
Packit df99a1
      /** Loads data from the file into memory. This function is only useful
Packit df99a1
	  for #DataPool#s getting data from a file. It descends the #DataPool#s
Packit df99a1
	  hierarchy until it either reaches a file-connected #DataPool#
Packit df99a1
	  or #DataPool# containing the real data. In the latter case it
Packit df99a1
	  does nothing, in the first case it makes the #DataPool# read all
Packit df99a1
	  data from the file into memory and stop using the file.
Packit df99a1
Packit df99a1
	  This may be useful when you want to overwrite the file and leave
Packit df99a1
	  existing #DataPool#s with valid data. */
Packit df99a1
   void		load_file(void);
Packit df99a1
      /** This function will make every #DataPool# in the program, which
Packit df99a1
	  is connected to a file, to load the file contents to the main
Packit df99a1
	  memory and close the file. This feature is important when you
Packit df99a1
	  want to do something with the file like remove or overwrite it
Packit df99a1
	  not affecting the rest of the program. */
Packit df99a1
   static void	load_file(const GURL &url;;
Packit df99a1
Packit df99a1
      /** This function will remove OpenFiles filelist. */
Packit df99a1
   static void	close_all(void);
Packit df99a1
Packit df99a1
      // Internal. Used by 'OpenFiles'
Packit df99a1
   void		clear_stream(const bool release = true);
Packit df99a1
Packit df99a1
      /** Useful in comparing data pools.  Returns true if dirived from
Packit df99a1
          same URL or bytestream. */
Packit df99a1
   bool simple_compare(DataPool &pool) const;
Packit df99a1
Packit df99a1
Packit df99a1
private:
Packit df99a1
   bool		eof_flag;
Packit df99a1
   bool		stop_flag;
Packit df99a1
   bool		stop_blocked_flag;
Packit df99a1
Packit df99a1
   Counter	*active_readers;
Packit df99a1
   
Packit df99a1
      // Source or storage of data
Packit df99a1
   GP<DataPool>		pool;
Packit df99a1
   GURL		furl;
Packit df99a1
   GP<OpenFiles_File>   fstream;
Packit df99a1
   GCriticalSection	class_stream_lock;
Packit df99a1
   GP<ByteStream>	data;
Packit df99a1
   GCriticalSection	data_lock;
Packit df99a1
   BlockList		*block_list;
Packit df99a1
   int			add_at;
Packit df99a1
   int			start, length;
Packit df99a1
Packit df99a1
      // List of readers waiting for data
Packit df99a1
   GPList<Reader>	readers_list;
Packit df99a1
   GCriticalSection	readers_lock;
Packit df99a1
Packit df99a1
      // Triggers
Packit df99a1
   GPList<Trigger>	triggers_list;		// List of passed or our triggers
Packit df99a1
   GCriticalSection	triggers_lock;		// Lock for the list above
Packit df99a1
   GCriticalSection	trigger_lock;		// Lock for static_trigger_cb()
Packit df99a1
Packit df99a1
   void		init(void);
Packit df99a1
   void		wait_for_data(const GP<Reader> & reader);
Packit df99a1
   void		wake_up_all_readers(void);
Packit df99a1
   void		check_triggers(void);
Packit df99a1
   int		get_data(void * buffer, int offset, int size, int level);
Packit df99a1
   int		get_size(int start, int length) const;
Packit df99a1
   void		restart_readers(void);
Packit df99a1
Packit df99a1
//   static void	static_trigger_cb(GP<GPEnabled> &);
Packit df99a1
   static void	static_trigger_cb(void *);
Packit df99a1
   void		trigger_cb(void);
Packit df99a1
   void		analyze_iff(void);
Packit df99a1
   void		added_data(const int offset, const int size);
Packit df99a1
public:
Packit df99a1
  static const char *Stop;
Packit df99a1
  friend class FCPools;
Packit df99a1
};
Packit df99a1
Packit df99a1
inline bool 
Packit df99a1
DataPool::simple_compare(DataPool &pool) const
Packit df99a1
{
Packit df99a1
  // return true if these pools are identical.  False means they may or may
Packit df99a1
  // not be identical.
Packit df99a1
  return (this == &pool)
Packit df99a1
    ||(furl.is_valid()&&!furl.is_empty()&&pool.furl.is_valid()&&(furl == pool.furl))
Packit df99a1
    ||(data && (data == pool.data));
Packit df99a1
}
Packit df99a1
Packit df99a1
inline bool
Packit df99a1
DataPool::is_connected(void) const
Packit df99a1
{
Packit df99a1
   return furl.is_local_file_url() || pool!=0;
Packit df99a1
}
Packit df99a1
Packit df99a1
//@}
Packit df99a1
Packit df99a1
Packit df99a1
#ifdef HAVE_NAMESPACES
Packit df99a1
}
Packit df99a1
# ifndef NOT_USING_DJVU_NAMESPACE
Packit df99a1
using namespace DJVU;
Packit df99a1
# endif
Packit df99a1
#endif
Packit df99a1
#endif