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 |
55 | typedef struct |
56 | { |
57 | quint32 ; |
58 | quint32 ; |
59 | quint32 ; |
60 | quint32 ; |
61 | } ; |
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 | |
76 | int 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 | |