File indexing completed on 2024-04-28 05:19:26
0001 /* 0002 lzfu.cpp 0003 0004 SPDX-FileCopyrightText: 2003 Michael Goffioul <kdeprint@swing.be> 0005 0006 This file is part of KTNEF, the KDE TNEF support library/program. 0007 0008 SPDX-License-Identifier: LGPL-2.0-or-later 0009 */ 0010 /** 0011 * @file 0012 * This file is part of the API for handling TNEF data and 0013 * provides the @acronym LZFU decompression functionality. 0014 * 0015 * @author Michael Goffioul 0016 */ 0017 0018 #include "lzfu.h" 0019 0020 #include <QIODevice> 0021 0022 #include <cstdio> 0023 #include <cstring> 0024 #include <sys/types.h> 0025 0026 //#define DO_DEBUG 0027 0028 //@cond IGNORE 0029 #define LZFU_COMPRESSED 0x75465a4c 0030 #define LZFU_UNCOMPRESSED 0x414c454d 0031 0032 #define LZFU_INITDICT \ 0033 "{\\rtf1\\ansi\\mac\\deff0\\deftab720{\\fonttbl;}" \ 0034 "{\\f0\\fnil \\froman \\fswiss \\fmodern \\fscrip" \ 0035 "t \\fdecor MS Sans SerifSymbolArialTimes Ne" \ 0036 "w RomanCourier{\\colortbl\\red0\\green0\\blue0" \ 0037 "\r\n\\par \\pard\\plain\\f0\\fs20\\b\\i\\u\\tab" \ 0038 "\\tx" 0039 #define LZFU_INITLENGTH 207 0040 //@endcond 0041 0042 //@cond PRIVATE 0043 using lzfuheader = struct _lzfuheader { 0044 quint32 cbSize; 0045 quint32 cbRawSize; 0046 quint32 dwMagic; 0047 quint32 dwCRC; 0048 }; 0049 //@endcond 0050 0051 //@cond IGNORE 0052 #define FLAG(f, n) (f >> n) & 0x1 0053 0054 /*typedef struct _blockheader { 0055 unsigned int offset:12; 0056 unsigned int length:4; 0057 } blockheader;*/ 0058 0059 #define OFFSET(b) (b >> 4) & 0xFFF 0060 #define LENGTH(b) ((b & 0xF) + 2) 0061 //@endcond 0062 0063 int KTnef::lzfu_decompress(QIODevice *input, QIODevice *output) 0064 { 0065 unsigned char window[4096]; 0066 unsigned int wlength = 0; 0067 unsigned int cursor = 0; 0068 unsigned int ocursor = 0; 0069 lzfuheader lzfuhdr; 0070 // blockheader blkhdr; 0071 quint16 blkhdr; 0072 char bFlags; 0073 int nFlags; 0074 0075 memcpy(window, LZFU_INITDICT, LZFU_INITLENGTH); 0076 wlength = LZFU_INITLENGTH; 0077 if (input->read((char *)&lzfuhdr, sizeof(lzfuhdr)) != sizeof(lzfuhdr)) { 0078 fprintf(stderr, "unexpected eof, cannot read LZFU header\n"); 0079 return -1; 0080 } 0081 cursor += sizeof(lzfuhdr); 0082 #ifdef DO_DEBUG 0083 fprintf(stdout, "total size : %d\n", lzfuhdr.cbSize + 4); 0084 fprintf(stdout, "raw size : %d\n", lzfuhdr.cbRawSize); 0085 fprintf(stdout, "compressed : %s\n", (lzfuhdr.dwMagic == LZFU_COMPRESSED ? "yes" : "no")); 0086 fprintf(stdout, "CRC : %x\n", lzfuhdr.dwCRC); 0087 fprintf(stdout, "\n"); 0088 #endif 0089 0090 while (cursor < lzfuhdr.cbSize + 4 && ocursor < lzfuhdr.cbRawSize && !input->atEnd()) { 0091 if (input->read(&bFlags, 1) != 1) { 0092 fprintf(stderr, "unexpected eof, cannot read chunk flag\n"); 0093 return -1; 0094 } 0095 nFlags = 8; 0096 cursor++; 0097 #ifdef DO_DEBUG 0098 fprintf(stdout, "Flags : "); 0099 for (int i = nFlags - 1; i >= 0; i--) { 0100 fprintf(stdout, "%d", FLAG(bFlags, i)); 0101 } 0102 fprintf(stdout, "\n"); 0103 #endif 0104 for (int i = 0; i < nFlags && ocursor < lzfuhdr.cbRawSize && cursor < lzfuhdr.cbSize + 4; i++) { 0105 if (FLAG(bFlags, i)) { 0106 // compressed chunk 0107 char c1; 0108 char c2; 0109 if (input->read(&c1, 1) != 1 || input->read(&c2, 1) != 1) { 0110 fprintf(stderr, "unexpected eof, cannot read block header\n"); 0111 return -1; 0112 } 0113 blkhdr = c1; 0114 blkhdr <<= 8; 0115 blkhdr |= (0xFF & c2); 0116 unsigned int offset = OFFSET(blkhdr); 0117 unsigned int length = LENGTH(blkhdr); 0118 cursor += 2; 0119 #ifdef DO_DEBUG 0120 fprintf(stdout, "block : offset=%.4d [%d], length=%.2d (0x%04X)\n", OFFSET(blkhdr), wlength, LENGTH(blkhdr), blkhdr); 0121 #endif 0122 // if ( offset >= wlength ) { 0123 // break; 0124 //} 0125 #ifdef DO_DEBUG 0126 fprintf(stdout, "block : "); 0127 #endif 0128 for (unsigned int i = 0; i < length; i++) { 0129 c1 = window[(offset + i) % 4096]; 0130 // if ( wlength < 4096 ) { 0131 window[wlength] = c1; 0132 wlength = (wlength + 1) % 4096; 0133 //} 0134 #ifdef DO_DEBUG 0135 if (c1 == '\n') { 0136 fprintf(stdout, "\nblock : "); 0137 } else { 0138 fprintf(stdout, "%c", c1); 0139 } 0140 #endif 0141 output->putChar(c1); 0142 ocursor++; 0143 } 0144 #ifdef DO_DEBUG 0145 fprintf(stdout, "\n"); 0146 #endif 0147 } else { 0148 // uncompressed chunk (char) 0149 char c; 0150 if (!input->getChar(&c)) { 0151 if (!input->atEnd()) { 0152 fprintf(stderr, "unexpected eof, cannot read character\n"); 0153 return -1; 0154 } 0155 break; 0156 } 0157 #ifdef DO_DEBUG 0158 fprintf(stdout, "char : %c\n", c); 0159 #endif 0160 cursor++; 0161 // if ( wlength < 4096 ) { 0162 window[wlength] = c; 0163 wlength = (wlength + 1) % 4096; 0164 //} 0165 output->putChar(c); 0166 ocursor++; 0167 } 0168 } 0169 } 0170 0171 return 0; 0172 }