1
/***************************************************************************
2
* Copyright (C) 2008 by Valerio Pilo *
5
* This program is free software; you can redistribute it and/or modify *
6
* it under the terms of the GNU Lesser General Public License as *
7
* published by the Free Software Foundation; either version 2.1 of the *
8
* License, or (at your option) any later version. *
10
* This program is distributed in the hope that it will be useful, *
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13
* GNU General Public License for more details. *
15
* You should have received a copy of the GNU Lesser General Public *
16
* License along with this program; if not, write to the *
17
* Free Software Foundation, Inc., *
18
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19
***************************************************************************/
23
#include "isfqt-internal.h"
28
#define HUFFMAN_BASES_NUM 8
29
#define HUFFMAN_BASE_SIZE 11
32
using namespace Isf::Compress;
36
const int bitAmounts_[HUFFMAN_BASES_NUM][HUFFMAN_BASE_SIZE] =
38
{0, 1, 2, 4, 6, 8, 12, 16, 24, 32, -1},
39
{0, 1, 1, 2, 4, 8, 12, 16, 24, 32, -1},
40
{0, 1, 1, 1, 2, 4, 8, 14, 22, 32, -1},
41
{0, 2, 2, 3, 5, 8, 12, 16, 24, 32, -1},
42
{0, 3, 4, 5, 8, 12, 16, 24, 32, -1, -1},
43
{0, 4, 6, 8, 12, 16, 24, 32, -1, -1, -1},
44
{0, 6, 8, 12, 16, 24, 32, -1, -1, -1, -1},
45
{0, 7, 8, 12, 16, 24, 32, -1, -1, -1, -1},
49
/// Huffman codec value bases.
50
const int huffmanBases_[HUFFMAN_BASES_NUM][HUFFMAN_BASE_SIZE] =
52
{0, 1, 2, 4, 12, 44, 172, 2220, 34988, 8423596, -1},
53
{0, 1, 2, 3, 5, 13, 141, 2189, 34957, 8423565, -1},
54
{0, 1, 2, 3, 4, 6, 14, 142, 8334, 2105486, -1},
55
{0, 1, 3, 5, 9, 25, 153, 2201, 34969, 8423577, -1},
56
{0, 1, 5, 13, 29, 157, 2205, 34973, 8423581, -1, -1},
57
{0, 1, 9, 41, 169, 2217, 34985, 8423593, -1, -1, -1},
58
{0, 1, 33, 161, 2209, 34977, 8423585, -1, -1, -1, -1},
59
{0, 1, 65, 193, 2241, 35009, 8423617, -1, -1, -1, -1},
65
* Get the most appropriate index for the given data.
67
* @param data Data to analyze
70
quint8 HuffmanAlgorithm::index( const QList<qint64> &data )
74
// TODO: Find out what the Huffman index algorithm is
84
* Compress data with the Huffman algorithm.
86
* @param encodedData Byte array where to store the compressed data
87
* @param index Index to use for compression
88
* @param source List of values to compress
91
bool HuffmanAlgorithm::deflate( QByteArray &encodedData, quint8 index, const QList<qint64> &source )
93
DataSource output( encodedData );
94
output.skipToNextByte();
96
foreach( quint64 value, source )
98
if( ! deflateValue( output, index, value ) )
101
qDebug() << "Deflating failure for value:" << value;
107
// Flush any leftover bit to the byte array
110
encodedData = output.data();
117
* Compress a single value with the Huffman algorithm.
119
* @param output Data source where to store the compressed value
120
* @param index Index to use for compression
121
* @param value Value to compress
124
bool HuffmanAlgorithm::deflateValue( DataSource &output, quint8 index, qint64 value )
127
quint8 requiredBits = 0;
130
// Fill in a bitAmounts local vector
131
QVector<int> bitAmounts;
132
for( int i = 0; i < HUFFMAN_BASE_SIZE; ++i )
134
if( bitAmounts_[ index ][ i ] == -1 )
139
bitAmounts.append( bitAmounts_[ index ][ i ] );
142
// Find the number of bits needed to store this value
149
while( ! bitAmounts.count( requiredBits ) )
154
qint64 offset = ( value < 0 ) ? -value : +value;
157
for( prefixLength = 1;
158
( prefixLength < HUFFMAN_BASE_SIZE ) && ( offset >= huffmanBases_[ index ][ prefixLength ] ); prefixLength++ )
160
// Empty loop on purpose
164
// Write prefixLength 1s to the stream, then a 0
165
QBitArray bits( prefixLength );
167
bits.clearBit( bits.size() - 1 );
169
// Write the number using the minimum possible number of bits
170
qint32 size = bitAmounts_[ index ][ prefixLength - 1 ];
171
qint64 mask = ( 1 << ( size - 1 ) ) - 1;
173
valueBits.resize( size );
174
offset = ( offset - huffmanBases_[ index ][ prefixLength - 1 ] ) & mask;
176
offset |= ( value < 0 ) ? 1 : 0;
178
// Copy the resulting offset
179
for( qint64 i = 0; i < size; ++i )
181
valueBits.setBit( i, offset & ( 1 << ( size - i - 1 ) ) );
184
// Add the bits to the data source
185
output.append( bits );
186
output.append( valueBits );
194
* Decompress data with the Huffman algorithm.
196
* @param source Data source where to read the compressed bytes
197
* @param length Number of items to read
198
* @param index Index to use for compression
199
* @param decodedData List where to place decompressed values
202
bool HuffmanAlgorithm::inflate( DataSource &source, quint64 length, quint8 index, QList<qint64> &decodedData )
204
QVector<int> huffmanBases;
205
QVector<int> bitAmounts( HUFFMAN_BASE_SIZE );
207
// Initialize the bit amounts vector
208
memcpy( bitAmounts.data(), bitAmounts_[ index ], sizeof(int)*HUFFMAN_BASE_SIZE );
211
huffmanBases.append( 0 );
213
// Fill up the huffman bases vector
214
for( quint8 i = 0; i < bitAmounts.size(); ++i )
216
int value = bitAmounts[ i ];
218
// The bit amounts sequence ends in -1
221
bitAmounts.resize( i );
230
huffmanBases.append( base );
231
base += pow( 2, value - 1 );
239
while( (uint)decodedData.length() < length )
241
bit = source.getBit();
253
else if( count < (uint)bitAmounts.size() )
255
quint64 offset = source.getBits( bitAmounts[ count ] );
256
bool sign = offset & 0x1;
258
value = huffmanBases[ count ] + offset;
259
value *= ( sign ? -1 : +1 );
261
else if( count == (uint)bitAmounts.size() )
263
// TODO: Implement 64-bit data decompression :)
265
qDebug() << "Unsupported 64-bit value found!";
272
qDebug() << "Decompression error!";
277
decodedData.append( value );