новые иконки в OpenBoard
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.
 
 
 
 
 
 
OpenBoard/src/pdf-merger/LZWDecode.cpp

217 lines
4.8 KiB

/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <iostream>
#include <QtGlobal>
#include "LZWDecode.h"
#include "FilterPredictor.h"
#include "core/memcheck.h"
// method performs decoding
using namespace merge_lib;
LZWDecode::LZWDecode():
_predict(NULL),
_dummy(""),
_encoded(_dummy),
_curSymbolIndex(0),
_earlyChange(1),
_readBuf(0),
_readBits(0),
_nextCode(0),
_bitsToRead(0),
_first(true),
_curSequenceLength(0)
{
clearTable();
}
LZWDecode::~LZWDecode()
{
if( _predict )
{
delete _predict;
}
}
bool LZWDecode::encode(std::string & decoded)
{
Q_UNUSED(decoded);
return true;
}
void LZWDecode::initialize(Object * objectWithStream)
{
if( objectWithStream )
{
std::string head;
objectWithStream->getHeader(head);
if((int) head.find(FilterPredictor::DECODE_PARAM_TOKEN) != -1 )
{
_predict = new FilterPredictor();
_predict->initialize(objectWithStream);
_earlyChange = _predict->getEarlyChange();
}
_readBits = 0;
_readBuf = 0;
clearTable();
}
}
void LZWDecode::clearTable()
{
_nextCode = 258;
_bitsToRead = 9;
_curSequenceLength = 0;
_first = true;
}
int LZWDecode::getCode()
{
int c = 0;
int code = 0;
while (_readBits < _bitsToRead)
{
if( _curSymbolIndex < _encoded.size() )
{
c = _encoded[_curSymbolIndex++];
}
else
{
return EOF;
}
_readBuf = (_readBuf << 8) | (c & 0xff);
_readBits += 8;
}
code = (_readBuf >> (_readBits - _bitsToRead)) & ((1 << _bitsToRead) - 1);
_readBits -= _bitsToRead;
return code;
}
// Method performs LZW decoding
bool LZWDecode::decode(std::string & encoded)
{
_curSymbolIndex = 0;
_encoded = encoded;
// LZW decoding
std::string decoded;
struct DecodingTable
{
int length;
int head;
unsigned tail;
} decTable[4097];
int prevCode = 0;
int newChar = 0;
unsigned curSequence[4097];
int nextLength = 0;
clearTable();
while(1)
{
int code = getCode();
if( code == EOF || code == 257 )
{
// finish
break;
}
if( code == 256 )
{
clearTable();
continue;
}
if( _nextCode >= 4997 )
{
std::cout<<"Bad LZW stream - unexpected clearTable\n";
clearTable();
continue;
}
nextLength = _curSequenceLength + 1;
if( code < 256 )
{
curSequence[ 0 ] = code;
_curSequenceLength = 1;
}
else if( code < _nextCode )
{
//lets take sequence from table
_curSequenceLength = decTable[code].length;
int j = code;
for( int i = _curSequenceLength - 1; i > 0; i--)
{
curSequence[ i ] = decTable[j].tail;
j = decTable[ j ].head;
}
curSequence[0] = j;
}
else if( code == _nextCode )
{
curSequence[ _curSequenceLength ] = newChar;
++_curSequenceLength;
}
else
{
std::cout<<"Bad LZW stream - unexpected code "<<code<<"\n";
break;
}
newChar = curSequence[0];
if( _first )
{
_first = false;
}
else
{
// lets build decoding table
decTable[ _nextCode ].length = nextLength;
decTable[ _nextCode ].head = prevCode;
decTable[ _nextCode ].tail = newChar;
++ _nextCode;
// processing of PDF LZW parameter
if (_nextCode + _earlyChange == 512)
{
_bitsToRead = 10;
}
else if (_nextCode + _earlyChange == 1024)
{
_bitsToRead = 11;
}
else if (_nextCode + _earlyChange == 2048)
{
_bitsToRead = 12;
}
}
prevCode = code;
// put current sequence to output stream
for(int i = 0;i < _curSequenceLength;i++)
{
decoded += (char)curSequence[ i ];
}
}
encoded = decoded;
// if predictor exists for that object, then lets decode it
if( _predict )
{
_predict->decode(encoded);
}
return true;
}