libmspack 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +5 -0
- data/.yardopts +1 -0
- data/Gemfile +4 -0
- data/README.md +75 -0
- data/Rakefile +22 -0
- data/UNLICENSE +24 -0
- data/ext/Rakefile +16 -0
- data/ext/i386-windows/libmspack.dll +0 -0
- data/ext/libmspack/AUTHORS +12 -0
- data/ext/libmspack/COPYING.LIB +504 -0
- data/ext/libmspack/ChangeLog +491 -0
- data/ext/libmspack/Makefile.am +100 -0
- data/ext/libmspack/NEWS +0 -0
- data/ext/libmspack/README +130 -0
- data/ext/libmspack/TODO +8 -0
- data/ext/libmspack/cleanup.sh +9 -0
- data/ext/libmspack/configure.ac +50 -0
- data/ext/libmspack/debian/changelog +6 -0
- data/ext/libmspack/debian/control +14 -0
- data/ext/libmspack/debian/rules +101 -0
- data/ext/libmspack/doc/Doxyfile.in +22 -0
- data/ext/libmspack/doc/Makefile.in +14 -0
- data/ext/libmspack/doc/szdd_kwaj_format.html +331 -0
- data/ext/libmspack/libmspack.pc.in +10 -0
- data/ext/libmspack/mspack/cab.h +127 -0
- data/ext/libmspack/mspack/cabc.c +24 -0
- data/ext/libmspack/mspack/cabd.c +1444 -0
- data/ext/libmspack/mspack/chm.h +122 -0
- data/ext/libmspack/mspack/chmc.c +24 -0
- data/ext/libmspack/mspack/chmd.c +1392 -0
- data/ext/libmspack/mspack/crc32.c +95 -0
- data/ext/libmspack/mspack/crc32.h +17 -0
- data/ext/libmspack/mspack/des.h +15 -0
- data/ext/libmspack/mspack/hlp.h +33 -0
- data/ext/libmspack/mspack/hlpc.c +24 -0
- data/ext/libmspack/mspack/hlpd.c +24 -0
- data/ext/libmspack/mspack/kwaj.h +118 -0
- data/ext/libmspack/mspack/kwajc.c +24 -0
- data/ext/libmspack/mspack/kwajd.c +561 -0
- data/ext/libmspack/mspack/lit.h +35 -0
- data/ext/libmspack/mspack/litc.c +24 -0
- data/ext/libmspack/mspack/litd.c +24 -0
- data/ext/libmspack/mspack/lzss.h +66 -0
- data/ext/libmspack/mspack/lzssd.c +93 -0
- data/ext/libmspack/mspack/lzx.h +221 -0
- data/ext/libmspack/mspack/lzxc.c +18 -0
- data/ext/libmspack/mspack/lzxd.c +895 -0
- data/ext/libmspack/mspack/mspack.def +28 -0
- data/ext/libmspack/mspack/mspack.h +2353 -0
- data/ext/libmspack/mspack/mszip.h +126 -0
- data/ext/libmspack/mspack/mszipc.c +18 -0
- data/ext/libmspack/mspack/mszipd.c +514 -0
- data/ext/libmspack/mspack/oab.h +60 -0
- data/ext/libmspack/mspack/oabc.c +24 -0
- data/ext/libmspack/mspack/oabd.c +408 -0
- data/ext/libmspack/mspack/qtm.h +128 -0
- data/ext/libmspack/mspack/qtmc.c +18 -0
- data/ext/libmspack/mspack/qtmd.c +489 -0
- data/ext/libmspack/mspack/readbits.h +207 -0
- data/ext/libmspack/mspack/readhuff.h +173 -0
- data/ext/libmspack/mspack/sha.h +15 -0
- data/ext/libmspack/mspack/system.c +239 -0
- data/ext/libmspack/mspack/system.h +124 -0
- data/ext/libmspack/mspack/szdd.h +39 -0
- data/ext/libmspack/mspack/szddc.c +24 -0
- data/ext/libmspack/mspack/szddd.c +247 -0
- data/ext/libmspack/rebuild.sh +8 -0
- data/ext/libmspack/test/cabd_c10 +19 -0
- data/ext/libmspack/test/cabd_compare +34 -0
- data/ext/libmspack/test/cabd_md5.c +161 -0
- data/ext/libmspack/test/cabd_memory.c +179 -0
- data/ext/libmspack/test/cabd_test.c +386 -0
- data/ext/libmspack/test/cabrip.c +81 -0
- data/ext/libmspack/test/chmd_compare +38 -0
- data/ext/libmspack/test/chmd_find.c +95 -0
- data/ext/libmspack/test/chmd_md5.c +67 -0
- data/ext/libmspack/test/chmd_order.c +144 -0
- data/ext/libmspack/test/chminfo.c +284 -0
- data/ext/libmspack/test/chmx.c +216 -0
- data/ext/libmspack/test/error.h +22 -0
- data/ext/libmspack/test/expand.c +79 -0
- data/ext/libmspack/test/md5.c +457 -0
- data/ext/libmspack/test/md5.h +165 -0
- data/ext/libmspack/test/md5_fh.h +123 -0
- data/ext/libmspack/test/msdecompile_md5 +24 -0
- data/ext/libmspack/test/msexpand_md5 +39 -0
- data/ext/libmspack/test/multifh.c +435 -0
- data/ext/libmspack/test/oabx.c +41 -0
- data/ext/libmspack/test/test_files/cabd/1.pl +84 -0
- data/ext/libmspack/test/test_files/cabd/2.pl +75 -0
- data/ext/libmspack/test/test_files/cabd/bad_folderindex.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/bad_nofiles.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/bad_nofolders.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/bad_signature.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/multi_basic_pt1.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/multi_basic_pt2.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/multi_basic_pt3.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/multi_basic_pt4.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/multi_basic_pt5.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/normal_255c_filename.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/normal_2files_1folder.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_nodata.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_nofiles.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_nofolder.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_shortextheader.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_shortfile1.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_shortfile2.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_shortfolder.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_shortheader.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_nofname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_noninfo.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_nonname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_nopinfo.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_nopname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_shortfname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_shortninfo.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_shortnname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_shortpinfo.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_shortpname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_---.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_--D.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_-F-.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_-FD.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_H--.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_H-D.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_HF-.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_HFD.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/search_basic.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/search_tricky1.cab +0 -0
- data/ext/libmspack/winbuild.sh +26 -0
- data/ext/x86_64-windows/libmspack.dll +0 -0
- data/lib/libmspack/constants.rb +9 -0
- data/lib/libmspack/exceptions.rb +12 -0
- data/lib/libmspack/mscab.rb +722 -0
- data/lib/libmspack/mschm.rb +301 -0
- data/lib/libmspack/mshlp.rb +15 -0
- data/lib/libmspack/mskwaj.rb +124 -0
- data/lib/libmspack/mslit.rb +18 -0
- data/lib/libmspack/msoab.rb +36 -0
- data/lib/libmspack/mspack.rb +208 -0
- data/lib/libmspack/msszdd.rb +81 -0
- data/lib/libmspack/system.rb +84 -0
- data/lib/libmspack/version.rb +4 -0
- data/lib/libmspack.rb +121 -0
- data/libmspack.gemspec +33 -0
- data/spec/libmspack_spec.rb +26 -0
- data/spec/spec_helper.rb +5 -0
- metadata +309 -0
@@ -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.h>
|
17
|
+
#include <szdd.h>
|
18
|
+
|
19
|
+
/* prototypes */
|
20
|
+
static struct msszddd_header *szddd_open(
|
21
|
+
struct msszdd_decompressor *base, const char *filename);
|
22
|
+
static void szddd_close(
|
23
|
+
struct msszdd_decompressor *base, struct msszddd_header *hdr);
|
24
|
+
static int szddd_read_headers(
|
25
|
+
struct mspack_system *sys, struct mspack_file *fh,
|
26
|
+
struct msszddd_header *hdr);
|
27
|
+
static int szddd_extract(
|
28
|
+
struct msszdd_decompressor *base, struct msszddd_header *hdr,
|
29
|
+
const char *filename);
|
30
|
+
static int szddd_decompress(
|
31
|
+
struct msszdd_decompressor *base, const char *input, const char *output);
|
32
|
+
static int szddd_error(
|
33
|
+
struct msszdd_decompressor *base);
|
34
|
+
|
35
|
+
/***************************************
|
36
|
+
* MSPACK_CREATE_SZDD_DECOMPRESSOR
|
37
|
+
***************************************
|
38
|
+
* constructor
|
39
|
+
*/
|
40
|
+
struct 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
|
+
*/
|
65
|
+
void 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
|
+
*/
|
79
|
+
static 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
|
+
if (hdr) sys->free(hdr);
|
104
|
+
hdr = NULL;
|
105
|
+
}
|
106
|
+
|
107
|
+
return hdr;
|
108
|
+
}
|
109
|
+
|
110
|
+
/***************************************
|
111
|
+
* SZDDD_CLOSE
|
112
|
+
***************************************
|
113
|
+
* closes an SZDD file
|
114
|
+
*/
|
115
|
+
static 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
|
+
*/
|
137
|
+
static unsigned char szdd_signature_expand[8] = {
|
138
|
+
0x53, 0x5A, 0x44, 0x44, 0x88, 0xF0, 0x27, 0x33
|
139
|
+
};
|
140
|
+
static unsigned char szdd_signature_qbasic[8] = {
|
141
|
+
0x53, 0x5A, 0x20, 0x88, 0xF0, 0x27, 0x33, 0xD1
|
142
|
+
};
|
143
|
+
|
144
|
+
static 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 ((mspack_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 ((mspack_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
|
+
*/
|
181
|
+
static 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
|
+
*/
|
223
|
+
static 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
|
+
*/
|
243
|
+
static 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
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
# Expand all cabs from the C10 collection; none are intentionally valid.
|
3
|
+
# See https://www.ee.oulu.fi/research/ouspg/PROTOS_Test-Suite_c10-archive
|
4
|
+
|
5
|
+
# I downloaded the .iso, unpacked cab_tar.bz2 and moved the cab files into
|
6
|
+
# 256 directories (00 to ff) under C10/unpacked. This makes it possible to
|
7
|
+
# invoke cabd_md5 just 256 times to test the entire collection.
|
8
|
+
|
9
|
+
for dir in `find C10/unpacked -maxdepth 1 -type d`
|
10
|
+
do
|
11
|
+
echo "testing $dir"
|
12
|
+
./cabd_md5 $dir/*.cab >/dev/null 2>.err
|
13
|
+
result=$?
|
14
|
+
if [ $result -ne 0 ]; then
|
15
|
+
echo "FAIL $dir $result" >&2
|
16
|
+
cat .err >&2
|
17
|
+
fi
|
18
|
+
done
|
19
|
+
rm .err
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
# Test if cabd_md5 expands cab files identically to Microsoft's EXPAND.EXE
|
3
|
+
|
4
|
+
[ -d .cache ] || mkdir .cache
|
5
|
+
|
6
|
+
for cab in "$@"
|
7
|
+
do
|
8
|
+
echo "test $cab"
|
9
|
+
cached=`echo $cab | sed -e 's/\//-/g' -e 's/^/.cache\//'`
|
10
|
+
if [ ! -s $cached ]; then
|
11
|
+
./msexpand_md5 $cab >.orig.out 2>.orig.err
|
12
|
+
if [ -s .orig.err ]; then
|
13
|
+
echo "FAIL $cab: MS errors" >&2
|
14
|
+
cat .orig.err >&2
|
15
|
+
else
|
16
|
+
mv .orig.out $cached
|
17
|
+
fi
|
18
|
+
fi
|
19
|
+
|
20
|
+
./cabd_md5 $cab >.test.out 2>.test.err
|
21
|
+
perl -pi -e 'if($.>1){s{\\}{/}g;s{ /}{ }}' .test.out
|
22
|
+
if [ -s .test.err ]; then
|
23
|
+
echo "FAIL $cab: errors" >&2
|
24
|
+
cat .test.err >&2
|
25
|
+
fi
|
26
|
+
|
27
|
+
if cmp $cached .test.out >/dev/null; then
|
28
|
+
echo "OK $cab"
|
29
|
+
else
|
30
|
+
echo "FAIL $cab: differences" >&2
|
31
|
+
diff -u $cached .test.out >&2
|
32
|
+
fi
|
33
|
+
done
|
34
|
+
rm -f .orig.out .orig.err .test.out .test.err
|
@@ -0,0 +1,161 @@
|
|
1
|
+
#ifdef HAVE_CONFIG_H
|
2
|
+
#include <config.h>
|
3
|
+
#endif
|
4
|
+
|
5
|
+
#include <stdio.h>
|
6
|
+
#include <stdlib.h>
|
7
|
+
#include <string.h>
|
8
|
+
#include <mspack.h>
|
9
|
+
#include <sys/stat.h>
|
10
|
+
#include <dirent.h>
|
11
|
+
|
12
|
+
#include <md5_fh.h>
|
13
|
+
#include <error.h>
|
14
|
+
|
15
|
+
/**
|
16
|
+
* Matches a cabinet's filename case-insensitively in the filesystem and
|
17
|
+
* returns the case-correct form.
|
18
|
+
*
|
19
|
+
* @param origcab if this is non-NULL, the pathname part of this filename
|
20
|
+
* will be extracted, and the search will be conducted in
|
21
|
+
* that directory.
|
22
|
+
* @param cabname the internal CAB filename to search for.
|
23
|
+
* @return a copy of the full, case-correct filename of the given cabinet
|
24
|
+
* filename, or NULL if the specified filename does not exist on disk.
|
25
|
+
*/
|
26
|
+
static char *find_cabinet_file(char *origcab, char *cabname) {
|
27
|
+
struct dirent *entry;
|
28
|
+
struct stat st_buf;
|
29
|
+
int found = 0, len;
|
30
|
+
char *tail, *cab;
|
31
|
+
DIR *dir;
|
32
|
+
|
33
|
+
/* ensure we have a cabinet name at all */
|
34
|
+
if (!cabname || !cabname[0]) return NULL;
|
35
|
+
|
36
|
+
/* find if there's a directory path in the origcab */
|
37
|
+
tail = origcab ? strrchr(origcab, '/') : NULL;
|
38
|
+
len = (tail - origcab) + 1;
|
39
|
+
|
40
|
+
/* allocate memory for our copy */
|
41
|
+
if (!(cab = (char *) malloc((tail ? len : 2) + strlen(cabname) + 1))) return NULL;
|
42
|
+
|
43
|
+
/* add the directory path from the original cabinet name, or "." */
|
44
|
+
if (tail) memcpy(cab, origcab, (size_t) len);
|
45
|
+
else cab[0]='.', cab[1]='/', len=2;
|
46
|
+
cab[len] = '\0';
|
47
|
+
|
48
|
+
/* try accessing the cabinet with its current name (case-sensitive) */
|
49
|
+
strcpy(&cab[len], cabname);
|
50
|
+
if (stat(cab, &st_buf) == 0) {
|
51
|
+
found = 1;
|
52
|
+
}
|
53
|
+
else {
|
54
|
+
/* cabinet was not found, look for it in the current dir */
|
55
|
+
cab[len] = '\0';
|
56
|
+
if ((dir = opendir(cab))) {
|
57
|
+
while ((entry = readdir(dir))) {
|
58
|
+
if (strcasecmp(cabname, entry->d_name) == 0) {
|
59
|
+
strcat(cab, entry->d_name);
|
60
|
+
found = (stat(cab, &st_buf) == 0);
|
61
|
+
break;
|
62
|
+
}
|
63
|
+
}
|
64
|
+
closedir(dir);
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
if (!found || !S_ISREG(st_buf.st_mode)) {
|
69
|
+
/* cabinet not found, or not a regular file */
|
70
|
+
free(cab);
|
71
|
+
cab = NULL;
|
72
|
+
}
|
73
|
+
|
74
|
+
return cab;
|
75
|
+
}
|
76
|
+
|
77
|
+
|
78
|
+
int main(int argc, char *argv[]) {
|
79
|
+
struct mscab_decompressor *cabd;
|
80
|
+
struct mscabd_cabinet *cab, *c, *c2;
|
81
|
+
struct mscabd_file *file;
|
82
|
+
char *cabname, *newname;
|
83
|
+
int err;
|
84
|
+
|
85
|
+
setbuf(stdout, NULL);
|
86
|
+
setbuf(stderr, NULL);
|
87
|
+
|
88
|
+
/* if self-test reveals an error */
|
89
|
+
MSPACK_SYS_SELFTEST(err);
|
90
|
+
if (err) return 1;
|
91
|
+
|
92
|
+
if (!(cabd = mspack_create_cab_decompressor(&read_files_write_md5))) {
|
93
|
+
fprintf(stderr, "can't make decompressor\n");
|
94
|
+
return 1;
|
95
|
+
}
|
96
|
+
|
97
|
+
for (argv++; (cabname = *argv); argv++) {
|
98
|
+
printf("*** %s\n", cabname);
|
99
|
+
|
100
|
+
if (!(cab = cabd->open(cabd, cabname))) {
|
101
|
+
fprintf(stderr, "cab open error: %s\n", ERROR(cabd));
|
102
|
+
continue;
|
103
|
+
}
|
104
|
+
|
105
|
+
/* prepend any spanning cabinets */
|
106
|
+
for (c = cab; c && (c->flags & MSCAB_HDR_PREVCAB); c = c->prevcab) {
|
107
|
+
if (!(newname = find_cabinet_file(cabname, c->prevname))) {
|
108
|
+
fprintf(stderr, "%s: can't find \"%s\" to prepend\n",
|
109
|
+
cabname, c->prevname);
|
110
|
+
break;
|
111
|
+
}
|
112
|
+
if (!(c2 = cabd->open(cabd, newname))) {
|
113
|
+
fprintf(stderr, "%s: error opening \"%s\" for prepend: %s\n",
|
114
|
+
cabname, newname, ERROR(cabd));
|
115
|
+
break;
|
116
|
+
}
|
117
|
+
if (cabd->prepend(cabd, c, c2) != MSPACK_ERR_OK) {
|
118
|
+
fprintf(stderr, "%s: error prepending \"%s\": %s\n",
|
119
|
+
cabname, newname, ERROR(cabd));
|
120
|
+
break;
|
121
|
+
}
|
122
|
+
}
|
123
|
+
|
124
|
+
/* append any spanning cabinets */
|
125
|
+
for (c = cab; c && (c->flags & MSCAB_HDR_NEXTCAB); c = c->nextcab) {
|
126
|
+
if (!(newname = find_cabinet_file(cabname, c->nextname))) {
|
127
|
+
fprintf(stderr, "%s: can't find \"%s\" to append\n",
|
128
|
+
cabname, c->nextname);
|
129
|
+
break;
|
130
|
+
}
|
131
|
+
if (!(c2 = cabd->open(cabd, newname))) {
|
132
|
+
fprintf(stderr, "%s: error opening \"%s\" for append: %s\n",
|
133
|
+
cabname, newname, ERROR(cabd));
|
134
|
+
break;
|
135
|
+
}
|
136
|
+
if (cabd->append(cabd, c, c2) != MSPACK_ERR_OK) {
|
137
|
+
fprintf(stderr, "%s: error appending \"%s\": %s\n",
|
138
|
+
cabname, newname, ERROR(cabd));
|
139
|
+
break;
|
140
|
+
}
|
141
|
+
}
|
142
|
+
|
143
|
+
/* extract files */
|
144
|
+
for (file = cab->files; file; file = file->next ) {
|
145
|
+
if (cabd->extract(cabd, file, NULL) == MSPACK_ERR_OK) {
|
146
|
+
printf("%s %s\n", md5_string, file->filename);
|
147
|
+
}
|
148
|
+
else {
|
149
|
+
fprintf(stderr, "%s: error extracting \"%s\": %s\n",
|
150
|
+
cabname, file->filename, ERROR(cabd));
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
154
|
+
/* free all resources */
|
155
|
+
for (c2 = cab->prevcab; c2; c2 = c2->prevcab) free((void*)c2->filename);
|
156
|
+
for (c2 = cab->nextcab; c2; c2 = c2->nextcab) free((void*)c2->filename);
|
157
|
+
cabd->close(cabd, cab);
|
158
|
+
}
|
159
|
+
mspack_destroy_cab_decompressor(cabd);
|
160
|
+
return 0;
|
161
|
+
}
|
@@ -0,0 +1,179 @@
|
|
1
|
+
/* An implementation of the mspack_system interface using only memory */
|
2
|
+
|
3
|
+
#ifdef HAVE_CONFIG_H
|
4
|
+
#include <config.h>
|
5
|
+
#endif
|
6
|
+
|
7
|
+
#include <stdio.h>
|
8
|
+
#include <stdlib.h>
|
9
|
+
#include <string.h>
|
10
|
+
#include <mspack.h>
|
11
|
+
|
12
|
+
/* use a pointer to a mem_buf structure as "filenames" */
|
13
|
+
struct mem_buf {
|
14
|
+
void *data;
|
15
|
+
size_t length;
|
16
|
+
};
|
17
|
+
|
18
|
+
struct mem_file {
|
19
|
+
char *data;
|
20
|
+
size_t length, posn;
|
21
|
+
};
|
22
|
+
|
23
|
+
static void *mem_alloc(struct mspack_system *self, size_t bytes) {
|
24
|
+
/* put your memory allocator here */
|
25
|
+
return malloc(bytes);
|
26
|
+
}
|
27
|
+
|
28
|
+
static void mem_free(void *buffer) {
|
29
|
+
/* put your memory deallocator here */
|
30
|
+
free(buffer);
|
31
|
+
}
|
32
|
+
|
33
|
+
static void mem_copy(void *src, void *dest, size_t bytes) {
|
34
|
+
/* put your own memory copy routine here */
|
35
|
+
memcpy(dest, src, bytes);
|
36
|
+
}
|
37
|
+
|
38
|
+
static void mem_msg(struct mem_file *file, const char *format, ...) {
|
39
|
+
/* put your own printf-type routine here, or leave it empty */
|
40
|
+
}
|
41
|
+
|
42
|
+
static struct mem_file *mem_open(struct mspack_system *self,
|
43
|
+
struct mem_buf *fn, int mode)
|
44
|
+
{
|
45
|
+
struct mem_file *fh;
|
46
|
+
if (!fn || !fn->data || !fn->length) return NULL;
|
47
|
+
if ((fh = (struct mem_file *) mem_alloc(self, sizeof(struct mem_file)))) {
|
48
|
+
fh->data = (char *) fn->data;
|
49
|
+
fh->length = fn->length;
|
50
|
+
fh->posn = (mode == MSPACK_SYS_OPEN_APPEND) ? fn->length : 0;
|
51
|
+
}
|
52
|
+
return fh;
|
53
|
+
}
|
54
|
+
|
55
|
+
static void mem_close(struct mem_file *fh) {
|
56
|
+
if (fh) mem_free(fh);
|
57
|
+
}
|
58
|
+
|
59
|
+
static int mem_read(struct mem_file *fh, void *buffer, int bytes) {
|
60
|
+
int todo;
|
61
|
+
if (!fh || !buffer || bytes < 0) return -1;
|
62
|
+
todo = fh->length - fh->posn;
|
63
|
+
if (todo > bytes) todo = bytes;
|
64
|
+
if (todo > 0) mem_copy(&fh->data[fh->posn], buffer, (size_t) todo);
|
65
|
+
fh->posn += todo; return todo;
|
66
|
+
}
|
67
|
+
|
68
|
+
static int mem_write(struct mem_file *fh, void *buffer, int bytes) {
|
69
|
+
int todo;
|
70
|
+
if (!fh || !buffer || bytes < 0) return -1;
|
71
|
+
todo = fh->length - fh->posn;
|
72
|
+
if (todo > bytes) todo = bytes;
|
73
|
+
if (todo > 0) mem_copy(buffer, &fh->data[fh->posn], (size_t) todo);
|
74
|
+
fh->posn += todo; return todo;
|
75
|
+
}
|
76
|
+
|
77
|
+
static int mem_seek(struct mem_file *fh, off_t offset, int mode) {
|
78
|
+
if (!fh) return 1;
|
79
|
+
switch (mode) {
|
80
|
+
case MSPACK_SYS_SEEK_START: break;
|
81
|
+
case MSPACK_SYS_SEEK_CUR: offset += (off_t) fh->posn; break;
|
82
|
+
case MSPACK_SYS_SEEK_END: offset += (off_t) fh->length; break;
|
83
|
+
default: return 1;
|
84
|
+
}
|
85
|
+
if ((offset < 0) || (offset > (off_t) fh->length)) return 1;
|
86
|
+
fh->posn = (size_t) offset;
|
87
|
+
return 0;
|
88
|
+
}
|
89
|
+
|
90
|
+
static off_t mem_tell(struct mem_file *fh) {
|
91
|
+
return (fh) ? (off_t) fh->posn : -1;
|
92
|
+
}
|
93
|
+
|
94
|
+
static struct mspack_system mem_system = {
|
95
|
+
(struct mspack_file * (*)(struct mspack_system *, const char *, int)) &mem_open,
|
96
|
+
(void (*)(struct mspack_file *)) &mem_close,
|
97
|
+
(int (*)(struct mspack_file *, void *, int)) &mem_read,
|
98
|
+
(int (*)(struct mspack_file *, void *, int)) &mem_write,
|
99
|
+
(int (*)(struct mspack_file *, off_t, int)) &mem_seek,
|
100
|
+
(off_t (*)(struct mspack_file *)) &mem_tell,
|
101
|
+
(void (*)(struct mspack_file *, const char *, ...)) &mem_msg,
|
102
|
+
&mem_alloc,
|
103
|
+
&mem_free,
|
104
|
+
&mem_copy,
|
105
|
+
NULL
|
106
|
+
};
|
107
|
+
|
108
|
+
/* example of usage with mscab_decompressor */
|
109
|
+
|
110
|
+
/* a simple cabinet */
|
111
|
+
static unsigned char embedded_cab[] = {
|
112
|
+
0x4D,0x53,0x43,0x46,0x00,0x00,0x00,0x00,0xFD,0x00,0x00,0x00,0x00,0x00,0x00,
|
113
|
+
0x00,0x2C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x01,0x01,0x00,0x02,0x00,
|
114
|
+
0x00,0x00,0x22,0x06,0x00,0x00,0x5E,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x4D,
|
115
|
+
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6C,0x22,0xBA,0x59,0x20,0x00,
|
116
|
+
0x68,0x65,0x6C,0x6C,0x6F,0x2E,0x63,0x00,0x4A,0x00,0x00,0x00,0x4D,0x00,0x00,
|
117
|
+
0x00,0x00,0x00,0x6C,0x22,0xE7,0x59,0x20,0x00,0x77,0x65,0x6C,0x63,0x6F,0x6D,
|
118
|
+
0x65,0x2E,0x63,0x00,0xBD,0x5A,0xA6,0x30,0x97,0x00,0x97,0x00,0x23,0x69,0x6E,
|
119
|
+
0x63,0x6C,0x75,0x64,0x65,0x20,0x3C,0x73,0x74,0x64,0x69,0x6F,0x2E,0x68,0x3E,
|
120
|
+
0x0D,0x0A,0x0D,0x0A,0x76,0x6F,0x69,0x64,0x20,0x6D,0x61,0x69,0x6E,0x28,0x76,
|
121
|
+
0x6F,0x69,0x64,0x29,0x0D,0x0A,0x7B,0x0D,0x0A,0x20,0x20,0x20,0x20,0x70,0x72,
|
122
|
+
0x69,0x6E,0x74,0x66,0x28,0x22,0x48,0x65,0x6C,0x6C,0x6F,0x2C,0x20,0x77,0x6F,
|
123
|
+
0x72,0x6C,0x64,0x21,0x5C,0x6E,0x22,0x29,0x3B,0x0D,0x0A,0x7D,0x0D,0x0A,0x23,
|
124
|
+
0x69,0x6E,0x63,0x6C,0x75,0x64,0x65,0x20,0x3C,0x73,0x74,0x64,0x69,0x6F,0x2E,
|
125
|
+
0x68,0x3E,0x0D,0x0A,0x0D,0x0A,0x76,0x6F,0x69,0x64,0x20,0x6D,0x61,0x69,0x6E,
|
126
|
+
0x28,0x76,0x6F,0x69,0x64,0x29,0x0D,0x0A,0x7B,0x0D,0x0A,0x20,0x20,0x20,0x20,
|
127
|
+
0x70,0x72,0x69,0x6E,0x74,0x66,0x28,0x22,0x57,0x65,0x6C,0x63,0x6F,0x6D,0x65,
|
128
|
+
0x21,0x5C,0x6E,0x22,0x29,0x3B,0x0D,0x0A,0x7D,0x0D,0x0A,0x0D,0x0A
|
129
|
+
};
|
130
|
+
|
131
|
+
int main() {
|
132
|
+
struct mscab_decompressor *cabd;
|
133
|
+
struct mscabd_cabinet *cab;
|
134
|
+
struct mscabd_file *file;
|
135
|
+
struct mem_buf source = { &embedded_cab[0], sizeof(embedded_cab) };
|
136
|
+
struct mem_buf output;
|
137
|
+
int err;
|
138
|
+
|
139
|
+
/* if self-test reveals an error */
|
140
|
+
MSPACK_SYS_SELFTEST(err);
|
141
|
+
if (err) return 1;
|
142
|
+
|
143
|
+
/* create a cab decompressor using our custom mspack_system interface */
|
144
|
+
if ((cabd = mspack_create_cab_decompressor(&mem_system))) {
|
145
|
+
|
146
|
+
/* open a cab file direct from memory */
|
147
|
+
if ((cab = cabd->open(cabd, (char *) &source))) {
|
148
|
+
|
149
|
+
/* for all files */
|
150
|
+
for (file = cab->files; file; file = file->next) {
|
151
|
+
/* fill out our "filename" (memory pointer and length) */
|
152
|
+
output.data = (char *) malloc(file->length);
|
153
|
+
output.length = file->length;
|
154
|
+
|
155
|
+
/* let cabd extract this file to our memory buffer */
|
156
|
+
if (output.data && cabd->extract(cabd, file, (char *) &output)) {
|
157
|
+
exit(1);
|
158
|
+
}
|
159
|
+
|
160
|
+
/* dump the memory buffer to stdout (for display purposes) */
|
161
|
+
printf("Filename: %s\nContents:\n", file->filename);
|
162
|
+
fwrite(output.data, 1, output.length, stdout);
|
163
|
+
|
164
|
+
/* free our buffer */
|
165
|
+
free(output.data);
|
166
|
+
}
|
167
|
+
cabd->close(cabd, cab);
|
168
|
+
}
|
169
|
+
else {
|
170
|
+
fprintf(stderr, "can't open cabinet (%d)\n", cabd->last_error(cabd));
|
171
|
+
}
|
172
|
+
mspack_destroy_cab_decompressor(cabd);
|
173
|
+
}
|
174
|
+
else {
|
175
|
+
fprintf(stderr, "can't make decompressor\n");
|
176
|
+
}
|
177
|
+
return 0;
|
178
|
+
|
179
|
+
}
|