File: lzfu.cpp

package info (click to toggle)
ktnef 4%3A25.12.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,576 kB
  • sloc: cpp: 2,829; makefile: 14; sh: 1
file content (172 lines) | stat: -rw-r--r-- 5,738 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/*
    lzfu.cpp

    SPDX-FileCopyrightText: 2003 Michael Goffioul <kdeprint@swing.be>

    This file is part of KTNEF, the KDE TNEF support library/program.

    SPDX-License-Identifier: LGPL-2.0-or-later
 */
/**
 * @file
 * This file is part of the API for handling TNEF data and
 * provides the @acronym LZFU decompression functionality.
 *
 * @author Michael Goffioul
 */

#include "lzfu.h"

#include <QIODevice>

#include <cstdio>
#include <cstring>
#include <sys/types.h>

// #define DO_DEBUG

//@cond IGNORE
#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
//@endcond

//@cond PRIVATE
using lzfuheader = struct _lzfuheader {
    quint32 cbSize;
    quint32 cbRawSize;
    quint32 dwMagic;
    quint32 dwCRC;
};
//@endcond

//@cond IGNORE
#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)
//@endcond

int KTnef::lzfu_decompress(QIODevice *input, QIODevice *output)
{
    unsigned char window[4096];
    unsigned int wlength = 0;
    unsigned int cursor = 0;
    unsigned int ocursor = 0;
    lzfuheader lzfuhdr;
    // blockheader blkhdr;
    quint16 blkhdr;
    char bFlags;
    int nFlags;

    memcpy(window, LZFU_INITDICT, LZFU_INITLENGTH);
    wlength = LZFU_INITLENGTH;
    if (input->read((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->read(&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 chunk
                char c1;
                char c2;
                if (input->read(&c1, 1) != 1 || input->read(&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);
                unsigned int 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->putChar(c1);
                    ocursor++;
                }
#ifdef DO_DEBUG
                fprintf(stdout, "\n");
#endif
            } else {
                // uncompressed chunk (char)
                char c;
                if (!input->getChar(&c)) {
                    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->putChar(c);
                ocursor++;
            }
        }
    }

    return 0;
}