diff options
Diffstat (limited to 'ktnef/lib/lzfu.cpp')
-rw-r--r-- | ktnef/lib/lzfu.cpp | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/ktnef/lib/lzfu.cpp b/ktnef/lib/lzfu.cpp new file mode 100644 index 000000000..ab4fa36a0 --- /dev/null +++ b/ktnef/lib/lzfu.cpp @@ -0,0 +1,178 @@ +/* + lzfu.cpp + + Copyright (C) 2003 Michael Goffioul <kdeprint@swing.be> + + This file is part of KTNEF, the KDE TNEF support library/program. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" + +#include "lzfu.h" + +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif +#include <sys/types.h> +#include <string.h> +#include <qiodevice.h> +#include <stdio.h> + +//#define DO_DEBUG + +#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 + +typedef struct _lzfuheader { + uint32_t cbSize; + uint32_t cbRawSize; + uint32_t dwMagic; + uint32_t dwCRC; +} lzfuheader; + +#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) + +int lzfu_decompress(QIODevice *input, QIODevice *output) +{ + unsigned char window[4096]; + unsigned int wlength = 0, cursor = 0, ocursor = 0; + lzfuheader lzfuhdr; + //blockheader blkhdr; + uint16_t blkhdr; + char bFlags; + int nFlags; + + memcpy(window, LZFU_INITDICT, LZFU_INITLENGTH); + wlength = LZFU_INITLENGTH; + if (input->readBlock((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->readBlock(&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->readBlock(&c1, 1) != 1 || input->readBlock(&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->putch(c1); + ocursor++; + } +#ifdef DO_DEBUG + fprintf( stdout, "\n" ); +#endif + } + else + { + // uncompressed chunk (char) + signed char c = (char)input->getch(); + if (c == -1) + { + 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->putch(c); + ocursor++; + } + } + + } + + return 0; +} |