summaryrefslogtreecommitdiff
path: root/utils/rbutilqt/mspack/szddd.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/rbutilqt/mspack/szddd.c')
-rw-r--r--utils/rbutilqt/mspack/szddd.c247
1 files changed, 247 insertions, 0 deletions
diff --git a/utils/rbutilqt/mspack/szddd.c b/utils/rbutilqt/mspack/szddd.c
new file mode 100644
index 0000000000..1d6d05f844
--- /dev/null
+++ b/utils/rbutilqt/mspack/szddd.c
@@ -0,0 +1,247 @@
1/* This file is part of libmspack.
2 * (C) 2003-2010 Stuart Caie.
3 *
4 * SZDD is a format used in the MS-DOS commands COMPRESS.EXE and
5 * EXPAND.EXE. The compression method is attributed to Steven Zeck,
6 * however it's pretty much identical to LZSS.
7 *
8 * libmspack is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
10 *
11 * For further details, see the file COPYING.LIB distributed with libmspack
12 */
13
14/* SZDD decompression implementation */
15
16#include "system-mspack.h"
17#include "szdd.h"
18
19/* prototypes */
20static struct msszddd_header *szddd_open(
21 struct msszdd_decompressor *base, const char *filename);
22static void szddd_close(
23 struct msszdd_decompressor *base, struct msszddd_header *hdr);
24static int szddd_read_headers(
25 struct mspack_system *sys, struct mspack_file *fh,
26 struct msszddd_header *hdr);
27static int szddd_extract(
28 struct msszdd_decompressor *base, struct msszddd_header *hdr,
29 const char *filename);
30static int szddd_decompress(
31 struct msszdd_decompressor *base, const char *input, const char *output);
32static int szddd_error(
33 struct msszdd_decompressor *base);
34
35/***************************************
36 * MSPACK_CREATE_SZDD_DECOMPRESSOR
37 ***************************************
38 * constructor
39 */
40struct msszdd_decompressor *
41 mspack_create_szdd_decompressor(struct mspack_system *sys)
42{
43 struct msszdd_decompressor_p *self = NULL;
44
45 if (!sys) sys = mspack_default_system;
46 if (!mspack_valid_system(sys)) return NULL;
47
48 if ((self = (struct msszdd_decompressor_p *) sys->alloc(sys, sizeof(struct msszdd_decompressor_p)))) {
49 self->base.open = &szddd_open;
50 self->base.close = &szddd_close;
51 self->base.extract = &szddd_extract;
52 self->base.decompress = &szddd_decompress;
53 self->base.last_error = &szddd_error;
54 self->system = sys;
55 self->error = MSPACK_ERR_OK;
56 }
57 return (struct msszdd_decompressor *) self;
58}
59
60/***************************************
61 * MSPACK_DESTROY_SZDD_DECOMPRESSOR
62 ***************************************
63 * destructor
64 */
65void mspack_destroy_szdd_decompressor(struct msszdd_decompressor *base)
66{
67 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
68 if (self) {
69 struct mspack_system *sys = self->system;
70 sys->free(self);
71 }
72}
73
74/***************************************
75 * SZDDD_OPEN
76 ***************************************
77 * opens an SZDD file without decompressing, reads header
78 */
79static struct msszddd_header *szddd_open(struct msszdd_decompressor *base,
80 const char *filename)
81{
82 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
83 struct msszddd_header *hdr;
84 struct mspack_system *sys;
85 struct mspack_file *fh;
86
87 if (!self) return NULL;
88 sys = self->system;
89
90 fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ);
91 hdr = (struct msszddd_header *) sys->alloc(sys, sizeof(struct msszddd_header_p));
92 if (fh && hdr) {
93 ((struct msszddd_header_p *) hdr)->fh = fh;
94 self->error = szddd_read_headers(sys, fh, hdr);
95 }
96 else {
97 if (!fh) self->error = MSPACK_ERR_OPEN;
98 if (!hdr) self->error = MSPACK_ERR_NOMEMORY;
99 }
100
101 if (self->error) {
102 if (fh) sys->close(fh);
103 sys->free(hdr);
104 hdr = NULL;
105 }
106
107 return hdr;
108}
109
110/***************************************
111 * SZDDD_CLOSE
112 ***************************************
113 * closes an SZDD file
114 */
115static void szddd_close(struct msszdd_decompressor *base,
116 struct msszddd_header *hdr)
117{
118 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
119 struct msszddd_header_p *hdr_p = (struct msszddd_header_p *) hdr;
120
121 if (!self || !self->system) return;
122
123 /* close the file handle associated */
124 self->system->close(hdr_p->fh);
125
126 /* free the memory associated */
127 self->system->free(hdr);
128
129 self->error = MSPACK_ERR_OK;
130}
131
132/***************************************
133 * SZDDD_READ_HEADERS
134 ***************************************
135 * reads the headers of an SZDD format file
136 */
137static unsigned char szdd_signature_expand[8] = {
138 0x53, 0x5A, 0x44, 0x44, 0x88, 0xF0, 0x27, 0x33
139};
140static unsigned char szdd_signature_qbasic[8] = {
141 0x53, 0x5A, 0x20, 0x88, 0xF0, 0x27, 0x33, 0xD1
142};
143
144static int szddd_read_headers(struct mspack_system *sys,
145 struct mspack_file *fh,
146 struct msszddd_header *hdr)
147{
148 unsigned char buf[8];
149
150 /* read and check signature */
151 if (sys->read(fh, buf, 8) != 8) return MSPACK_ERR_READ;
152
153 if ((memcmp(buf, szdd_signature_expand, 8) == 0)) {
154 /* common SZDD */
155 hdr->format = MSSZDD_FMT_NORMAL;
156
157 /* read the rest of the header */
158 if (sys->read(fh, buf, 6) != 6) return MSPACK_ERR_READ;
159 if (buf[0] != 0x41) return MSPACK_ERR_DATAFORMAT;
160 hdr->missing_char = buf[1];
161 hdr->length = EndGetI32(&buf[2]);
162 }
163 else if ((memcmp(buf, szdd_signature_qbasic, 8) == 0)) {
164 /* special QBasic SZDD */
165 hdr->format = MSSZDD_FMT_QBASIC;
166 if (sys->read(fh, buf, 4) != 4) return MSPACK_ERR_READ;
167 hdr->missing_char = '\0';
168 hdr->length = EndGetI32(buf);
169 }
170 else {
171 return MSPACK_ERR_SIGNATURE;
172 }
173 return MSPACK_ERR_OK;
174}
175
176/***************************************
177 * SZDDD_EXTRACT
178 ***************************************
179 * decompresses an SZDD file
180 */
181static int szddd_extract(struct msszdd_decompressor *base,
182 struct msszddd_header *hdr, const char *filename)
183{
184 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
185 struct mspack_file *fh, *outfh;
186 struct mspack_system *sys;
187 off_t data_offset;
188
189 if (!self) return MSPACK_ERR_ARGS;
190 if (!hdr) return self->error = MSPACK_ERR_ARGS;
191 sys = self->system;
192
193 fh = ((struct msszddd_header_p *) hdr)->fh;
194
195 /* seek to the compressed data */
196 data_offset = (hdr->format == MSSZDD_FMT_NORMAL) ? 14 : 12;
197 if (sys->seek(fh, data_offset, MSPACK_SYS_SEEK_START)) {
198 return self->error = MSPACK_ERR_SEEK;
199 }
200
201 /* open file for output */
202 if (!(outfh = sys->open(sys, filename, MSPACK_SYS_OPEN_WRITE))) {
203 return self->error = MSPACK_ERR_OPEN;
204 }
205
206 /* decompress the data */
207 self->error = lzss_decompress(sys, fh, outfh, SZDD_INPUT_SIZE,
208 hdr->format == MSSZDD_FMT_NORMAL
209 ? LZSS_MODE_EXPAND
210 : LZSS_MODE_QBASIC);
211
212 /* close output file */
213 sys->close(outfh);
214
215 return self->error;
216}
217
218/***************************************
219 * SZDDD_DECOMPRESS
220 ***************************************
221 * unpacks directly from input to output
222 */
223static int szddd_decompress(struct msszdd_decompressor *base,
224 const char *input, const char *output)
225{
226 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
227 struct msszddd_header *hdr;
228 int error;
229
230 if (!self) return MSPACK_ERR_ARGS;
231
232 if (!(hdr = szddd_open(base, input))) return self->error;
233 error = szddd_extract(base, hdr, output);
234 szddd_close(base, hdr);
235 return self->error = error;
236}
237
238/***************************************
239 * SZDDD_ERROR
240 ***************************************
241 * returns the last error that occurred
242 */
243static int szddd_error(struct msszdd_decompressor *base)
244{
245 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
246 return (self) ? self->error : MSPACK_ERR_ARGS;
247}