/* lzfu.cpp Copyright (C) 2003 Michael Goffioul 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 #include #include #include //#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; iread( &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; iputChar( 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; }