Blame libdjvu/BSByteStream.cpp

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
#ifdef HAVE_CONFIG_H
Packit df99a1
# include "config.h"
Packit df99a1
#endif
Packit df99a1
#if NEED_GNUG_PRAGMAS
Packit df99a1
# pragma implementation
Packit df99a1
#endif
Packit df99a1
Packit df99a1
// - Author: Leon Bottou, 07/1998
Packit df99a1
Packit df99a1
#include <stddef.h>
Packit df99a1
#include <stdlib.h>
Packit df99a1
#include <stdio.h>
Packit df99a1
#include <string.h>
Packit df99a1
#include "BSByteStream.h"
Packit df99a1
#undef BSORT_TIMER
Packit df99a1
#ifdef BSORT_TIMER
Packit df99a1
#include "GOS.h"
Packit df99a1
#endif
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
class BSByteStream::Decode : public BSByteStream
Packit df99a1
{
Packit df99a1
public:
Packit df99a1
  /** Creates a Static object for allocating the memory area of
Packit df99a1
      length #sz# starting at address #buffer#. */
Packit df99a1
  Decode(GP<ByteStream> bs);
Packit df99a1
  ~Decode();
Packit df99a1
  void init(void);
Packit df99a1
  // Virtual functions
Packit df99a1
  virtual size_t read(void *buffer, size_t sz);
Packit df99a1
  virtual void flush(void);
Packit df99a1
protected:
Packit df99a1
  unsigned int decode(void);
Packit df99a1
private:
Packit df99a1
  bool eof;
Packit df99a1
};
Packit df99a1
Packit df99a1
// ========================================
Packit df99a1
// --- Assertion
Packit df99a1
Packit df99a1
#define ASSERT(expr) do{if(!(expr))G_THROW("assertion ("#expr") failed");}while(0)
Packit df99a1
Packit df99a1
// ========================================
Packit df99a1
// --- Construction
Packit df99a1
Packit df99a1
BSByteStream::BSByteStream(GP<ByteStream> xbs)
Packit df99a1
: offset(0), bptr(0), blocksize(0), size(0), bs(xbs),
Packit df99a1
  gbs(xbs), gdata(data,0)
Packit df99a1
{
Packit df99a1
  // Initialize context array
Packit df99a1
  memset(ctx, 0, sizeof(ctx));
Packit df99a1
}
Packit df99a1
Packit df99a1
BSByteStream::~BSByteStream() {}
Packit df99a1
Packit df99a1
BSByteStream::Decode::Decode(GP<ByteStream> xbs)
Packit df99a1
: BSByteStream(xbs), eof(false) {}
Packit df99a1
Packit df99a1
void
Packit df99a1
BSByteStream::Decode::init(void)
Packit df99a1
{
Packit df99a1
  gzp=ZPCodec::create(gbs,false,true);
Packit df99a1
}
Packit df99a1
Packit df99a1
BSByteStream::Decode::~Decode() {}
Packit df99a1
Packit df99a1
GP<ByteStream>
Packit df99a1
BSByteStream::create(GP<ByteStream> xbs)
Packit df99a1
{
Packit df99a1
  BSByteStream::Decode *rbs=new BSByteStream::Decode(xbs);
Packit df99a1
  GP<ByteStream> retval=rbs;
Packit df99a1
  rbs->init();
Packit df99a1
  return retval;
Packit df99a1
}
Packit df99a1
Packit df99a1
void 
Packit df99a1
BSByteStream::Decode::flush()
Packit df99a1
{
Packit df99a1
  size = bptr = 0;
Packit df99a1
}
Packit df99a1
Packit df99a1
// ========================================
Packit df99a1
// -- Decoding
Packit df99a1
Packit df99a1
Packit df99a1
static int 
Packit df99a1
decode_raw(ZPCodec &zp, int bits)
Packit df99a1
{
Packit df99a1
  int n = 1;
Packit df99a1
  const int m = (1<
Packit df99a1
  while (n < m)
Packit df99a1
    {
Packit df99a1
      const int b = zp.decoder();
Packit df99a1
      n = (n<<1) | b;
Packit df99a1
    }
Packit df99a1
  return n - m;
Packit df99a1
}
Packit df99a1
Packit df99a1
static inline int 
Packit df99a1
decode_binary(ZPCodec &zp, BitContext *ctx, int bits)
Packit df99a1
{
Packit df99a1
  int n = 1;
Packit df99a1
  int m = (1<
Packit df99a1
  ctx = ctx - 1;
Packit df99a1
  while (n < m)
Packit df99a1
    {
Packit df99a1
      int b = zp.decoder(ctx[n]);
Packit df99a1
      n = (n<<1) | b;
Packit df99a1
    }
Packit df99a1
  return n - m;
Packit df99a1
}
Packit df99a1
  
Packit df99a1
unsigned int
Packit df99a1
BSByteStream::Decode::decode(void)
Packit df99a1
{
Packit df99a1
  /////////////////////////////////
Packit df99a1
  ////////////  Decode input stream
Packit df99a1
  
Packit df99a1
  int i;
Packit df99a1
  // Decode block size
Packit df99a1
  ZPCodec &zp=*gzp;
Packit df99a1
  size = decode_raw(zp, 24);
Packit df99a1
  if (!size)
Packit df99a1
    return 0;
Packit df99a1
  if (size>MAXBLOCK*1024)
Packit df99a1
    G_THROW( ERR_MSG("ByteStream.corrupt") );
Packit df99a1
  // Allocate
Packit df99a1
  if ((int)blocksize < size)
Packit df99a1
    {
Packit df99a1
      blocksize = size;
Packit df99a1
      if (data)
Packit df99a1
      {
Packit df99a1
        gdata.resize(0);
Packit df99a1
      }
Packit df99a1
    }
Packit df99a1
  if (! data) 
Packit df99a1
    gdata.resize(blocksize);
Packit df99a1
  // Decode Estimation Speed
Packit df99a1
  int fshift = 0;
Packit df99a1
  if (zp.decoder())
Packit df99a1
    {
Packit df99a1
      fshift += 1;
Packit df99a1
      if (zp.decoder())
Packit df99a1
        fshift += 1;
Packit df99a1
    }
Packit df99a1
  // Prepare Quasi MTF
Packit df99a1
  static const unsigned char xmtf[256]={
Packit df99a1
    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
Packit df99a1
    0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
Packit df99a1
    0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
Packit df99a1
    0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
Packit df99a1
    0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
Packit df99a1
    0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
Packit df99a1
    0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
Packit df99a1
    0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
Packit df99a1
    0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
Packit df99a1
    0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
Packit df99a1
    0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
Packit df99a1
    0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
Packit df99a1
    0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
Packit df99a1
    0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
Packit df99a1
    0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
Packit df99a1
    0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
Packit df99a1
    0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
Packit df99a1
    0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
Packit df99a1
    0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
Packit df99a1
    0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
Packit df99a1
    0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
Packit df99a1
    0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
Packit df99a1
    0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
Packit df99a1
    0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
Packit df99a1
    0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
Packit df99a1
    0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
Packit df99a1
    0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
Packit df99a1
    0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
Packit df99a1
    0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
Packit df99a1
    0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
Packit df99a1
    0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
Packit df99a1
    0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF};
Packit df99a1
  unsigned char mtf[256];
Packit df99a1
  memcpy(mtf,xmtf,sizeof(xmtf));
Packit df99a1
  unsigned int freq[FREQMAX];
Packit df99a1
  memset(freq,0,sizeof(freq));
Packit df99a1
  int fadd = 4;
Packit df99a1
  // Decode
Packit df99a1
  int mtfno = 3;
Packit df99a1
  int markerpos = -1;
Packit df99a1
  for (i=0; i
Packit df99a1
    {
Packit df99a1
      int ctxid = CTXIDS-1;
Packit df99a1
      if (ctxid>mtfno) ctxid=mtfno;
Packit df99a1
      BitContext *cx = ctx;
Packit df99a1
      if (zp.decoder(cx[ctxid]))
Packit df99a1
        { mtfno=0; data[i]=mtf[mtfno]; goto rotate; }
Packit df99a1
      cx+=CTXIDS;
Packit df99a1
      if (zp.decoder(cx[ctxid]))
Packit df99a1
        { mtfno=1; data[i]=mtf[mtfno]; goto rotate; } 
Packit df99a1
      cx+=CTXIDS;
Packit df99a1
      if (zp.decoder(cx[0]))
Packit df99a1
        { mtfno=2+decode_binary(zp,cx+1,1); data[i]=mtf[mtfno]; goto rotate; } 
Packit df99a1
      cx+=1+1;
Packit df99a1
      if (zp.decoder(cx[0]))
Packit df99a1
        { mtfno=4+decode_binary(zp,cx+1,2); data[i]=mtf[mtfno]; goto rotate; } 
Packit df99a1
      cx+=1+3;
Packit df99a1
      if (zp.decoder(cx[0]))
Packit df99a1
        { mtfno=8+decode_binary(zp,cx+1,3); data[i]=mtf[mtfno]; goto rotate; } 
Packit df99a1
      cx+=1+7;
Packit df99a1
      if (zp.decoder(cx[0]))
Packit df99a1
        { mtfno=16+decode_binary(zp,cx+1,4); data[i]=mtf[mtfno]; goto rotate; } 
Packit df99a1
      cx+=1+15;
Packit df99a1
      if (zp.decoder(cx[0]))
Packit df99a1
        { mtfno=32+decode_binary(zp,cx+1,5); data[i]=mtf[mtfno]; goto rotate; } 
Packit df99a1
      cx+=1+31;
Packit df99a1
      if (zp.decoder(cx[0]))
Packit df99a1
        { mtfno=64+decode_binary(zp,cx+1,6); data[i]=mtf[mtfno]; goto rotate; } 
Packit df99a1
      cx+=1+63;
Packit df99a1
      if (zp.decoder(cx[0]))
Packit df99a1
        { mtfno=128+decode_binary(zp,cx+1,7); data[i]=mtf[mtfno]; goto rotate; } 
Packit df99a1
      mtfno=256;
Packit df99a1
      data[i]=0;
Packit df99a1
      markerpos=i;
Packit df99a1
      continue;
Packit df99a1
      // Rotate mtf according to empirical frequencies (new!)
Packit df99a1
    rotate:
Packit df99a1
      // Adjust frequencies for overflow
Packit df99a1
      int k;
Packit df99a1
      fadd = fadd + (fadd>>fshift);
Packit df99a1
      if (fadd > 0x10000000) 
Packit df99a1
        {
Packit df99a1
          fadd    >>= 24;
Packit df99a1
          freq[0] >>= 24;
Packit df99a1
          freq[1] >>= 24;
Packit df99a1
          freq[2] >>= 24;
Packit df99a1
          freq[3] >>= 24;
Packit df99a1
          for (k=4; k
Packit df99a1
            freq[k] = freq[k]>>24;
Packit df99a1
        }
Packit df99a1
      // Relocate new char according to new freq
Packit df99a1
      unsigned int fc = fadd;
Packit df99a1
      if (mtfno < FREQMAX)
Packit df99a1
        fc += freq[mtfno];
Packit df99a1
      for (k=mtfno; k>=FREQMAX; k--) 
Packit df99a1
        mtf[k] = mtf[k-1];
Packit df99a1
      for (; k>0 && fc>=freq[k-1]; k--)
Packit df99a1
        {
Packit df99a1
          mtf[k] = mtf[k-1];
Packit df99a1
          freq[k] = freq[k-1];
Packit df99a1
        }
Packit df99a1
      mtf[k] = data[i];
Packit df99a1
      freq[k] = fc;
Packit df99a1
    }
Packit df99a1
  
Packit df99a1
Packit df99a1
  /////////////////////////////////
Packit df99a1
  ////////// Reconstruct the string
Packit df99a1
  
Packit df99a1
  if (markerpos<1 || markerpos>=size)
Packit df99a1
    G_THROW( ERR_MSG("ByteStream.corrupt") );
Packit df99a1
  // Allocate pointers
Packit df99a1
  unsigned int *posn;
Packit df99a1
  GPBuffer<unsigned int> gposn(posn,blocksize);
Packit df99a1
  memset(posn, 0, sizeof(unsigned int)*size);
Packit df99a1
  // Prepare count buffer
Packit df99a1
  int count[256];
Packit df99a1
  for (i=0; i<256; i++)
Packit df99a1
    count[i] = 0;
Packit df99a1
  // Fill count buffer
Packit df99a1
  for (i=0; i
Packit df99a1
    {
Packit df99a1
      unsigned char c = data[i];
Packit df99a1
      posn[i] = (c<<24) | (count[c] & 0xffffff);
Packit df99a1
      count[c] += 1;
Packit df99a1
    }
Packit df99a1
  for (i=markerpos+1; i
Packit df99a1
    {
Packit df99a1
      unsigned char c = data[i];
Packit df99a1
      posn[i] = (c<<24) | (count[c] & 0xffffff);
Packit df99a1
      count[c] += 1;
Packit df99a1
    }
Packit df99a1
  // Compute sorted char positions
Packit df99a1
  int last = 1;
Packit df99a1
  for (i=0; i<256; i++)
Packit df99a1
    {
Packit df99a1
      int tmp = count[i];
Packit df99a1
      count[i] = last;
Packit df99a1
      last += tmp;
Packit df99a1
    }
Packit df99a1
  // Undo the sort transform
Packit df99a1
  i = 0;
Packit df99a1
  last = size-1;
Packit df99a1
  while (last>0)
Packit df99a1
    {
Packit df99a1
      unsigned int n = posn[i];
Packit df99a1
      unsigned char c = (posn[i]>>24);
Packit df99a1
      data[--last] = c;
Packit df99a1
      i = count[c] + (n & 0xffffff);
Packit df99a1
    }
Packit df99a1
  // Free and check
Packit df99a1
  if (i != markerpos)
Packit df99a1
    G_THROW( ERR_MSG("ByteStream.corrupt") );
Packit df99a1
  return size;
Packit df99a1
}
Packit df99a1
Packit df99a1
Packit df99a1
Packit df99a1
// ========================================
Packit df99a1
// -- ByteStream interface
Packit df99a1
Packit df99a1
Packit df99a1
Packit df99a1
long 
Packit df99a1
BSByteStream::tell() const
Packit df99a1
{
Packit df99a1
  return offset;
Packit df99a1
}
Packit df99a1
Packit df99a1
size_t 
Packit df99a1
BSByteStream::Decode::read(void *buffer, size_t sz)
Packit df99a1
{
Packit df99a1
  if (eof)
Packit df99a1
    return 0;
Packit df99a1
  // Loop
Packit df99a1
  int copied = 0;
Packit df99a1
  while (sz>0 && !eof)
Packit df99a1
    {
Packit df99a1
      // Decode if needed
Packit df99a1
      if (!size)
Packit df99a1
        {
Packit df99a1
          bptr = 0;
Packit df99a1
          if (! decode()) 
Packit df99a1
          {
Packit df99a1
            size = 1 ;
Packit df99a1
            eof = true;
Packit df99a1
          }
Packit df99a1
          size -= 1;
Packit df99a1
        }
Packit df99a1
      // Compute remaining
Packit df99a1
      int bytes = size;
Packit df99a1
      if (bytes > (int)sz)
Packit df99a1
        bytes = sz;
Packit df99a1
      // Transfer
Packit df99a1
      if (buffer && bytes)
Packit df99a1
        {
Packit df99a1
          memcpy(buffer, data+bptr, bytes);
Packit df99a1
          buffer = (void*)((char*)buffer + bytes);
Packit df99a1
        }
Packit df99a1
      size -= bytes;
Packit df99a1
      bptr += bytes;
Packit df99a1
      sz -= bytes;
Packit df99a1
      copied += bytes;
Packit df99a1
      offset += bytes;
Packit df99a1
    }
Packit df99a1
  // Return copied bytes
Packit df99a1
  return copied;
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