source: trunk/libdjvu/DjVuPort.h @ 101

Last change on this file since 101 was 17, checked in by Eugene Romanenko, 16 years ago

update makefiles, remove absolute paths, update djvulibre to version 3.5.17

File size: 23.6 KB
Line 
1//C-  -*- C++ -*-
2//C- -------------------------------------------------------------------
3//C- DjVuLibre-3.5
4//C- Copyright (c) 2002  Leon Bottou and Yann Le Cun.
5//C- Copyright (c) 2001  AT&T
6//C-
7//C- This software is subject to, and may be distributed under, the
8//C- GNU General Public License, Version 2. The license should have
9//C- accompanied the software or you may obtain a copy of the license
10//C- from the Free Software Foundation at http://www.fsf.org .
11//C-
12//C- This program is distributed in the hope that it will be useful,
13//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
14//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15//C- GNU General Public License for more details.
16//C-
17//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library
18//C- distributed by Lizardtech Software.  On July 19th 2002, Lizardtech
19//C- Software authorized us to replace the original DjVu(r) Reference
20//C- Library notice by the following text (see doc/lizard2002.djvu):
21//C-
22//C-  ------------------------------------------------------------------
23//C- | DjVu (r) Reference Library (v. 3.5)
24//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
25//C- | The DjVu Reference Library is protected by U.S. Pat. No.
26//C- | 6,058,214 and patents pending.
27//C- |
28//C- | This software is subject to, and may be distributed under, the
29//C- | GNU General Public License, Version 2. The license should have
30//C- | accompanied the software or you may obtain a copy of the license
31//C- | from the Free Software Foundation at http://www.fsf.org .
32//C- |
33//C- | The computer code originally released by LizardTech under this
34//C- | license and unmodified by other parties is deemed "the LIZARDTECH
35//C- | ORIGINAL CODE."  Subject to any third party intellectual property
36//C- | claims, LizardTech grants recipient a worldwide, royalty-free,
37//C- | non-exclusive license to make, use, sell, or otherwise dispose of
38//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the
39//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU
40//C- | General Public License.   This grant only confers the right to
41//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to
42//C- | the extent such infringement is reasonably necessary to enable
43//C- | recipient to make, have made, practice, sell, or otherwise dispose
44//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to
45//C- | any greater extent that may be necessary to utilize further
46//C- | modifications or combinations.
47//C- |
48//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
49//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
50//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
51//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
52//C- +------------------------------------------------------------------
53//
54// $Id: DjVuPort.h,v 1.8 2003/11/07 22:08:21 leonb Exp $
55// $Name:  $
56
57#ifndef _DJVUPORT_H
58#define _DJVUPORT_H
59#ifdef HAVE_CONFIG_H
60#include "config.h"
61#endif
62#if NEED_GNUG_PRAGMAS
63# pragma interface
64#endif
65
66
67#include "GThreads.h"
68#include "GURL.h"
69
70#ifdef HAVE_NAMESPACES
71namespace DJVU {
72# ifdef NOT_DEFINED // Just to fool emacs c++ mode
73}
74#endif
75#endif
76
77class DataPool;
78
79/** @name DjVuPort.h
80    Files #"DjVuPort.h"# and #"DjVuPort.cpp"# implement a communication
81    mechanism between different parties involved in decoding DjVu files.
82    It should be pretty clear that the creator of \Ref{DjVuDocument} and
83    \Ref{DjVuFile} would like to receive some information about the progress
84    of decoding, errors occurred, etc. It may also want to provide source data
85    for decoders (like it's done in the plugin where the real data is downloaded
86    from the net and is fed into DjVu decoders).
87
88    Normally this functionality is implemented by means of callbacks which are
89    run when a given condition comes true. Unfortunately it's not quite easy
90    to implement this strategy in our case. The reason is that there may be
91    more than one "client" working with the same document, and the document
92    should send the information to each of the clients. This could be done by
93    means of callback {\em lists}, of course, but we want to achieve more
94    bulletproof results: we want to be sure that the client that we're about
95    to contact is still alive, and is not being destroyed by another thread.
96    Besides, we are going to call these "callbacks" from many places, from
97    many different classes.  Maintaining multi-thread safe callback lists is
98    very difficult.
99
100    Finally, we want to provide some default implementation of these
101    "callbacks" in the library, which should attempt to process the requests
102    themselves if they can, and contact the client only if they're unable to
103    do it (like in the case of \Ref{DjVuPort::request_data}() with local URL
104    where \Ref{DjVuDocument} can get the data from the hard drive itself not
105    disturbing the document's creator.
106
107    Two classes implement a general communication mechanism: \Ref{DjVuPort} and
108    \Ref{DjVuPortcaster}. Any sender and recipient of requests should be a
109    subclass of \Ref{DjVuPort}.  \Ref{DjVuPortcaster} maintains a map of
110    routes between \Ref{DjVuPort}s, which should be configured by somebody
111    else. Whenever a port wants to send a request, it calls the corresponding
112    function of \Ref{DjVuPortcaster}, and the portcaster relays the request to
113    all the destinations that it sees in the internal map.
114
115    The \Ref{DjVuPortcaster} is responsible for keeping the map up to date by
116    getting rid of destinations that have been destroyed.  Map updates are
117    performed from a single place and are serialized by a global monitor.
118   
119    @memo DjVu decoder communication mechanism.
120    @author Andrei Erofeev <eaf@geocities.com>\\
121            L\'eon Bottou <leonb@research.att.com>
122    @version #$Id: DjVuPort.h,v 1.8 2003/11/07 22:08:21 leonb Exp $# */
123//@{
124
125class DjVuPort;
126class DjVuPortcaster;
127class DjVuFile;
128
129/** Base class for notification targets.
130    #DjVuPort# provides base functionality for classes willing to take part in
131    sending and receiving messages generated during decoding process.  You
132    need to derive your class from #DjVuPort# if you want it to be able to
133    send or receive requests. In addition, for receiving requests you should
134    override one or more virtual function.
135
136    {\bf Important remark} --- All ports should be allocated on the heap using
137    #operator new# and immediately secured using a \Ref{GP} smart pointer.
138    Ports which are not secured by a smart-pointer are not considered
139    ``alive'' and never receive notifications! */
140
141class DjVuPort : public GPEnabled
142{
143public:
144   DjVuPort();
145   virtual ~DjVuPort();
146   static void *operator new (size_t sz);
147   static void operator delete(void *addr);
148
149      /**  Use this function to get a copy of the global \Ref{DjVuPortcaster}. */
150   static DjVuPortcaster *get_portcaster(void);
151
152      /** Copy constructor. When #DjVuPort#s are copied, the portcaster
153          copies all incoming and outgoing routes of the original. */
154   DjVuPort(const DjVuPort & port);
155
156      /** Copy operator. Similarly to the copy constructor, the portcaster
157          copies all incoming and outgoing coming routes of the original. */
158   DjVuPort & operator=(const DjVuPort & port);
159
160      /** Should return 1 if the called class inherits class #class_name#.
161          When a destination receives a request, it can retrieve the pointer
162          to the source #DjVuPort#. This virtual function should be able
163          to help to identify the source of the request. For example,
164          \Ref{DjVuFile} is also derived from #DjVuPort#. In order for
165          the receiver to recognize the sender, the \Ref{DjVuFile} should
166          override this function to return #TRUE# when the #class_name#
167          is either #DjVuPort# or #DjVuFile# */
168   virtual bool         inherits(const GUTF8String &class_name) const;
169
170      /** @name Notifications.
171          These virtual functions may be overridden by the subclasses
172          of #DjVuPort#.  They are called by the \Ref{DjVuPortcaster}
173          when the port is alive and when there is a route between the
174          source of the notification and this port. */
175      //@{
176
177      /** This request is issued to request translation of the ID, used
178          in an DjVu INCL chunk to a URL, which may be used to request
179          data associated with included file. \Ref{DjVuDocument} usually
180          intercepts all such requests, and the user doesn't have to
181          worry about the translation */
182   virtual GURL         id_to_url(const DjVuPort * source, const GUTF8String &id);
183
184      /** This request is used to get a file corresponding to the
185          given ID. \Ref{DjVuDocument} is supposed to intercept it
186          and either create a new instance of \Ref{DjVuFile} or reuse
187          an existing one from the cache. */
188   virtual GP<DjVuFile> id_to_file(const DjVuPort * source, const GUTF8String &id);
189
190      /** This request is issued when decoder needs additional data
191          for decoding.  Both \Ref{DjVuFile} and \Ref{DjVuDocument} are
192          initialized with a URL, not the document data.  As soon as
193          they need the data, they call this function, whose responsibility
194          is to locate the source of the data basing on the #URL# passed
195          and return it back in the form of the \Ref{DataPool}. If this
196          particular receiver is unable to fullfil the request, it should
197          return #0#. */
198   virtual GP<DataPool> request_data(const DjVuPort * source, const GURL & url);
199
200      /** This notification is sent when an error occurs and the error message
201          should be shown to the user.  The receiver should return #0# if it is
202          unable to process the request. Otherwise the receiver should return 1. */
203   virtual bool         notify_error(const DjVuPort * source, const GUTF8String &msg);
204
205      /** This notification is sent to update the decoding status.  The
206          receiver should return #0# if it is unable to process the
207          request. Otherwise the receiver should return 1. */
208   virtual bool         notify_status(const DjVuPort * source, const GUTF8String &msg);
209
210      /** This notification is sent by \Ref{DjVuImage} when it should be
211          redrawn. It may be used to implement progressive redisplay.
212
213          @param source The sender of the request */
214   virtual void         notify_redisplay(const class DjVuImage * source);
215
216      /** This notification is sent by \ref{DjVuImage} when its geometry
217          has been changed as a result of decoding. It may be used to
218          implement progressive redisplay. */
219   virtual void         notify_relayout(const class DjVuImage * source);
220
221      /** This notification is sent when a new chunk has been decoded. */
222   virtual void         notify_chunk_done(const DjVuPort * source, const GUTF8String &name);
223
224      /** This notification is sent after the \Ref{DjVuFile} flags have
225          been changed. This happens, for example, when:
226          \begin{itemize}
227            \item Decoding succeeded, failed or just stopped
228            \item All data has been received
229            \item All included files have been created
230          \end{itemize}
231         
232          @param source \Ref{DjVuFile}, which flags have been changed
233          @param set_mask bits, which have been set
234          @param clr_mask bits, which have been cleared */
235   virtual void         notify_file_flags_changed(const class DjVuFile * source,
236                                                  long set_mask, long clr_mask);
237
238      /** This notification is sent after the \Ref{DjVuDocument} flags have
239          been changed. This happens, for example, after it receives enough
240          data and can determine its structure (#BUNDLED#, #OLD_INDEXED#, etc.).
241
242          @param source \Ref{DjVuDocument}, which flags have been changed
243          @param set_mask bits, which have been set
244          @param clr_mask bits, which have been cleared */
245   virtual void         notify_doc_flags_changed(const class DjVuDocument * source,
246                                                 long set_mask, long clr_mask);
247   
248      /** This notification is sent from time to time while decoding is in
249          progress. The purpose is obvious: to provide a way to know how much
250          is done and how long the decoding will continue.  Argument #done# is
251          a number from 0 to 1 reflecting the progress. */
252   virtual void         notify_decode_progress(const DjVuPort * source, float done);
253
254      /** This is the standard types for defining what to do in case of errors.
255          This is only used by some of the subclasses, but it needs to be
256          defined here to guarantee all subclasses use the same enum types.
257          In general, many errors are non recoverable.  Using a setting
258          other than ABORT may just result in even more errors. */
259   enum ErrorRecoveryAction {ABORT=0,SKIP_PAGES=1,SKIP_CHUNKS=2,KEEP_ALL=3 }; 
260      //@}
261public:
262   class DjVuPortCorpse;
263private:
264   static GCriticalSection      * corpse_lock;
265   static DjVuPortCorpse        * corpse_head, * corpse_tail;
266   static int                   corpse_num;
267};
268
269/** Simple port. 
270    An instance of #DjVuSimplePort# is automatically created when you create a
271    \Ref{DjVuFile} or a \Ref{DjVuDocument} without specifying a port.  This
272    simple port can retrieve data for local urls (i.e. urls referring to local
273    files) and display error messages on #stderr#.  All other notifications
274    are ignored. */
275
276class DjVuSimplePort : public DjVuPort
277{
278public:
279      /// Returns 1 if #class_name# is #"DjVuPort"# or #"DjVuSimplePort"#.
280   virtual bool         inherits(const GUTF8String &class_name) const;
281
282      /** If #url# is local, it created a \Ref{DataPool}, connects it to the
283          file with the given name and returns.  Otherwise returns #0#. */
284   virtual GP<DataPool> request_data(const DjVuPort * source, const GURL & url);
285
286      /// Displays error on #stderr#. Always returns 1.
287   virtual bool         notify_error(const DjVuPort * source, const GUTF8String &msg);
288   
289      /// Displays status on #stderr#. Always returns 1.
290   virtual bool         notify_status(const DjVuPort * source, const GUTF8String &msg);
291};
292
293
294/** Memory based port.
295    This \Ref{DjVuPort} maintains a map associating pseudo urls with data
296    segments.  It processes the #request_data# notifications according to this
297    map.  After initializing the port, you should add as many pairs #<url,
298    pool># as needed need and add a route from a \Ref{DjVuDocument} or
299    \Ref{DjVuFile} to this port. */
300
301class DjVuMemoryPort : public DjVuPort
302{
303public:
304      /// Returns 1 if #class_name# is #"DjVuPort"# or #"DjVuMemoryPort"#
305   virtual bool         inherits(const GUTF8String &class_name) const;
306
307      /** If #url# is one of those, that have been added before by means
308          of \Ref{add_data}() function, it will return the associated
309          \Ref{DataPool}. #ZERO# otherwize. */
310   virtual GP<DataPool> request_data(const DjVuPort * source, const GURL & url);
311
312      /** Adds #<url, pool># pair to the internal map. From now on, if
313          somebody asks for data corresponding to the #url#, it will
314          be returning the #pool# */
315   void         add_data(const GURL & url, const GP<DataPool> & pool);
316private:
317   GCriticalSection     lock;
318   GPMap<GURL, DataPool>map;
319};
320
321
322
323/** Maintains associations between ports.
324    It monitors the status of all ports (have they been destructed yet?),
325    accepts requests and notifications from them and forwards them to
326    destinations according to internally maintained map of routes.
327
328    The caller can modify the route map any way he likes (see
329    \Ref{add_route}(), \Ref{del_route}(), \Ref{copy_routes}(),
330    etc. functions). Any port can be either a sender of a message, an
331    intermediary receiver or a final destination. 
332
333    When a request is sent, the #DjVuPortcaster# computes the list of
334    destinations by consulting with the route map.  Notifications are only
335    sent to ``alive'' ports.  A port is alive if it is referenced by a valid
336    \Ref{GP} smartpointer.  As a consequence, a port usually becomes alive
337    after running the constructor (since the returned pointer is then assigned
338    to a smartpointer) and is no longer alive when the port is destroyed
339    (because it would not be destroyed if a smartpointer was referencing it).
340
341    Destination ports are sorted according to their distance from the source.
342    For example, if port {\bf A} is connected to ports {\bf B} and {\bf C}
343    directly, and port {\bf B} is connected to {\bf D}, then {\bf B} and {\bf
344    C} are assumed to be one hop away from {\bf A}, while {\bf D} is two hops
345    away from {\bf A}.
346
347    In some cases the requests and notifications are sent to every possible
348    destination, and the order is not significant (like it is for
349    \Ref{notify_file_flags_changed}() request). Others should be sent to the closest
350    destinations first, and only then to the farthest, in case if they have
351    not been processed by the closest. The examples are \Ref{request_data}(),
352    \Ref{notify_error}() and \Ref{notify_status}().
353
354    The user is not expected to create the #DjVuPortcaster# itself. He should
355    use \Ref{get_portcaster}() global function instead.  */
356class DjVuPortcaster
357{
358public:
359      /**  Use this function to get a copy of the global \Ref{DjVuPortcaster}. */
360   static DjVuPortcaster *get_portcaster(void)
361    { return DjVuPort::get_portcaster(); } ;
362
363      /** The default constructor. */
364   DjVuPortcaster(void);
365
366   virtual ~DjVuPortcaster(void);
367
368      /** Removes the specified port from all routes. It will no longer
369          be able to receive or generate messages and will be considered
370    {\bf "dead"} by \Ref{is_port_alive}() function. */
371   void         del_port(const DjVuPort * port);
372   
373      /** Adds route from #src# to #dst#. Whenever a request is
374          sent or received by #src#, it will be forwarded to #dst# as well.
375          @param src The source
376          @param dst The destination */
377   void         add_route(const DjVuPort *src, DjVuPort *dst);
378
379      /** The opposite of \Ref{add_route}(). Removes the association
380          between #src# and #dst# */
381   void         del_route(const DjVuPort *src, DjVuPort *dst);
382
383      /** Copies all incoming and outgoing routes from #src# to
384          #dst#. This function should be called when a \Ref{DjVuPort} is
385          copied, if you want to preserve the connectivity. */
386   void         copy_routes(DjVuPort *dst, const DjVuPort *src);
387
388      /** Returns a smart pointer to the port if #port# is a valid pointer
389          to an existing #DjVuPort#.  Returns a null pointer otherwise. */
390   GP<DjVuPort> is_port_alive(DjVuPort *port);
391
392      /** Assigns one more {\em alias} for the specified \Ref{DjVuPort}.
393          {\em Aliases} are names, which can be used later to retrieve this
394          \Ref{DjVuPort}, if it still exists. Any \Ref{DjVuPort} may have
395          more than one {\em alias}. But every {\em alias} must correspond
396          to only one \Ref{DjVuPort}. Thus, if the specified alias is
397          already associated with another port, this association will be
398          removed. */
399   void         add_alias(const DjVuPort * port, const GUTF8String &alias);
400
401      /** Removes all the aliases */
402   static void          clear_all_aliases(void);
403
404      /** Removes all aliases associated with the given \Ref{DjVuPort}. */
405   void         clear_aliases(const DjVuPort * port);
406
407      /** Returns \Ref{DjVuPort} associated with the given #alias#. If nothing
408          is known about name #alias#, or the port associated with it has
409          already been destroyed #ZERO# pointer will be returned. */
410   GP<DjVuPort> alias_to_port(const GUTF8String &name);
411
412      /** Returns a list of \Ref{DjVuPort}s with aliases starting with
413          #prefix#. If no \Ref{DjVuPort}s have been found, empty
414          list is returned. */
415   GPList<DjVuPort>     prefix_to_ports(const GUTF8String &prefix);
416
417      /** Computes destination list for #source# and calls the corresponding
418          function in each of the ports from the destination list starting from
419          the closest until one of them returns non-empty \Ref{GURL}. */
420   virtual GURL         id_to_url(const DjVuPort * source, const GUTF8String &id);
421
422      /** Computes destination list for #source# and calls the corresponding
423          function in each of the ports from the destination list starting from
424          the closest until one of them returns non-zero pointer to
425          \Ref{DjVuFile}. */
426   virtual GP<DjVuFile> id_to_file(const DjVuPort * source, const GUTF8String &id);
427
428      /** Computes destination list for #source# and calls the corresponding
429          function in each of the ports from the destination list starting from
430          the closest until one of them returns non-zero \Ref{DataPool}. */
431   virtual GP<DataPool> request_data(const DjVuPort * source, const GURL & url);
432
433      /** Computes destination list for #source# and calls the corresponding.
434          function in each of the ports from the destination starting from
435          the closest until one of them returns 1. */
436   virtual bool         notify_error(const DjVuPort * source, const GUTF8String &msg);
437
438      /** Computes destination list for #source# and calls the corresponding
439          function in each of the ports from the destination list starting from
440          the closest until one of them returns 1. */
441   virtual bool         notify_status(const DjVuPort * source, const GUTF8String &msg);
442
443      /** Computes destination list for #source# and calls the corresponding
444          function in each of the ports from the destination list starting from
445          the closest. */
446   virtual void         notify_redisplay(const class DjVuImage * source);
447
448      /** Computes destination list for #source# and calls the corresponding
449          function in each of the ports from the destination list starting from
450          the closest. */
451   virtual void         notify_relayout(const class DjVuImage * source);
452
453      /** Computes destination list for #source# and calls the corresponding
454          function in each of the ports from the destination list starting from
455          the closest. */
456   virtual void         notify_chunk_done(const DjVuPort * source, const GUTF8String &name);
457
458      /** Computes destination list for #source# and calls the corresponding
459          function in each of the ports from the destination list starting from
460          the closest. */
461   virtual void         notify_file_flags_changed(const class DjVuFile * source,
462                                                  long set_mask, long clr_mask);
463
464      /** Computes destination list for #source# and calls the corresponding
465          function in each of the ports from the destination list starting from
466          the closest. */
467   virtual void         notify_doc_flags_changed(const class DjVuDocument * source,
468                                                 long set_mask, long clr_mask);
469   
470      /** Computes destination list for #source# and calls the corresponding
471          function in each of the ports from the destination list starting from
472          the closest. */
473   virtual void         notify_decode_progress(const DjVuPort * source, float done);
474
475private:
476      // We use these 'void *' to minimize template instantiations.
477   friend class DjVuPort;
478   GCriticalSection             map_lock;
479   GMap<const void *, void *>   route_map;      // GMap<DjVuPort *, GList<DjVuPort *> *>
480   GMap<const void *, void *>   cont_map;       // GMap<DjVuPort *, DjVuPort *>
481   GMap<GUTF8String, const void *>      a2p_map;        // GMap<GUTF8String, DjVuPort *>
482   void add_to_closure(GMap<const void*, void*> & set,
483                       const DjVuPort *dst, int distance);
484   void compute_closure(const DjVuPort *src, GPList<DjVuPort> &list,
485                        bool sorted=false);
486};
487
488
489inline bool
490DjVuPort::inherits(const GUTF8String &class_name) const
491{
492   return (class_name == "DjVuPort");
493}
494
495inline bool
496DjVuSimplePort::inherits(const GUTF8String &class_name) const
497{
498   return
499      (class_name == "DjVuSimplePort") || DjVuPort::inherits(class_name);
500}
501
502inline bool
503DjVuMemoryPort::inherits(const GUTF8String &class_name) const
504{
505   return
506      (class_name == "DjVuMemoryPort") || DjVuPort::inherits(class_name);
507}
508
509//@}
510
511
512#ifdef HAVE_NAMESPACES
513}
514# ifndef NOT_USING_DJVU_NAMESPACE
515using namespace DJVU;
516# endif
517#endif
518#endif
Note: See TracBrowser for help on using the repository browser.