1/*
2 lzfu.cpp
3
4 Copyright (C) 2003 Michael Goffioul <kdeprint@swing.be>
5
6 This file is part of KTNEF, the KDE TNEF support library/program.
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
22 */
23/**
24 * @file
25 * This file is part of the API for handling TNEF data and
26 * provides the @acronym LZFU decompression functionality.
27 *
28 * @author Michael Goffioul
29 */
30
31#include "lzfu.h"
32
33#include <QtCore/QIODevice>
34
35#include <sys/types.h>
36#include <string.h>
37#include <stdio.h>
38
39//#define DO_DEBUG
40
41//@cond IGNORE
42#define LZFU_COMPRESSED 0x75465a4c
43#define LZFU_UNCOMPRESSED 0x414c454d
44
45#define LZFU_INITDICT "{\\rtf1\\ansi\\mac\\deff0\\deftab720{\\fonttbl;}" \
46 "{\\f0\\fnil \\froman \\fswiss \\fmodern \\fscrip" \
47 "t \\fdecor MS Sans SerifSymbolArialTimes Ne" \
48 "w RomanCourier{\\colortbl\\red0\\green0\\blue0" \
49 "\r\n\\par \\pard\\plain\\f0\\fs20\\b\\i\\u\\tab" \
50 "\\tx"
51#define LZFU_INITLENGTH 207
52//@endcond
53
54//@cond PRIVATE
55typedef struct _lzfuheader
56{
57 quint32 cbSize;
58 quint32 cbRawSize;
59 quint32 dwMagic;
60 quint32 dwCRC;
61} lzfuheader;
62//@endcond
63
64//@cond IGNORE
65#define FLAG(f,n) (f>>n)&0x1
66
67/*typedef struct _blockheader {
68 unsigned int offset:12;
69 unsigned int length:4;
70 } blockheader;*/
71
72#define OFFSET(b) (b>>4)&0xFFF
73#define LENGTH(b) ((b&0xF)+2)
74//@endcond
75
76int lzfu_decompress( QIODevice *input, QIODevice *output )
77{
78 unsigned char window[4096];
79 unsigned int wlength = 0, cursor = 0, ocursor = 0;
80 lzfuheader lzfuhdr;
81 //blockheader blkhdr;
82 quint16 blkhdr;
83 char bFlags;
84 int nFlags;
85
86 memcpy( window, LZFU_INITDICT, LZFU_INITLENGTH );
87 wlength = LZFU_INITLENGTH;
88 if ( input->read( (char *)&lzfuhdr, sizeof(lzfuhdr) ) != sizeof(lzfuhdr) ) {
89 fprintf( stderr, "unexpected eof, cannot read LZFU header\n" );
90 return -1;
91 }
92 cursor += sizeof( lzfuhdr );
93#ifdef DO_DEBUG
94 fprintf( stdout, "total size : %d\n", lzfuhdr.cbSize+4 );
95 fprintf( stdout, "raw size : %d\n", lzfuhdr.cbRawSize );
96 fprintf( stdout, "compressed : %s\n", ( lzfuhdr.dwMagic == LZFU_COMPRESSED ? "yes" : "no" ) );
97 fprintf( stdout, "CRC : %x\n", lzfuhdr.dwCRC );
98 fprintf( stdout, "\n" );
99#endif
100
101 while ( cursor < lzfuhdr.cbSize+4 && ocursor < lzfuhdr.cbRawSize && !input->atEnd() ) {
102 if ( input->read( &bFlags, 1 ) != 1 ) {
103 fprintf( stderr, "unexpected eof, cannot read chunk flag\n" );
104 return -1;
105 }
106 nFlags = 8;
107 cursor++;
108#ifdef DO_DEBUG
109 fprintf( stdout, "Flags : " );
110 for ( int i=nFlags-1; i>=0; i-- ) {
111 fprintf( stdout, "%d", FLAG( bFlags, i ) );
112 }
113 fprintf( stdout, "\n" );
114#endif
115 for ( int i=0; i<nFlags && ocursor<lzfuhdr.cbRawSize && cursor<lzfuhdr.cbSize+4; i++ ) {
116 if ( FLAG( bFlags, i ) ) {
117 // compressed chunck
118 char c1, c2;
119 if ( input->read( &c1, 1 ) != 1 || input->read( &c2, 1 ) != 1 ) {
120 fprintf( stderr, "unexpected eof, cannot read block header\n" );
121 return -1;
122 }
123 blkhdr = c1;
124 blkhdr <<= 8;
125 blkhdr |= ( 0xFF & c2 );
126 unsigned int offset = OFFSET( blkhdr ), length = LENGTH( blkhdr );
127 cursor += 2;
128#ifdef DO_DEBUG
129 fprintf( stdout, "block : offset=%.4d [%d], length=%.2d (0x%04X)\n",
130 OFFSET( blkhdr ), wlength, LENGTH( blkhdr ), blkhdr );
131#endif
132 //if ( offset >= wlength ) {
133 // break;
134 //}
135#ifdef DO_DEBUG
136 fprintf( stdout, "block : " );
137#endif
138 for ( unsigned int i=0; i<length; i++ ) {
139 c1 = window[( offset + i ) % 4096];
140 //if ( wlength < 4096 ) {
141 window[wlength] = c1;
142 wlength = ( wlength + 1 ) % 4096;
143 //}
144#ifdef DO_DEBUG
145 if ( c1 == '\n' ) {
146 fprintf( stdout, "\nblock : " );
147 } else {
148 fprintf( stdout, "%c", c1 );
149 }
150#endif
151 output->putChar( c1 );
152 ocursor++;
153 }
154#ifdef DO_DEBUG
155 fprintf( stdout, "\n" );
156#endif
157 } else {
158 // uncompressed chunk (char)
159 char c;
160 if ( !input->getChar( &c ) ) {
161 if ( !input->atEnd() ) {
162 fprintf( stderr, "unexpected eof, cannot read character\n" );
163 return -1;
164 }
165 break;
166 }
167#ifdef DO_DEBUG
168 fprintf( stdout, "char : %c\n", c );
169#endif
170 cursor++;
171 //if ( wlength < 4096 ) {
172 window[wlength] = c;
173 wlength = ( wlength+1 ) % 4096;
174 //}
175 output->putChar( c );
176 ocursor++;
177 }
178 }
179
180 }
181
182 return 0;
183}
184