kde-playground/kdepimlibs/ktnef/lzfu.cpp
2015-04-14 21:49:29 +00:00

183 lines
5.2 KiB
C++

/*
lzfu.cpp
Copyright (C) 2003 Michael Goffioul <kdeprint@swing.be>
This file is part of KTNEF, the KDE TNEF support library/program.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
/**
* @file
* This file is part of the API for handling TNEF data and
* provides the @acronym LZFU decompression functionality.
*
* @author Michael Goffioul
*/
#include "lzfu.h"
#include <QtCore/QIODevice>
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
//#define DO_DEBUG
//@cond IGNORE
#define LZFU_COMPRESSED 0x75465a4c
#define LZFU_UNCOMPRESSED 0x414c454d
#define LZFU_INITDICT "{\\rtf1\\ansi\\mac\\deff0\\deftab720{\\fonttbl;}" \
"{\\f0\\fnil \\froman \\fswiss \\fmodern \\fscrip" \
"t \\fdecor MS Sans SerifSymbolArialTimes Ne" \
"w RomanCourier{\\colortbl\\red0\\green0\\blue0" \
"\r\n\\par \\pard\\plain\\f0\\fs20\\b\\i\\u\\tab" \
"\\tx"
#define LZFU_INITLENGTH 207
//@endcond
//@cond PRIVATE
typedef struct _lzfuheader
{
quint32 cbSize;
quint32 cbRawSize;
quint32 dwMagic;
quint32 dwCRC;
} lzfuheader;
//@endcond
//@cond IGNORE
#define FLAG(f,n) (f>>n)&0x1
/*typedef struct _blockheader {
unsigned int offset:12;
unsigned int length:4;
} blockheader;*/
#define OFFSET(b) (b>>4)&0xFFF
#define LENGTH(b) ((b&0xF)+2)
//@endcond
int lzfu_decompress( QIODevice *input, QIODevice *output )
{
unsigned char window[4096];
unsigned int wlength = 0, cursor = 0, ocursor = 0;
lzfuheader lzfuhdr;
//blockheader blkhdr;
quint16 blkhdr;
char bFlags;
int nFlags;
memcpy( window, LZFU_INITDICT, LZFU_INITLENGTH );
wlength = LZFU_INITLENGTH;
if ( input->read( (char *)&lzfuhdr, sizeof(lzfuhdr) ) != sizeof(lzfuhdr) ) {
fprintf( stderr, "unexpected eof, cannot read LZFU header\n" );
return -1;
}
cursor += sizeof( lzfuhdr );
#ifdef DO_DEBUG
fprintf( stdout, "total size : %d\n", lzfuhdr.cbSize+4 );
fprintf( stdout, "raw size : %d\n", lzfuhdr.cbRawSize );
fprintf( stdout, "compressed : %s\n", ( lzfuhdr.dwMagic == LZFU_COMPRESSED ? "yes" : "no" ) );
fprintf( stdout, "CRC : %x\n", lzfuhdr.dwCRC );
fprintf( stdout, "\n" );
#endif
while ( cursor < lzfuhdr.cbSize+4 && ocursor < lzfuhdr.cbRawSize && !input->atEnd() ) {
if ( input->read( &bFlags, 1 ) != 1 ) {
fprintf( stderr, "unexpected eof, cannot read chunk flag\n" );
return -1;
}
nFlags = 8;
cursor++;
#ifdef DO_DEBUG
fprintf( stdout, "Flags : " );
for ( int i=nFlags-1; i>=0; i-- ) {
fprintf( stdout, "%d", FLAG( bFlags, i ) );
}
fprintf( stdout, "\n" );
#endif
for ( int i=0; i<nFlags && ocursor<lzfuhdr.cbRawSize && cursor<lzfuhdr.cbSize+4; i++ ) {
if ( FLAG( bFlags, i ) ) {
// compressed chunck
char c1, c2;
if ( input->read( &c1, 1 ) != 1 || input->read( &c2, 1 ) != 1 ) {
fprintf( stderr, "unexpected eof, cannot read block header\n" );
return -1;
}
blkhdr = c1;
blkhdr <<= 8;
blkhdr |= ( 0xFF & c2 );
unsigned int offset = OFFSET( blkhdr ), length = LENGTH( blkhdr );
cursor += 2;
#ifdef DO_DEBUG
fprintf( stdout, "block : offset=%.4d [%d], length=%.2d (0x%04X)\n",
OFFSET( blkhdr ), wlength, LENGTH( blkhdr ), blkhdr );
#endif
//if ( offset >= wlength ) {
// break;
//}
#ifdef DO_DEBUG
fprintf( stdout, "block : " );
#endif
for ( unsigned int i=0; i<length; i++ ) {
c1 = window[( offset + i ) % 4096];
//if ( wlength < 4096 ) {
window[wlength] = c1;
wlength = ( wlength + 1 ) % 4096;
//}
#ifdef DO_DEBUG
if ( c1 == '\n' ) {
fprintf( stdout, "\nblock : " );
} else {
fprintf( stdout, "%c", c1 );
}
#endif
output->putChar( c1 );
ocursor++;
}
#ifdef DO_DEBUG
fprintf( stdout, "\n" );
#endif
} else {
// uncompressed chunk (char)
char c;
if ( !input->getChar( &c ) ) {
if ( !input->atEnd() ) {
fprintf( stderr, "unexpected eof, cannot read character\n" );
return -1;
}
break;
}
#ifdef DO_DEBUG
fprintf( stdout, "char : %c\n", c );
#endif
cursor++;
//if ( wlength < 4096 ) {
window[wlength] = c;
wlength = ( wlength+1 ) % 4096;
//}
output->putChar( c );
ocursor++;
}
}
}
return 0;
}