Blame libdjvu/IFFByteStream.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 _IFFBYTESTREAM_H_
Packit df99a1
#define _IFFBYTESTREAM_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
/** @name IFFByteStream.h
Packit df99a1
Packit df99a1
    Files #"IFFByteStream.h"# and #"IFFByteStream.cpp"# implement a parser for
Packit df99a1
    files structured according the Electronic Arts ``EA IFF 85 Interchange
Packit df99a1
    File Format''.  IFF files are composed of a sequence of data {\em chunks}.
Packit df99a1
    Each chunk is identified by a four character {\em chunk identifier}
Packit df99a1
    describing the type of the data stored in the chunk.  A few special chunk
Packit df99a1
    identifiers, for instance #"FORM"#, are reserved for {\em composite
Packit df99a1
    chunks} which themselves contain a sequence of data chunks.  This
Packit df99a1
    conventions effectively provides IFF files with a convenient hierarchical
Packit df99a1
    structure.  Composite chunks are further identified by a secondary chunk
Packit df99a1
    identifier.
Packit df99a1
    
Packit df99a1
    We found convenient to define a {\em extended chunk identifier}.  In the
Packit df99a1
    case of a regular chunk, the extended chunk identifier is simply the
Packit df99a1
    chunk identifier, as in #"PM44"#. In the case of a composite chunk, the
Packit df99a1
    extended chunk identifier is composed by concatenating the main chunk
Packit df99a1
    identifier, a colon, and the secondary chunk identifier, as in
Packit df99a1
    #"FORM:DJVU"#.
Packit df99a1
Packit df99a1
    Class \Ref{IFFByteStream} provides a way to read or write IFF structured
Packit df99a1
    files.  Member functions provide an easy mean to position the underlying
Packit df99a1
    \Ref{ByteStream} at the beginning of each chunk and to read or write the
Packit df99a1
    data until reaching the end of the chunk.  The utility program
Packit df99a1
    \Ref{djvuinfo} demonstrates how to use class #IFFByteStream#.
Packit df99a1
Packit df99a1
    {\bf IFF Files and ZP-Coder} ---
Packit df99a1
    Class #IFFByteStream# repositions the underlying ByteStream whenever a new
Packit df99a1
    chunk is accessed.  It is possible to code chunk data with the ZP-Coder
Packit df99a1
    without worrying about the final file position. See class \Ref{ZPCodec}
Packit df99a1
    for more details.
Packit df99a1
    
Packit df99a1
    {\bf DjVu IFF Files} --- We had initially planned to exactly follow the
Packit df99a1
    IFF specifications.  Then we realized that certain versions of MSIE
Packit df99a1
    recognize any IFF file as a Microsoft AIFF sound file and pop a message
Packit df99a1
    box "Cannot play that sound".  It appears that the structure of AIFF files
Packit df99a1
    is entirely modeled after the IFF standard, with small variations
Packit df99a1
    regarding the endianness of numbers and the padding rules.  We eliminate
Packit df99a1
    this problem by casting the octet protection spell.  Our IFF files always
Packit df99a1
    start with the four octets #0x41,0x54,0x26,0x54# followed by the fully
Packit df99a1
    conformant IFF byte stream.  Class #IFFByteStream# silently skips these
Packit df99a1
    four octets when it encounters them.
Packit df99a1
Packit df99a1
    {\bf References} --- EA IFF 85 Interchange File Format specification:\\
Packit df99a1
    \URL{http://www.cica.indiana.edu/graphics/image_specs/ilbm.format.txt} or
Packit df99a1
    \URL{http://www.tnt.uni-hannover.de/soft/compgraph/fileformats/docs/iff.pre}
Packit df99a1
Packit df99a1
    @memo 
Packit df99a1
    IFF file parser.
Packit df99a1
    @author
Packit df99a1
    L\'eon Bottou <leonb@research.att.com>
Packit df99a1
Packit df99a1
// From: Leon Bottou, 1/31/2002
Packit df99a1
// This has been changed by Lizardtech to fit better 
Packit df99a1
// with their re-implementation of ByteStreams.
Packit df99a1
Packit df99a1
*/
Packit df99a1
//@{
Packit df99a1
Packit df99a1
Packit df99a1
#include "DjVuGlobal.h"
Packit df99a1
#include <stddef.h>
Packit df99a1
#include <stdlib.h>
Packit df99a1
#include <stdio.h>
Packit df99a1
#include <string.h>
Packit df99a1
#include "GException.h"
Packit df99a1
#include "GString.h"
Packit df99a1
#include "ByteStream.h"
Packit df99a1
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
/** ByteStream interface for an IFF file. 
Packit df99a1
Packit df99a1
    Class #IFFByteStream# augments the #ByteStream# interface with
Packit df99a1
    functions for navigating from chunk to chunk.  It works in relation
Packit df99a1
    with a ByteStream specified at construction time. 
Packit df99a1
Packit df99a1
    {\bf Reading an IFF file} --- You can read an IFF file by constructing an
Packit df99a1
    #IFFByteStream# object attached to the ByteStream containing the IFF file.
Packit df99a1
    Calling function \Ref{get_chunk} positions the file pointer at the
Packit df99a1
    beginning of the first chunk.  You can then use \Ref{ByteStream::read} to
Packit df99a1
    access the chunk data.  Function #read# will return #0# if you attempt to
Packit df99a1
    read past the end of the chunk, just as if you were trying to read past
Packit df99a1
    the end of a file. You can at any time call function \Ref{close_chunk} to
Packit df99a1
    terminate reading data in this chunk.  The following chunks can be
Packit df99a1
    accessed by calling #get_chunk# and #close_chunk# repeatedly until you
Packit df99a1
    reach the end of the file.  Function #read# is not very useful when
Packit df99a1
    accessing a composite chunk.  You can instead make nested calls to
Packit df99a1
    functions #get_chunk# and #close_chunk# in order to access the chunks
Packit df99a1
    located inside the composite chunk.
Packit df99a1
    
Packit df99a1
    {\bf Writing an IFF file} --- You can write an IFF file by constructing an
Packit df99a1
    #IFFByteStream# object attached to the seekable ByteStream object that
Packit df99a1
    will contain the IFF file.  Calling function \Ref{put_chunk} creates a
Packit df99a1
    first chunk header and positions the file pointer at the beginning of the
Packit df99a1
    chunk.  You can then use \Ref{ByteStream::write} to store the chunk data.
Packit df99a1
    Calling function \Ref{close_chunk} terminates the current chunk.  You can
Packit df99a1
    append more chunks by calling #put_chunk# and #close_chunk# repeatedly.
Packit df99a1
    Function #write# is not very useful for writing a composite chunk.  You
Packit df99a1
    can instead make nested calls to function #put_chunk# and #close_chunk# in
Packit df99a1
    order to create chunks located inside the composite chunk.
Packit df99a1
Packit df99a1
    Writing an IFF file requires a seekable ByteStream (see
Packit df99a1
    \Ref{ByteStream::is_seekable}).  This is not much of a problem because you
Packit df99a1
    can always create the IFF file into a \Ref{MemoryByteStream} and then use
Packit df99a1
    \Ref{ByteStream::copy} to transfer the IFF file into a non seekable
Packit df99a1
    ByteStream.  */
Packit df99a1
Packit df99a1
class DJVUAPI IFFByteStream : protected ByteStream::Wrapper
Packit df99a1
{
Packit df99a1
protected: 
Packit df99a1
  IFFByteStream(const GP<ByteStream> &bs, const int pos);
Packit df99a1
public:
Packit df99a1
  /** Constructs an IFFByteStream object attached to ByteStream #bs#.
Packit df99a1
      Any ByteStream can be used when reading an IFF file.  Writing
Packit df99a1
      an IFF file however requires a seekable ByteStream. */
Packit df99a1
  static GP<IFFByteStream> create(const GP<ByteStream> &bs);
Packit df99a1
  // --- BYTESTREAM INTERFACE
Packit df99a1
  ~IFFByteStream();
Packit df99a1
  virtual size_t read(void *buffer, size_t size);
Packit df99a1
  virtual size_t write(const void *buffer, size_t size);
Packit df99a1
  virtual long tell(void) const;
Packit df99a1
  // -- NAVIGATING CHUNKS
Packit df99a1
  /** Enters a chunk for reading.  Function #get_chunk# returns zero when the
Packit df99a1
      last chunk has already been accessed.  Otherwise it parses a chunk
Packit df99a1
      header, positions the IFFByteStream at the beginning of the chunk data,
Packit df99a1
      stores the extended chunk identifier into string #chkid#, and returns
Packit df99a1
      the non zero chunk size.  The file offset of the chunk data may be
Packit df99a1
      retrieved using function #tell#.  The chunk data can then be read using
Packit df99a1
      function #read# until reaching the end of the chunk.  Advanced users may
Packit df99a1
      supply two pointers to integer variables using arguments #rawoffsetptr#
Packit df99a1
      and #rawsizeptr#. These variables will be overwritten with the offset
Packit df99a1
      and the length of the file segment containing both the chunk header and
Packit df99a1
      the chunk data. */
Packit df99a1
  int get_chunk(GUTF8String &chkid, int *rawoffsetptr=0, int *rawsizeptr=0);
Packit df99a1
  /** Enters a chunk for writing.  Function #put_chunk# prepares a chunk
Packit df99a1
      header and positions the IFFByteStream at the beginning of the chunk
Packit df99a1
      data.  Argument #chkid# defines a extended chunk identifier for this
Packit df99a1
      chunk.  The chunk data can then be written using function #write#.  The
Packit df99a1
      chunk is terminated by a matching call to function #close_chunk#.  When
Packit df99a1
      #insertmagic# is non zero, function #put_chunk# inserts the bytes:
Packit df99a1
      0x41, 0x54, 0x26, 0x54 before the chunk header, as discussed in
Packit df99a1
      \Ref{IFFByteStream.h}. */
Packit df99a1
  void put_chunk(const char *chkid, int insertmagic=0);
Packit df99a1
  /** Leaves the current chunk.  This function leaves the chunk previously
Packit df99a1
      entered by a matching call to #get_chunk# and #put_chunk#.  The
Packit df99a1
      IFFByteStream is then ready to process the next chunk at the same
Packit df99a1
      hierarchical level. */
Packit df99a1
  void close_chunk();
Packit df99a1
  /** This is identical to the above, plus it adds a seek to the start of
Packit df99a1
      the next chunk.  This way we catch EOF errors with the current chunk.*/
Packit df99a1
  void seek_close_chunk();
Packit df99a1
  /** Returns true when it is legal to call #read# or #write#. */
Packit df99a1
  int ready();
Packit df99a1
  /** Returns true when the current chunk is a composite chunk. */
Packit df99a1
  int composite();
Packit df99a1
  /** Returns the current chunk identifier of the current chunk.  String
Packit df99a1
      #chkid# is overwritten with the {\em extended chunk identifier} of the
Packit df99a1
      current chunk.  The extended chunk identifier of a regular chunk is
Packit df99a1
      simply the chunk identifier, as in #"PM44"#.  The extended chunk
Packit df99a1
      identifier of a composite chunk is the concatenation of the chunk
Packit df99a1
      identifier, of a semicolon #":"#, and of the secondary chunk identifier,
Packit df99a1
      as in #"FORM:DJVU"#. */
Packit df99a1
  void short_id(GUTF8String &chkid);
Packit df99a1
  /** Returns the qualified chunk identifier of the current chunk.  String
Packit df99a1
      #chkid# is overwritten with the {\em qualified chunk identifier} of the
Packit df99a1
      current chunk.  The qualified chunk identifier of a composite chunk is
Packit df99a1
      equal to the extended chunk identifier.  The qualified chunk identifier
Packit df99a1
      of a regular chunk is composed by concatenating the secondary chunk
Packit df99a1
      identifier of the closest #"FORM"# or #"PROP"# composite chunk
Packit df99a1
      containing the current chunk, a dot #"."#, and the current chunk
Packit df99a1
      identifier, as in #"DJVU.INFO"#.  According to the EA IFF 85 identifier
Packit df99a1
      scoping rules, the qualified chunk identifier uniquely defines how the
Packit df99a1
      chunk data should be interpreted. */
Packit df99a1
  void full_id(GUTF8String &chkid);
Packit df99a1
  /** Checks a potential chunk identifier.  This function categorizes the
Packit df99a1
      chunk identifier formed by the first four characters of string #chkid#.
Packit df99a1
      It returns #0# if this is a legal identifier for a regular chunk.  It
Packit df99a1
      returns #+1# if this is a reserved composite chunk identifier.  It
Packit df99a1
      returns #-1# if this is an illegal or otherwise reserved identifier
Packit df99a1
      which should not be used.  */
Packit df99a1
  static int check_id(const char *id);
Packit df99a1
  GP<ByteStream> get_bytestream(void) {return this;}
Packit df99a1
  /** Copy data from another ByteStream.  A maximum of #size# bytes are read
Packit df99a1
      from the ByteStream #bsfrom# and are written to the ByteStream #*this#
Packit df99a1
      at the current position.  Less than #size# bytes may be written if an
Packit df99a1
      end-of-file mark is reached on #bsfrom#.  This function returns the
Packit df99a1
      total number of bytes copied.  Setting argument #size# to zero (the
Packit df99a1
      default value) has a special meaning: the copying process will continue
Packit df99a1
      until reaching the end-of-file mark on ByteStream #bsfrom#, regardless
Packit df99a1
      of the number of bytes transferred.  */
Packit df99a1
  size_t copy(ByteStream &bsfrom, size_t size=0)
Packit df99a1
  { return get_bytestream()->copy(bsfrom,size); }
Packit df99a1
  /** Flushes all buffers in the ByteStream.  Calling this function
Packit df99a1
      guarantees that pending data have been actually written (i.e. passed to
Packit df99a1
      the operating system). Class #ByteStream# provides a default
Packit df99a1
      implementation which does nothing. */
Packit df99a1
  virtual void flush(void)
Packit df99a1
  { ByteStream::Wrapper::flush(); }
Packit df99a1
  /** This is a simple compare method.  The IFFByteStream may be read for
Packit df99a1
      the sake of the comparison.  Since IFFByteStreams are non-seekable,
Packit df99a1
      the stream is not valid for use after comparing, regardless of the
Packit df99a1
      result. */
Packit df99a1
  bool compare(IFFByteStream &iff);
Packit df99a1
  /** #has_magic_att# is true if the stream has 
Packit df99a1
      the DjVu magic 'AT&T' marker. */
Packit df99a1
  bool has_magic_att;
Packit df99a1
  /** #has_magic_sdjv# is true if the stream has 
Packit df99a1
      the Celartem magic 'SDJV' marker. */
Packit df99a1
  bool has_magic_sdjv;
Packit df99a1
private:
Packit df99a1
  // private datatype
Packit df99a1
  struct IFFContext
Packit df99a1
  {
Packit df99a1
    IFFContext *next;
Packit df99a1
    long offStart;
Packit df99a1
    long offEnd;
Packit df99a1
    char idOne[4];
Packit df99a1
    char idTwo[4];
Packit df99a1
    char bComposite;
Packit df99a1
  };
Packit df99a1
  // Implementation
Packit df99a1
  IFFContext *ctx;
Packit df99a1
  long offset;
Packit df99a1
  long seekto;
Packit df99a1
  int dir;
Packit df99a1
  // Cancel C++ default stuff
Packit df99a1
  IFFByteStream(const IFFByteStream &);
Packit df99a1
  IFFByteStream & operator=(const IFFByteStream &);
Packit df99a1
  static GP<IFFByteStream> create(ByteStream *bs);
Packit df99a1
};
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