You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegraphics/kviewshell/plugins/djvu/libdjvu/BSByteStream.cpp

465 lines
13 KiB

//C- -------------------------------------------------------------------
//C- DjVuLibre-3.5
//C- Copyright (c) 2002 Leon Bottou and Yann Le Cun.
//C- Copyright (c) 2001 AT&T
//C-
//C- This software is subject to, and may be distributed under, the
//C- GNU General Public License, Version 2. The license should have
//C- accompanied the software or you may obtain a copy of the license
//C- from the Free Software Foundation at http://www.fsf.org .
//C-
//C- This program is distributed in the hope that it will be useful,
//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//C- GNU General Public License for more details.
//C-
//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library
//C- distributed by Lizardtech Software. On July 19th 2002, Lizardtech
//C- Software authorized us to replace the original DjVu(r) Reference
//C- Library notice by the following text (see doc/lizard2002.djvu):
//C-
//C- ------------------------------------------------------------------
//C- | DjVu (r) Reference Library (v. 3.5)
//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
//C- | The DjVu Reference Library is protected by U.S. Pat. No.
//C- | 6,058,214 and patents pending.
//C- |
//C- | This software is subject to, and may be distributed under, the
//C- | GNU General Public License, Version 2. The license should have
//C- | accompanied the software or you may obtain a copy of the license
//C- | from the Free Software Foundation at http://www.fsf.org .
//C- |
//C- | The computer code originally released by LizardTech under this
//C- | license and unmodified by other parties is deemed "the LIZARDTECH
//C- | ORIGINAL CODE." Subject to any third party intellectual property
//C- | claims, LizardTech grants recipient a worldwide, royalty-free,
//C- | non-exclusive license to make, use, sell, or otherwise dispose of
//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the
//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU
//C- | General Public License. This grant only confers the right to
//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to
//C- | the extent such infringement is reasonably necessary to enable
//C- | recipient to make, have made, practice, sell, or otherwise dispose
//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to
//C- | any greater extent that may be necessary to utilize further
//C- | modifications or combinations.
//C- |
//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
//C- +------------------------------------------------------------------
//
// $Id: BSByteStream.cpp,v 1.8 2003/11/07 22:08:20 leonb Exp $
// $Name: release_3_5_15 $
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#if NEED_GNUG_PRAGMAS
# pragma implementation
#endif
// - Author: Leon Bottou, 07/1998
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "BSByteStream.h"
#undef BSORT_TIMER
#ifdef BSORT_TIMER
#include "GOS.h"
#endif
#ifdef HAVE_NAMESPACES
namespace DJVU {
# ifdef NOT_DEFINED // Just to fool emacs c++ mode
}
#endif
#endif
class BSByteStream::Decode : public BSByteStream
{
public:
/** Creates a Static object for allocating the memory area of
length #sz# starting at address #buffer#. */
Decode(GP<ByteStream> bs);
~Decode();
void init(void);
// Virtual functions
virtual size_t read(void *buffer, size_t sz);
virtual void flush(void);
protected:
unsigned int decode(void);
private:
bool eof;
};
// ========================================
// --- Assertion
#define ASSERT(expr) do{if(!(expr))G_THROW("assertion ("#expr") failed");}while(0)
// ========================================
// --- Construction
BSByteStream::BSByteStream(GP<ByteStream> xbs)
: offset(0), bptr(0), blocksize(0), size(0), bs(xbs),
gbs(xbs), gdata(data,0)
{
// Initialize context array
memset(ctx, 0, sizeof(ctx));
}
BSByteStream::~BSByteStream() {}
BSByteStream::Decode::Decode(GP<ByteStream> xbs)
: BSByteStream(xbs), eof(false) {}
void
BSByteStream::Decode::init(void)
{
gzp=ZPCodec::create(gbs,false,true);
}
BSByteStream::Decode::~Decode() {}
GP<ByteStream>
BSByteStream::create(GP<ByteStream> xbs)
{
BSByteStream::Decode *rbs=new BSByteStream::Decode(xbs);
GP<ByteStream> retval=rbs;
rbs->init();
return retval;
}
void
BSByteStream::Decode::flush()
{
size = bptr = 0;
}
// ========================================
// -- Decoding
static int
decode_raw(ZPCodec &zp, int bits)
{
int n = 1;
const int m = (1<<bits);
while (n < m)
{
const int b = zp.decoder();
n = (n<<1) | b;
}
return n - m;
}
static inline int
decode_binary(ZPCodec &zp, BitContext *ctx, int bits)
{
int n = 1;
int m = (1<<bits);
ctx = ctx - 1;
while (n < m)
{
int b = zp.decoder(ctx[n]);
n = (n<<1) | b;
}
return n - m;
}
static inline void
assignmtf(unsigned char xmtf[256])
{
static const unsigned char mtf[256]={
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF};
memcpy(xmtf,mtf,sizeof(mtf));
}
unsigned int
BSByteStream::Decode::decode(void)
{
/////////////////////////////////
//////////// Decode input stream
int i;
// Decode block size
ZPCodec &zp=*gzp;
size = decode_raw(zp, 24);
if (!size)
return 0;
if (size>MAXBLOCK*1024)
G_THROW( ERR_MSG("ByteStream.corrupt") );
// Allocate
if ((int)blocksize < size)
{
blocksize = size;
if (data)
{
gdata.resize(0);
}
}
if (! data)
gdata.resize(blocksize);
// Decode Estimation Speed
int fshift = 0;
if (zp.decoder())
{
fshift += 1;
if (zp.decoder())
fshift += 1;
}
// Prepare Quasi MTF
static const unsigned char xmtf[256]={
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF};
unsigned char mtf[256];
memcpy(mtf,xmtf,sizeof(xmtf));
unsigned int freq[FREQMAX];
memset(freq,0,sizeof(freq));
int fadd = 4;
// Decode
int mtfno = 3;
int markerpos = -1;
for (i=0; i<size; i++)
{
int ctxid = CTXIDS-1;
if (ctxid>mtfno) ctxid=mtfno;
BitContext *cx = ctx;
if (zp.decoder(cx[ctxid]))
{ mtfno=0; data[i]=mtf[mtfno]; goto rotate; }
cx+=CTXIDS;
if (zp.decoder(cx[ctxid]))
{ mtfno=1; data[i]=mtf[mtfno]; goto rotate; }
cx+=CTXIDS;
if (zp.decoder(cx[0]))
{ mtfno=2+decode_binary(zp,cx+1,1); data[i]=mtf[mtfno]; goto rotate; }
cx+=1+1;
if (zp.decoder(cx[0]))
{ mtfno=4+decode_binary(zp,cx+1,2); data[i]=mtf[mtfno]; goto rotate; }
cx+=1+3;
if (zp.decoder(cx[0]))
{ mtfno=8+decode_binary(zp,cx+1,3); data[i]=mtf[mtfno]; goto rotate; }
cx+=1+7;
if (zp.decoder(cx[0]))
{ mtfno=16+decode_binary(zp,cx+1,4); data[i]=mtf[mtfno]; goto rotate; }
cx+=1+15;
if (zp.decoder(cx[0]))
{ mtfno=32+decode_binary(zp,cx+1,5); data[i]=mtf[mtfno]; goto rotate; }
cx+=1+31;
if (zp.decoder(cx[0]))
{ mtfno=64+decode_binary(zp,cx+1,6); data[i]=mtf[mtfno]; goto rotate; }
cx+=1+63;
if (zp.decoder(cx[0]))
{ mtfno=128+decode_binary(zp,cx+1,7); data[i]=mtf[mtfno]; goto rotate; }
mtfno=256;
data[i]=0;
markerpos=i;
continue;
// Rotate mtf according to empirical frequencies (new!)
rotate:
// Adjust frequencies for overflow
int k;
fadd = fadd + (fadd>>fshift);
if (fadd > 0x10000000)
{
fadd >>= 24;
freq[0] >>= 24;
freq[1] >>= 24;
freq[2] >>= 24;
freq[3] >>= 24;
for (k=4; k<FREQMAX; k++)
freq[k] = freq[k]>>24;
}
// Relocate new char according to new freq
unsigned int fc = fadd;
if (mtfno < FREQMAX)
fc += freq[mtfno];
for (k=mtfno; k>=FREQMAX; k--)
mtf[k] = mtf[k-1];
for (; k>0 && fc>=freq[k-1]; k--)
{
mtf[k] = mtf[k-1];
freq[k] = freq[k-1];
}
mtf[k] = data[i];
freq[k] = fc;
}
/////////////////////////////////
////////// Reconstruct the string
if (markerpos<1 || markerpos>=size)
G_THROW( ERR_MSG("ByteStream.corrupt") );
// Allocate pointers
unsigned int *posn;
GPBuffer<unsigned int> gposn(posn,blocksize);
memset(posn, 0, sizeof(unsigned int)*size);
// Prepare count buffer
int count[256];
for (i=0; i<256; i++)
count[i] = 0;
// Fill count buffer
for (i=0; i<markerpos; i++)
{
unsigned char c = data[i];
posn[i] = (c<<24) | (count[c] & 0xffffff);
count[c] += 1;
}
for (i=markerpos+1; i<size; i++)
{
unsigned char c = data[i];
posn[i] = (c<<24) | (count[c] & 0xffffff);
count[c] += 1;
}
// Compute sorted char positions
int last = 1;
for (i=0; i<256; i++)
{
int tmp = count[i];
count[i] = last;
last += tmp;
}
// Undo the sort transform
i = 0;
last = size-1;
while (last>0)
{
unsigned int n = posn[i];
unsigned char c = (posn[i]>>24);
data[--last] = c;
i = count[c] + (n & 0xffffff);
}
// Free and check
if (i != markerpos)
G_THROW( ERR_MSG("ByteStream.corrupt") );
return size;
}
// ========================================
// -- ByteStream interface
long
BSByteStream::tell() const
{
return offset;
}
size_t
BSByteStream::Decode::read(void *buffer, size_t sz)
{
if (eof)
return 0;
// Loop
int copied = 0;
while (sz>0 && !eof)
{
// Decode if needed
if (!size)
{
bptr = 0;
if (! decode())
{
size = 1 ;
eof = true;
}
size -= 1;
}
// Compute remaining
int bytes = size;
if (bytes > (int)sz)
bytes = sz;
// Transfer
if (buffer && bytes)
{
memcpy(buffer, data+bptr, bytes);
buffer = (void*)((char*)buffer + bytes);
}
size -= bytes;
bptr += bytes;
sz -= bytes;
copied += bytes;
offset += bytes;
}
// Return copied bytes
return copied;
}
#ifdef HAVE_NAMESPACES
}
# ifndef NOT_USING_DJVU_NAMESPACE
using namespace DJVU;
# endif
#endif