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 }