Browse code

add missing files

git-svn-id: file:///var/lib/svn/clamav-devel/trunk/clamav-devel@588 77e5149b-7576-45b1-b177-96237e5ba77b

Tomasz Kojm authored on 2004/06/02 09:53:43
Showing 11 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,127 @@
0
+/* This file is part of libmspack.
1
+ * (C) 2003-2004 Stuart Caie.
2
+ *
3
+ * libmspack is free software; you can redistribute it and/or modify it under
4
+ * the terms of the GNU Lesser General Public License (LGPL) version 2.1
5
+ *
6
+ * For further details, see the file COPYING.LIB distributed with libmspack
7
+ */
8
+
9
+#ifndef MSPACK_CAB_H
10
+#define MSPACK_CAB_H 1
11
+
12
+#include <mszip.h>
13
+#include <qtm.h>
14
+#include <lzx.h>
15
+
16
+/* generic CAB definitions */
17
+
18
+/* structure offsets */
19
+#define cfhead_Signature         (0x00)
20
+#define cfhead_CabinetSize       (0x08)
21
+#define cfhead_FileOffset        (0x10)
22
+#define cfhead_MinorVersion      (0x18)
23
+#define cfhead_MajorVersion      (0x19)
24
+#define cfhead_NumFolders        (0x1A)
25
+#define cfhead_NumFiles          (0x1C)
26
+#define cfhead_Flags             (0x1E)
27
+#define cfhead_SetID             (0x20)
28
+#define cfhead_CabinetIndex      (0x22)
29
+#define cfhead_SIZEOF            (0x24)
30
+#define cfheadext_HeaderReserved (0x00)
31
+#define cfheadext_FolderReserved (0x02)
32
+#define cfheadext_DataReserved   (0x03)
33
+#define cfheadext_SIZEOF         (0x04)
34
+#define cffold_DataOffset        (0x00)
35
+#define cffold_NumBlocks         (0x04)
36
+#define cffold_CompType          (0x06)
37
+#define cffold_SIZEOF            (0x08)
38
+#define cffile_UncompressedSize  (0x00)
39
+#define cffile_FolderOffset      (0x04)
40
+#define cffile_FolderIndex       (0x08)
41
+#define cffile_Date              (0x0A)
42
+#define cffile_Time              (0x0C)
43
+#define cffile_Attribs           (0x0E)
44
+#define cffile_SIZEOF            (0x10)
45
+#define cfdata_CheckSum          (0x00)
46
+#define cfdata_CompressedSize    (0x04)
47
+#define cfdata_UncompressedSize  (0x06)
48
+#define cfdata_SIZEOF            (0x08)
49
+
50
+/* flags */
51
+#define cffoldCOMPTYPE_MASK            (0x000f)
52
+#define cffoldCOMPTYPE_NONE            (0x0000)
53
+#define cffoldCOMPTYPE_MSZIP           (0x0001)
54
+#define cffoldCOMPTYPE_QUANTUM         (0x0002)
55
+#define cffoldCOMPTYPE_LZX             (0x0003)
56
+#define cfheadPREV_CABINET             (0x0001)
57
+#define cfheadNEXT_CABINET             (0x0002)
58
+#define cfheadRESERVE_PRESENT          (0x0004)
59
+#define cffileCONTINUED_FROM_PREV      (0xFFFD)
60
+#define cffileCONTINUED_TO_NEXT        (0xFFFE)
61
+#define cffileCONTINUED_PREV_AND_NEXT  (0xFFFF)
62
+
63
+/* CAB data blocks are <= 32768 bytes in uncompressed form. Uncompressed
64
+ * blocks have zero growth. MSZIP guarantees that it won't grow above
65
+ * uncompressed size by more than 12 bytes. LZX guarantees it won't grow
66
+ * more than 6144 bytes. Quantum has no documentation, but the largest
67
+ * block seen in the wild is 337 bytes above uncompressed size.
68
+ */
69
+#define CAB_BLOCKMAX (32768)
70
+#define CAB_INPUTMAX (CAB_BLOCKMAX+6144)
71
+
72
+/* CAB compression definitions */
73
+
74
+struct mscab_compressor_p {
75
+  struct mscab_compressor base;
76
+  struct mspack_system *system;
77
+  /* todo */
78
+};
79
+
80
+/* CAB decompression definitions */
81
+
82
+struct mscabd_decompress_state {
83
+  struct mscabd_folder_p *folder;    /* current folder we're extracting from */
84
+  struct mscabd_folder_data *data;   /* current folder split we're in        */
85
+  unsigned int offset;               /* uncompressed offset within folder    */
86
+  unsigned int block;                /* which block are we decompressing?    */
87
+  struct mspack_system sys;          /* special I/O code for decompressor    */
88
+  int comp_type;                     /* type of compression used by folder   */
89
+  int (*decompress)(void *, off_t);  /* decompressor code                    */
90
+  void *state;                       /* decompressor state                   */
91
+  struct mscabd_cabinet_p *incab;    /* cabinet where input data comes from  */
92
+  struct mspack_file *infh;          /* input file handle                    */
93
+  struct mspack_file *outfh;         /* output file handle                   */
94
+  unsigned char *i_ptr, *i_end;      /* input data consumed, end             */
95
+  unsigned char input[CAB_INPUTMAX]; /* one input block of data              */
96
+};
97
+
98
+struct mscab_decompressor_p {
99
+  struct mscab_decompressor base;
100
+  struct mscabd_decompress_state *d;
101
+  struct mspack_system *system;
102
+  int param[3]; /* !!! MATCH THIS TO NUM OF PARAMS IN MSPACK.H !!! */
103
+  int error;
104
+};
105
+
106
+struct mscabd_cabinet_p {
107
+  struct mscabd_cabinet base;
108
+  off_t blocks_off;                  /* offset to data blocks                */
109
+  int block_resv;                    /* reserved space in data blocks        */
110
+};
111
+
112
+/* there is one of these for every cabinet a folder spans */
113
+struct mscabd_folder_data {
114
+  struct mscabd_folder_data *next;
115
+  struct mscabd_cabinet_p *cab;      /* cabinet file of this folder span     */
116
+  off_t offset;                      /* cabinet offset of first datablock    */
117
+};
118
+
119
+struct mscabd_folder_p {
120
+  struct mscabd_folder base;
121
+  struct mscabd_folder_data data;    /* where are the data blocks?           */
122
+  struct mscabd_file *merge_prev;    /* do we need to merge backwards?       */
123
+  struct mscabd_file *merge_next;    /* do we need to merge forwards?        */
124
+};
125
+
126
+#endif
0 127
new file mode 100644
... ...
@@ -0,0 +1,1519 @@
0
+/* WARNING: This version also supports dopen for descriptor opening and
1
+ *	    is not compatible with the original version. -- T. Kojm
2
+ *
3
+ * This file is part of libmspack.
4
+ * (C) 2003-2004 Stuart Caie.
5
+ *
6
+ * libmspack is free software; you can redistribute it and/or modify it under
7
+ * the terms of the GNU Lesser General Public License (LGPL) version 2.1
8
+ *
9
+ * For further details, see the file COPYING.LIB distributed with libmspack
10
+ */
11
+
12
+/* Cabinet (.CAB) files are a form of file archive. Each cabinet contains
13
+ * "folders", which are compressed spans of data. Each cabinet has
14
+ * "files", whose metadata is in the cabinet header, but whose actual data
15
+ * is stored compressed in one of the "folders". Cabinets can span more
16
+ * than one physical file on disk, in which case they are a "cabinet set",
17
+ * and usually the last folder of each cabinet extends into the next
18
+ * cabinet.
19
+ *
20
+ * For a complete description of the format, get the official Microsoft
21
+ * CAB SDK. It can be found at the following URL:
22
+ *
23
+ *   http://msdn.microsoft.com/library/en-us/dncabsdk/html/cabdl.asp
24
+ *
25
+ * It is a self-extracting ZIP file, which can be extracted with the unzip
26
+ * command.
27
+ */
28
+
29
+/* CAB decompression implementation */
30
+
31
+#if HAVE_CONFIG_H
32
+#include "clamav-config.h"
33
+#endif
34
+
35
+#include <mspack.h>
36
+#include <system.h>
37
+#include <cab.h>
38
+
39
+/* Notes on compliance with cabinet specification:
40
+ *
41
+ * One of the main changes between cabextract 0.6 and libmspack's cab
42
+ * decompressor is the move from block-oriented decompression to
43
+ * stream-oriented decompression.
44
+ *
45
+ * cabextract would read one data block from disk, decompress it with the
46
+ * appropriate method, then write the decompressed data. The CAB
47
+ * specification is specifically designed to work like this, as it ensures
48
+ * compression matches do not span the maximum decompressed block size
49
+ * limit of 32kb.
50
+ *
51
+ * However, the compression algorithms used are stream oriented, with
52
+ * specific hacks added to them to enforce the "individual 32kb blocks"
53
+ * rule in CABs. In other file formats, they do not have this limitation.
54
+ *
55
+ * In order to make more generalised decompressors, libmspack's CAB
56
+ * decompressor has moved from being block-oriented to more stream
57
+ * oriented. This also makes decompression slightly faster.
58
+ *
59
+ * However, this leads to incompliance with the CAB specification. The
60
+ * CAB controller can no longer ensure each block of input given to the
61
+ * decompressors is matched with their output. The "decompressed size" of
62
+ * each individual block is thrown away.
63
+ *
64
+ * Each CAB block is supposed to be seen as individually compressed. This
65
+ * means each consecutive data block can have completely different
66
+ * "uncompressed" sizes, ranging from 1 to 32768 bytes. However, in
67
+ * reality, all data blocks in a folder decompress to exactly 32768 bytes,
68
+ * excepting the final block. 
69
+ *
70
+ * Given this situation, the decompression algorithms are designed to
71
+ * realign their input bitstreams on 32768 output-byte boundaries, and
72
+ * various other special cases have been made. libmspack will not
73
+ * correctly decompress LZX or Quantum compressed folders where the blocks
74
+ * do not follow this "32768 bytes until last block" pattern. It could be
75
+ * implemented if needed, but hopefully this is not necessary -- it has
76
+ * not been seen in over 3Gb of CAB archives.
77
+ */
78
+
79
+/* prototypes */
80
+static struct mscabd_cabinet * cabd_open(
81
+  struct mscab_decompressor *base, char *filename);
82
+static struct mscabd_cabinet * cabd_dopen(
83
+  struct mscab_decompressor *base, int desc);
84
+static void cabd_close(
85
+  struct mscab_decompressor *base, struct mscabd_cabinet *origcab);
86
+static int cabd_read_headers(
87
+  struct mspack_system *sys, struct mspack_file *fh,
88
+  struct mscabd_cabinet_p *cab, off_t offset, int quiet);
89
+static char *cabd_read_string(
90
+  struct mspack_system *sys, struct mspack_file *fh,
91
+  struct mscabd_cabinet_p *cab, int *error);
92
+
93
+static struct mscabd_cabinet *cabd_search(
94
+  struct mscab_decompressor *base, char *filename);
95
+static struct mscabd_cabinet *cabd_dsearch(
96
+  struct mscab_decompressor *base, int desc);
97
+static int cabd_find(
98
+  struct mscab_decompressor_p *this, unsigned char *buf,
99
+  struct mspack_file *fh, char *filename, int desc, off_t flen,
100
+  unsigned int *firstlen, struct mscabd_cabinet_p **firstcab);
101
+
102
+static int cabd_prepend(
103
+  struct mscab_decompressor *base, struct mscabd_cabinet *cab,
104
+  struct mscabd_cabinet *prevcab);
105
+static int cabd_append(
106
+  struct mscab_decompressor *base, struct mscabd_cabinet *cab,
107
+  struct mscabd_cabinet *nextcab);
108
+static int cabd_merge(
109
+  struct mscab_decompressor *base, struct mscabd_cabinet *lcab,
110
+  struct mscabd_cabinet *rcab);
111
+
112
+static int cabd_extract(
113
+  struct mscab_decompressor *base, struct mscabd_file *file, char *filename);
114
+static int cabd_init_decomp(
115
+  struct mscab_decompressor_p *this, unsigned int ct);
116
+static void cabd_free_decomp(
117
+  struct mscab_decompressor_p *this);
118
+static int cabd_sys_read(
119
+  struct mspack_file *file, void *buffer, int bytes);
120
+static int cabd_sys_write(
121
+  struct mspack_file *file, void *buffer, int bytes);
122
+static int cabd_sys_read_block(
123
+  struct mspack_system *sys, struct mscabd_decompress_state *d, int *out,
124
+  int ignore_cksum);
125
+static unsigned int cabd_checksum(
126
+  unsigned char *data, unsigned int bytes, unsigned int cksum);
127
+static struct noned_state *noned_init(
128
+  struct mspack_system *sys, struct mspack_file *in, struct mspack_file *out,
129
+  int bufsize);
130
+
131
+static int noned_decompress(
132
+  struct noned_state *s, off_t bytes);
133
+static void noned_free(
134
+  struct noned_state *state);
135
+
136
+static int cabd_param(
137
+  struct mscab_decompressor *base, int param, int value);
138
+
139
+static int cabd_error(
140
+  struct mscab_decompressor *base);
141
+
142
+
143
+/***************************************
144
+ * MSPACK_CREATE_CAB_DECOMPRESSOR
145
+ ***************************************
146
+ * constructor
147
+ */
148
+struct mscab_decompressor *
149
+  mspack_create_cab_decompressor(struct mspack_system *sys)
150
+{
151
+  struct mscab_decompressor_p *this = NULL;
152
+
153
+  if (!sys) sys = mspack_default_system;
154
+  if (!mspack_valid_system(sys)) return NULL;
155
+
156
+  if ((this = sys->alloc(sys, sizeof(struct mscab_decompressor_p)))) {
157
+    this->base.open       = &cabd_open;
158
+    this->base.dopen      = &cabd_dopen;
159
+    this->base.close      = &cabd_close;
160
+    this->base.search     = &cabd_search;
161
+    this->base.dsearch    = &cabd_dsearch;
162
+    this->base.extract    = &cabd_extract;
163
+    this->base.prepend    = &cabd_prepend;
164
+    this->base.append     = &cabd_append;
165
+    this->base.set_param  = &cabd_param;
166
+    this->base.last_error = &cabd_error;
167
+    this->system          = sys;
168
+    this->d               = NULL;
169
+    this->error           = MSPACK_ERR_OK;
170
+
171
+    this->param[MSCABD_PARAM_SEARCHBUF] = 32768;
172
+    this->param[MSCABD_PARAM_FIXMSZIP]  = 0;
173
+    this->param[MSCABD_PARAM_DECOMPBUF] = 4096;
174
+  }
175
+  return (struct mscab_decompressor *) this;
176
+}
177
+
178
+/***************************************
179
+ * MSPACK_DESTROY_CAB_DECOMPRESSOR
180
+ ***************************************
181
+ * destructor
182
+ */
183
+void mspack_destroy_cab_decompressor(struct mscab_decompressor *base) {
184
+  struct mscab_decompressor_p *this = (struct mscab_decompressor_p *) base;
185
+  if (this) {
186
+    struct mspack_system *sys = this->system;
187
+    cabd_free_decomp(this);
188
+    if (this->d) {
189
+      if (this->d->infh) sys->close(this->d->infh);
190
+      sys->free(this->d);
191
+    }
192
+    sys->free(this);
193
+  }
194
+}
195
+
196
+
197
+/***************************************
198
+ * CABD_OPEN
199
+ ***************************************
200
+ * opens a file and tries to read it as a cabinet file
201
+ */
202
+static struct mscabd_cabinet *cabd_open(struct mscab_decompressor *base,
203
+					char *filename)
204
+{
205
+  struct mscab_decompressor_p *this = (struct mscab_decompressor_p *) base;
206
+  struct mscabd_cabinet_p *cab = NULL;
207
+  struct mspack_system *sys;
208
+  struct mspack_file *fh;
209
+  int error;
210
+
211
+  if (!base) return NULL;
212
+  sys = this->system;
213
+
214
+  if ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) {
215
+    if ((cab = sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) {
216
+      cab->base.filename = filename;
217
+      /* cab->base.desc = 0; */
218
+      error = cabd_read_headers(sys, fh, cab, (off_t) 0, 0);
219
+      if (error) {
220
+	cabd_close(base, (struct mscabd_cabinet *) cab);
221
+	cab = NULL;
222
+      }
223
+      this->error = error;
224
+    }
225
+    else {
226
+      this->error = MSPACK_ERR_NOMEMORY;
227
+    }
228
+    sys->close(fh);
229
+  }
230
+  else {
231
+    this->error = MSPACK_ERR_OPEN;
232
+  }
233
+  return (struct mscabd_cabinet *) cab;
234
+}
235
+
236
+static struct mscabd_cabinet *cabd_dopen(struct mscab_decompressor *base,
237
+					int desc)
238
+{
239
+  struct mscab_decompressor_p *this = (struct mscab_decompressor_p *) base;
240
+  struct mscabd_cabinet_p *cab = NULL;
241
+  struct mspack_system *sys;
242
+  struct mspack_file *fh;
243
+  int error;
244
+
245
+  if (!base) return NULL;
246
+  sys = this->system;
247
+
248
+  if ((fh = sys->dopen(sys, desc, MSPACK_SYS_OPEN_READ))) {
249
+    if ((cab = sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) {
250
+      cab->base.filename = "descriptor";
251
+      cab->base.desc = desc;
252
+      error = cabd_read_headers(sys, fh, cab, (off_t) 0, 0);
253
+      if (error) {
254
+	cabd_close(base, (struct mscabd_cabinet *) cab);
255
+	cab = NULL;
256
+      }
257
+      this->error = error;
258
+    }
259
+    else {
260
+      this->error = MSPACK_ERR_NOMEMORY;
261
+    }
262
+    sys->close(fh);
263
+  }
264
+  else {
265
+    this->error = MSPACK_ERR_OPEN;
266
+  }
267
+  return (struct mscabd_cabinet *) cab;
268
+}
269
+
270
+/***************************************
271
+ * CABD_CLOSE
272
+ ***************************************
273
+ * frees all memory associated with a given mscabd_cabinet.
274
+ */
275
+static void cabd_close(struct mscab_decompressor *base,
276
+		       struct mscabd_cabinet *origcab)
277
+{
278
+  struct mscab_decompressor_p *this = (struct mscab_decompressor_p *) base;
279
+  struct mscabd_folder_data *dat, *ndat;
280
+  struct mscabd_cabinet *cab, *ncab;
281
+  struct mscabd_folder *fol, *nfol;
282
+  struct mscabd_file *fi, *nfi;
283
+  struct mspack_system *sys;
284
+
285
+  if (!base) return;
286
+  sys = this->system;
287
+
288
+  this->error = MSPACK_ERR_OK;
289
+
290
+  while (origcab) {
291
+    /* free files */
292
+    for (fi = origcab->files; fi; fi = nfi) {
293
+      nfi = fi->next;
294
+      sys->free(fi->filename);
295
+      sys->free(fi);
296
+    }
297
+
298
+    /* free folders */
299
+    for (fol = origcab->folders; fol; fol = nfol) {
300
+      nfol = fol->next;
301
+
302
+      /* free folder decompression state if it has been decompressed */
303
+      if (this->d && (this->d->folder == (struct mscabd_folder_p *) fol)) {
304
+	if (this->d->infh) sys->close(this->d->infh);
305
+	cabd_free_decomp(this);
306
+	sys->free(this->d);
307
+	this->d = NULL;
308
+      }
309
+
310
+      /* free folder data segments */
311
+      for (dat = ((struct mscabd_folder_p *)fol)->data.next; dat; dat = ndat) {
312
+	ndat = dat->next;
313
+	sys->free(dat);
314
+      }
315
+      sys->free(fol);
316
+    }
317
+
318
+    /* free predecessor cabinets (and the original cabinet's strings) */
319
+    for (cab = origcab; cab; cab = ncab) {
320
+      ncab = cab->prevcab;
321
+      sys->free(cab->prevname);
322
+      sys->free(cab->nextname);
323
+      sys->free(cab->previnfo);
324
+      sys->free(cab->nextinfo);
325
+      if (cab != origcab) sys->free(cab);
326
+    }
327
+
328
+    /* free successor cabinets */
329
+    for (cab = origcab->nextcab; cab; cab = ncab) {
330
+      ncab = cab->nextcab;
331
+      sys->free(cab->prevname);
332
+      sys->free(cab->nextname);
333
+      sys->free(cab->previnfo);
334
+      sys->free(cab->nextinfo);
335
+      sys->free(cab);
336
+    }
337
+
338
+    /* free actual cabinet structure */
339
+    cab = origcab->next;
340
+    sys->free(origcab);
341
+
342
+    /* repeat full procedure again with the cab->next pointer (if set) */
343
+    origcab = cab;
344
+  }
345
+}
346
+
347
+/***************************************
348
+ * CABD_READ_HEADERS
349
+ ***************************************
350
+ * reads the cabinet file header, folder list and file list.
351
+ * fills out a pre-existing mscabd_cabinet structure, allocates memory
352
+ * for folders and files as necessary
353
+ */
354
+static int cabd_read_headers(struct mspack_system *sys,
355
+			     struct mspack_file *fh,
356
+			     struct mscabd_cabinet_p *cab,
357
+			     off_t offset, int quiet)
358
+{
359
+  int num_folders, num_files, folder_resv, i, x;
360
+  struct mscabd_folder_p *fol, *linkfol = NULL;
361
+  struct mscabd_file *file, *linkfile = NULL;
362
+  unsigned char buf[64];
363
+
364
+  /* initialise pointers */
365
+  cab->base.next     = NULL;
366
+  cab->base.files    = NULL;
367
+  cab->base.folders  = NULL;
368
+  cab->base.prevcab  = cab->base.nextcab  = NULL;
369
+  cab->base.prevname = cab->base.nextname = NULL;
370
+  cab->base.previnfo = cab->base.nextinfo = NULL;
371
+
372
+  cab->base.base_offset = offset;
373
+
374
+  /* seek to CFHEADER */
375
+  if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START)) {
376
+    return MSPACK_ERR_SEEK;
377
+  }
378
+
379
+  /* read in the CFHEADER */
380
+  if (sys->read(fh, &buf[0], cfhead_SIZEOF) != cfhead_SIZEOF) {
381
+    return MSPACK_ERR_READ;
382
+  }
383
+
384
+  /* check for "MSCF" signature */
385
+  if (EndGetI32(&buf[cfhead_Signature]) != 0x4643534D) {
386
+    return MSPACK_ERR_SIGNATURE;
387
+  }
388
+
389
+  /* some basic header fields */
390
+  cab->base.length    = EndGetI32(&buf[cfhead_CabinetSize]);
391
+  cab->base.set_id    = EndGetI16(&buf[cfhead_SetID]);
392
+  cab->base.set_index = EndGetI16(&buf[cfhead_CabinetIndex]);
393
+
394
+  /* get the number of folders */
395
+  num_folders = EndGetI16(&buf[cfhead_NumFolders]);
396
+  if (num_folders == 0) {
397
+    if (!quiet) sys->message(fh, "no folders in cabinet.");
398
+    return MSPACK_ERR_DATAFORMAT;
399
+  }
400
+
401
+  /* get the number of files */
402
+  num_files = EndGetI16(&buf[cfhead_NumFiles]);
403
+  if (num_files == 0) {
404
+    if (!quiet) sys->message(fh, "no files in cabinet.");
405
+    return MSPACK_ERR_DATAFORMAT;
406
+  }
407
+
408
+  /* check cabinet version */
409
+  if ((buf[cfhead_MajorVersion] != 1) && (buf[cfhead_MinorVersion] != 3)) {
410
+    if (!quiet) sys->message(fh, "WARNING; cabinet version is not 1.3");
411
+  }
412
+
413
+  /* read the reserved-sizes part of header, if present */
414
+  cab->base.flags = EndGetI16(&buf[cfhead_Flags]);
415
+  if (cab->base.flags & cfheadRESERVE_PRESENT) {
416
+    if (sys->read(fh, &buf[0], cfheadext_SIZEOF) != cfheadext_SIZEOF) {
417
+      return MSPACK_ERR_READ;
418
+    }
419
+    cab->base.header_resv = EndGetI16(&buf[cfheadext_HeaderReserved]);
420
+    folder_resv           = buf[cfheadext_FolderReserved];
421
+    cab->block_resv       = buf[cfheadext_DataReserved];
422
+
423
+    if (cab->base.header_resv > 60000) {
424
+      if (!quiet) sys->message(fh, "WARNING; reserved header > 60000.");
425
+    }
426
+
427
+    /* skip the reserved header */
428
+    if (cab->base.header_resv) {
429
+      if (sys->seek(fh, (off_t) cab->base.header_resv, MSPACK_SYS_SEEK_CUR)) {
430
+	return MSPACK_ERR_SEEK;
431
+      }
432
+    }
433
+  }
434
+  else {
435
+    cab->base.header_resv = 0;
436
+    folder_resv           = 0; 
437
+    cab->block_resv       = 0;
438
+  }
439
+
440
+  /* read name and info of preceeding cabinet in set, if present */
441
+  if (cab->base.flags & cfheadPREV_CABINET) {
442
+    cab->base.prevname = cabd_read_string(sys, fh, cab, &x); if (x) return x;
443
+    cab->base.previnfo = cabd_read_string(sys, fh, cab, &x); if (x) return x;
444
+  }
445
+
446
+  /* read name and info of next cabinet in set, if present */
447
+  if (cab->base.flags & cfheadNEXT_CABINET) {
448
+    cab->base.nextname = cabd_read_string(sys, fh, cab, &x); if (x) return x;
449
+    cab->base.nextinfo = cabd_read_string(sys, fh, cab, &x); if (x) return x;
450
+  }
451
+
452
+  /* read folders */
453
+  for (i = 0; i < num_folders; i++) {
454
+    if (sys->read(fh, &buf[0], cffold_SIZEOF) != cffold_SIZEOF) {
455
+      return MSPACK_ERR_READ;
456
+    }
457
+    if (folder_resv) {
458
+      if (sys->seek(fh, (off_t) folder_resv, MSPACK_SYS_SEEK_CUR)) {
459
+	return MSPACK_ERR_SEEK;
460
+      }
461
+    }
462
+
463
+    if (!(fol = sys->alloc(sys, sizeof(struct mscabd_folder_p)))) {
464
+      return MSPACK_ERR_NOMEMORY;
465
+    }
466
+    fol->base.next       = NULL;
467
+    fol->base.comp_type  = EndGetI16(&buf[cffold_CompType]);
468
+    fol->base.num_blocks = EndGetI16(&buf[cffold_NumBlocks]);
469
+    fol->data.next       = NULL;
470
+    fol->data.cab        = (struct mscabd_cabinet_p *) cab;
471
+    fol->data.offset     = offset + (off_t)
472
+      ( (unsigned int) EndGetI32(&buf[cffold_DataOffset]) );
473
+    fol->merge_prev      = NULL;
474
+    fol->merge_next      = NULL;
475
+
476
+    /* link folder into list of folders */
477
+    if (!linkfol) cab->base.folders = (struct mscabd_folder *) fol;
478
+    else linkfol->base.next = (struct mscabd_folder *) fol;
479
+    linkfol = fol;
480
+  }
481
+
482
+  /* read files */
483
+  for (i = 0; i < num_files; i++) {
484
+    if (sys->read(fh, &buf[0], cffile_SIZEOF) != cffile_SIZEOF) {
485
+      return MSPACK_ERR_READ;
486
+    }
487
+
488
+    if (!(file = sys->alloc(sys, sizeof(struct mscabd_file)))) {
489
+      return MSPACK_ERR_NOMEMORY;
490
+    }
491
+
492
+    file->next     = NULL;
493
+    file->length   = EndGetI32(&buf[cffile_UncompressedSize]);
494
+    file->attribs  = EndGetI16(&buf[cffile_Attribs]);
495
+    file->offset   = EndGetI32(&buf[cffile_FolderOffset]);
496
+
497
+    /* set folder pointer */
498
+    x = EndGetI16(&buf[cffile_FolderIndex]);
499
+    if (x < cffileCONTINUED_FROM_PREV) {
500
+      /* normal folder index; count up to the correct folder. the folder
501
+       * pointer will be NULL if folder index is invalid */
502
+      struct mscabd_folder *ifol = cab->base.folders; 
503
+      while (x--) if (ifol) ifol = ifol->next;
504
+      file->folder = ifol;
505
+
506
+      if (!ifol) {
507
+	sys->free(file);
508
+	D(("invalid folder index"))
509
+	return MSPACK_ERR_DATAFORMAT;
510
+      }
511
+    }
512
+    else {
513
+      /* either CONTINUED_TO_NEXT, CONTINUED_FROM_PREV or
514
+       * CONTINUED_PREV_AND_NEXT */
515
+      if ((x == cffileCONTINUED_TO_NEXT) ||
516
+	  (x == cffileCONTINUED_PREV_AND_NEXT))
517
+      {
518
+	/* get last folder */
519
+	struct mscabd_folder *ifol = cab->base.folders;
520
+	while (ifol->next) ifol = ifol->next;
521
+	file->folder = ifol;
522
+
523
+	/* set "merge next" pointer */
524
+	fol = (struct mscabd_folder_p *) ifol;
525
+	if (!fol->merge_next) fol->merge_next = file;
526
+      }
527
+
528
+      if ((x == cffileCONTINUED_FROM_PREV) ||
529
+	  (x == cffileCONTINUED_PREV_AND_NEXT))
530
+      {
531
+	/* get first folder */
532
+	file->folder = cab->base.folders;
533
+
534
+	/* set "merge prev" pointer */
535
+	fol = (struct mscabd_folder_p *) file->folder;
536
+	if (!fol->merge_prev) fol->merge_prev = file;
537
+      }
538
+    }
539
+
540
+    /* get time */
541
+    x = EndGetI16(&buf[cffile_Time]);
542
+    file->time_h = x >> 11;
543
+    file->time_m = (x >> 5) & 0x3F;
544
+    file->time_s = (x << 1) & 0x3E;
545
+
546
+    /* get date */
547
+    x = EndGetI16(&buf[cffile_Date]);
548
+    file->date_d = x & 0x1F;
549
+    file->date_m = (x >> 5) & 0xF;
550
+    file->date_y = (x >> 9) + 1980;
551
+
552
+    /* get filename */
553
+    file->filename = cabd_read_string(sys, fh, cab, &x);
554
+    if (x) { 
555
+      sys->free(file);
556
+      return x;
557
+    }
558
+
559
+    /* link file entry into file list */
560
+    if (!linkfile) cab->base.files = file;
561
+    else linkfile->next = file;
562
+    linkfile = file;
563
+  }
564
+
565
+  return MSPACK_ERR_OK;
566
+}
567
+
568
+static char *cabd_read_string(struct mspack_system *sys,
569
+			      struct mspack_file *fh,
570
+			      struct mscabd_cabinet_p *cab, int *error)
571
+{
572
+  off_t base = sys->tell(fh);
573
+  char buf[256], *str;
574
+  unsigned int len, i, ok;
575
+
576
+  /* read up to 256 bytes */
577
+  len = sys->read(fh, &buf[0], 256);
578
+
579
+  /* search for a null terminator in the buffer */
580
+  for (i = 0, ok = 0; i < len; i++) if (!buf[i]) { ok = 1; break; }
581
+  if (!ok) {
582
+    *error = MSPACK_ERR_DATAFORMAT;
583
+    return NULL;
584
+  }
585
+
586
+  len = i + 1;
587
+
588
+  /* set the data stream to just after the string and return */
589
+  if (sys->seek(fh, base + (off_t)len, MSPACK_SYS_SEEK_START)) {
590
+    *error = MSPACK_ERR_SEEK;
591
+    return NULL;
592
+  }
593
+
594
+  if (!(str = sys->alloc(sys, len))) {
595
+    *error = MSPACK_ERR_NOMEMORY;
596
+    return NULL;
597
+  }
598
+
599
+  sys->copy(&buf[0], str, len);
600
+  *error = MSPACK_ERR_OK;
601
+  return str;
602
+}
603
+    
604
+/***************************************
605
+ * CABD_SEARCH, CABD_FIND
606
+ ***************************************
607
+ * cabd_search opens a file, finds its extent, allocates a search buffer,
608
+ * then reads through the whole file looking for possible cabinet headers.
609
+ * if it finds any, it tries to read them as real cabinets. returns a linked
610
+ * list of results
611
+ *
612
+ * cabd_find is the inner loop of cabd_search, to make it easier to
613
+ * break out of the loop and be sure that all resources are freed
614
+ */
615
+static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
616
+					  char *filename)
617
+{
618
+  struct mscab_decompressor_p *this = (struct mscab_decompressor_p *) base;
619
+  struct mscabd_cabinet_p *cab = NULL;
620
+  struct mspack_system *sys;
621
+  unsigned char *search_buf;
622
+  struct mspack_file *fh;
623
+  unsigned int firstlen = 0;
624
+  off_t filelen;
625
+
626
+  if (!base) return NULL;
627
+  sys = this->system;
628
+
629
+  /* allocate a search buffer */
630
+  search_buf = sys->alloc(sys, (size_t) this->param[MSCABD_PARAM_SEARCHBUF]);
631
+  if (!search_buf) {
632
+    this->error = MSPACK_ERR_NOMEMORY;
633
+    return NULL;
634
+  }
635
+
636
+  /* open file and get its full file length */
637
+  if ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) {
638
+    if (!(this->error = mspack_sys_filelen(sys, fh, &filelen))) {
639
+      this->error = cabd_find(this, search_buf, fh, filename, 0,
640
+			      filelen, &firstlen, &cab);
641
+    }
642
+
643
+    /* truncated / extraneous data warning: */
644
+    if (firstlen && (firstlen != filelen) &&
645
+	(!cab || (cab->base.base_offset == 0)))
646
+    {
647
+      if (firstlen < filelen) {
648
+	sys->message(fh, "WARNING; possible %u extra bytes at end of file.",
649
+		     (unsigned int) (filelen - firstlen));
650
+      }
651
+      else {
652
+	sys->message(fh, "WARNING; file possibly truncated by %u bytes.",
653
+		     (unsigned int) (firstlen - filelen));
654
+      }
655
+    }
656
+    
657
+    sys->close(fh);
658
+  }
659
+  else {
660
+    this->error = MSPACK_ERR_OPEN;
661
+  }
662
+
663
+  /* free the search buffer */
664
+  sys->free(search_buf);
665
+
666
+  return (struct mscabd_cabinet *) cab;
667
+}
668
+
669
+static struct mscabd_cabinet *cabd_dsearch(struct mscab_decompressor *base,
670
+					  int desc)
671
+{
672
+  struct mscab_decompressor_p *this = (struct mscab_decompressor_p *) base;
673
+  struct mscabd_cabinet_p *cab = NULL;
674
+  struct mspack_system *sys;
675
+  unsigned char *search_buf;
676
+  struct mspack_file *fh;
677
+  unsigned int firstlen = 0;
678
+  off_t filelen;
679
+  char *filename = "descriptor-";
680
+
681
+  if (!base) return NULL;
682
+  sys = this->system;
683
+
684
+  /* allocate a search buffer */
685
+  search_buf = sys->alloc(sys, (size_t) this->param[MSCABD_PARAM_SEARCHBUF]);
686
+  if (!search_buf) {
687
+    this->error = MSPACK_ERR_NOMEMORY;
688
+    return NULL;
689
+  }
690
+
691
+  /* open file and get its full file length */
692
+  if ((fh = sys->dopen(sys, desc, MSPACK_SYS_OPEN_READ))) {
693
+    if (!(this->error = mspack_sys_filelen(sys, fh, &filelen))) {
694
+      this->error = cabd_find(this, search_buf, fh, filename, desc,
695
+			      filelen, &firstlen, &cab);
696
+    }
697
+
698
+    /* truncated / extraneous data warning: */
699
+    if (firstlen && (firstlen != filelen) &&
700
+	(!cab || (cab->base.base_offset == 0)))
701
+    {
702
+      if (firstlen < filelen) {
703
+	sys->message(fh, "WARNING; possible %u extra bytes at end of file.",
704
+		     (unsigned int) (filelen - firstlen));
705
+      }
706
+      else {
707
+	sys->message(fh, "WARNING; file possibly truncated by %u bytes.",
708
+		     (unsigned int) (firstlen - filelen));
709
+      }
710
+    }
711
+    
712
+    /* sys->close(fh); */
713
+  }
714
+  else {
715
+    this->error = MSPACK_ERR_OPEN;
716
+  }
717
+
718
+  /* free the search buffer */
719
+  sys->free(search_buf);
720
+
721
+  return (struct mscabd_cabinet *) cab;
722
+}
723
+
724
+
725
+static int cabd_find(struct mscab_decompressor_p *this, unsigned char *buf,
726
+		     struct mspack_file *fh, char *filename, int desc, off_t flen,
727
+		     unsigned int *firstlen,
728
+		     struct mscabd_cabinet_p **firstcab)
729
+{
730
+  struct mscabd_cabinet_p *cab, *link = NULL;
731
+  off_t caboff, offset, foffset=0, cablen=0;
732
+  struct mspack_system *sys = this->system;
733
+  unsigned char *p, *pend, state = 0;
734
+  int false_cabs = 0, length;
735
+
736
+  /* search through the full file length */
737
+  for (offset = 0; offset < flen; offset += length) {
738
+    /* search length is either the full length of the search buffer, or the
739
+     * amount of data remaining to the end of the file, whichever is less. */
740
+    length = flen - offset;
741
+    if (length > this->param[MSCABD_PARAM_SEARCHBUF]) {
742
+      length = this->param[MSCABD_PARAM_SEARCHBUF];
743
+    }
744
+
745
+    /* fill the search buffer with data from disk */
746
+    if (sys->read(fh, &buf[0], length) != length) {
747
+      return MSPACK_ERR_READ;
748
+    }
749
+
750
+    /* FAQ avoidance strategy */
751
+    if ((offset == 0) && (EndGetI32(&buf[0]) == 0x28635349)) {
752
+      sys->message(fh, "WARNING; found InstallShield header. "
753
+		   "This is probably an InstallShield file. "
754
+		   "Use UNSHIELD (http://synce.sf.net) to unpack it.");
755
+    }
756
+
757
+    /* read through the entire buffer. */
758
+    for (p = &buf[0], pend = &buf[length]; p < pend; ) {
759
+      switch (state) {
760
+	/* starting state */
761
+      case 0:
762
+	/* we spend most of our time in this while loop, looking for
763
+	 * a leading 'M' of the 'MSCF' signature */
764
+	while (p < pend && *p != 0x4D) p++;
765
+	/* if we found tht 'M', advance state */
766
+	if (p++ < pend) state = 1;
767
+	break;
768
+
769
+      /* verify that the next 3 bytes are 'S', 'C' and 'F' */
770
+      case 1: state = (*p++ == 0x53) ? 2 : 0; break;
771
+      case 2: state = (*p++ == 0x43) ? 3 : 0; break;
772
+      case 3: state = (*p++ == 0x46) ? 4 : 0; break;
773
+
774
+      /* we don't care about bytes 4-7 (see default: for action) */
775
+
776
+      /* bytes 8-11 are the overall length of the cabinet */
777
+      case 8:  cablen  = *p++;       state++; break;
778
+      case 9:  cablen |= *p++ << 8;  state++; break;
779
+      case 10: cablen |= *p++ << 16; state++; break;
780
+      case 11: cablen |= *p++ << 24; state++; break;
781
+
782
+      /* we don't care about bytes 12-15 (see default: for action) */
783
+
784
+      /* bytes 16-19 are the offset within the cabinet of the filedata */
785
+      case 16: foffset  = *p++;       state++; break;
786
+      case 17: foffset |= *p++ << 8;  state++; break;
787
+      case 18: foffset |= *p++ << 16; state++; break;
788
+      case 19: foffset |= *p++ << 24;
789
+	/* now we have recieved 20 bytes of potential cab header. work out
790
+	 * the offset in the file of this potential cabinet */
791
+	caboff = offset + (p - &buf[0]) - 20;
792
+
793
+	/* should reading cabinet fail, restart search just after 'MSCF' */
794
+	offset = caboff + 4;
795
+
796
+	/* capture the "length of cabinet" field if there is a cabinet at
797
+	 * offset 0 in the file, regardless of whether the cabinet can be
798
+	 * read correctly or not */
799
+	if (caboff == 0) *firstlen = cablen;
800
+
801
+	/* check that the files offset is less than the alleged length of
802
+	 * the cabinet, and that the offset + the alleged length are
803
+	 * 'roughly' within the end of overall file length */
804
+	if ((foffset < cablen) &&
805
+	    ((caboff + foffset) < (flen + 32)) &&
806
+	    ((caboff + cablen)  < (flen + 32)) )
807
+	{
808
+	  /* likely cabinet found -- try reading it */
809
+	  if (!(cab = sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) {
810
+	    return MSPACK_ERR_NOMEMORY;
811
+	  }
812
+	  cab->base.filename = filename;
813
+	  cab->base.desc = desc;
814
+	  if (cabd_read_headers(sys, fh, cab, caboff, 1)) {
815
+	    /* destroy the failed cabinet */
816
+	    cabd_close((struct mscab_decompressor *) this,
817
+		       (struct mscabd_cabinet *) cab);
818
+	    false_cabs++;
819
+	  }
820
+	  else {
821
+	    /* cabinet read correctly! */
822
+
823
+	    /* cause the search to restart after this cab's data. */
824
+	    offset = caboff + cablen;
825
+	      
826
+	    /* link the cab into the list */
827
+	    if (!link) *firstcab = cab;
828
+	    else link->base.next = (struct mscabd_cabinet *) cab;
829
+	    link = cab;
830
+	  }
831
+	}
832
+
833
+	/* restart search */
834
+	if (offset >= flen) return MSPACK_ERR_OK;
835
+	if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START))
836
+	  return MSPACK_ERR_SEEK;
837
+	length = 0;
838
+	p = pend;
839
+	state = 0;
840
+	break;
841
+
842
+      /* for bytes 4-7 and 12-15, just advance state/pointer */
843
+      default:
844
+	p++, state++;
845
+      } /* switch(state) */
846
+    } /* for (... p < pend ...) */
847
+  } /* for (... offset < length ...) */
848
+
849
+  if (false_cabs) {
850
+    D(("%d false cabinets found", false_cabs))
851
+  }
852
+
853
+  return MSPACK_ERR_OK;
854
+}
855
+					     
856
+/***************************************
857
+ * CABD_MERGE, CABD_PREPEND, CABD_APPEND
858
+ ***************************************
859
+ * joins cabinets together, also merges split folders between these two
860
+ * cabinets only. this includes freeing the duplicate folder and file(s)
861
+ * and allocating a further mscabd_folder_data structure to append to the
862
+ * merged folder's data parts list.
863
+ */
864
+static int cabd_prepend(struct mscab_decompressor *base,
865
+			struct mscabd_cabinet *cab,
866
+			struct mscabd_cabinet *prevcab)
867
+{
868
+  return cabd_merge(base, prevcab, cab);
869
+}
870
+
871
+static int cabd_append(struct mscab_decompressor *base,
872
+			struct mscabd_cabinet *cab,
873
+			struct mscabd_cabinet *nextcab)
874
+{
875
+  return cabd_merge(base, cab, nextcab);
876
+}
877
+
878
+static int cabd_merge(struct mscab_decompressor *base,
879
+		      struct mscabd_cabinet *lcab,
880
+		      struct mscabd_cabinet *rcab)
881
+{
882
+  struct mscab_decompressor_p *this = (struct mscab_decompressor_p *) base;
883
+  struct mscabd_folder_data *data, *ndata;
884
+  struct mscabd_folder_p *lfol, *rfol;
885
+  struct mscabd_file *fi, *rfi, *lfi;
886
+  struct mscabd_cabinet *cab;
887
+  struct mspack_system *sys;
888
+
889
+  if (!this) return MSPACK_ERR_ARGS;
890
+  sys = this->system;
891
+
892
+  /* basic args check */
893
+  if (!lcab || !rcab || (lcab == rcab)) {
894
+    D(("lcab NULL, rcab NULL or lcab = rcab"))
895
+    return this->error = MSPACK_ERR_ARGS;
896
+  }
897
+
898
+  /* check there's not already a cabinet attached */
899
+  if (lcab->nextcab || rcab->prevcab) {
900
+    D(("cabs already joined"))
901
+    return this->error = MSPACK_ERR_ARGS;
902
+  }
903
+
904
+  /* do not create circular cabinet chains */
905
+  for (cab = lcab->prevcab; cab; cab = cab->prevcab) {
906
+    if (cab == rcab) {D(("circular!")) return this->error = MSPACK_ERR_ARGS;}
907
+  }
908
+  for (cab = rcab->nextcab; cab; cab = cab->nextcab) {
909
+    if (cab == lcab) {D(("circular!")) return this->error = MSPACK_ERR_ARGS;}
910
+  }
911
+
912
+  /* warn about odd set IDs or indices */
913
+  if (lcab->set_id != rcab->set_id) {
914
+    sys->message(NULL, "WARNING; merged cabinets with differing Set IDs.");
915
+  }
916
+
917
+  if (lcab->set_index > rcab->set_index) {
918
+    sys->message(NULL, "WARNING; merged cabinets with odd order.");
919
+  }
920
+
921
+  /* merging the last folder in lcab with the first folder in rcab */
922
+  lfol = (struct mscabd_folder_p *) lcab->folders;
923
+  rfol = (struct mscabd_folder_p *) rcab->folders;
924
+  while (lfol->base.next) lfol = (struct mscabd_folder_p *) lfol->base.next;
925
+
926
+  /* do we need to merge folders? */
927
+  if (!lfol->merge_next && !rfol->merge_prev) {
928
+    /* no, at least one of the folders is not for merging */
929
+
930
+    /* attach cabs */
931
+    lcab->nextcab = rcab;
932
+    rcab->prevcab = lcab;
933
+
934
+    /* attach folders */
935
+    lfol->base.next = (struct mscabd_folder *) rfol;
936
+
937
+    /* attach files */
938
+    fi = lcab->files;
939
+    while (fi->next) fi = fi->next;
940
+    fi->next = rcab->files;
941
+  }
942
+  else {
943
+    /* folder merge required */
944
+
945
+    if (!lfol->merge_next) {
946
+      D(("rcab has merge files, lcab doesn't"))
947
+      return this->error = MSPACK_ERR_DATAFORMAT;
948
+    }
949
+
950
+    if (!rfol->merge_prev) {
951
+      D(("lcab has merge files, rcab doesn't"))
952
+      return this->error = MSPACK_ERR_DATAFORMAT;
953
+    }
954
+
955
+    /* check that both folders use the same compression method/settings */
956
+    if (lfol->base.comp_type != rfol->base.comp_type) {
957
+      D(("compression type mismatch"))
958
+      return this->error = MSPACK_ERR_DATAFORMAT;
959
+    }
960
+
961
+    /* for all files in lfol (which is the last folder in whichever cab),
962
+     * compare them to the files from rfol. they should be identical in
963
+     * number and order. to verify this, check the OFFSETS of each file. */
964
+    lfi = lfol->merge_next;
965
+    rfi = rfol->merge_prev;
966
+    while (lfi) {
967
+      if (!rfi || (lfi->offset !=  rfi->offset)) {
968
+	D(("folder merge mismatch"))
969
+	return this->error = MSPACK_ERR_DATAFORMAT;
970
+      }
971
+      lfi = lfi->next;
972
+      rfi = rfi->next;
973
+    }
974
+
975
+    /* allocate a new folder data structure */
976
+    if (!(data = sys->alloc(sys, sizeof(struct mscabd_folder_data)))) {
977
+      return this->error = MSPACK_ERR_NOMEMORY;
978
+    }
979
+
980
+    /* attach cabs */
981
+    lcab->nextcab = rcab;
982
+    rcab->prevcab = lcab;
983
+
984
+    /* append rfol's data to lfol */
985
+    ndata = &lfol->data;
986
+    while (ndata->next) ndata = ndata->next;
987
+    ndata->next = data;
988
+    *data = rfol->data;
989
+    rfol->data.next = NULL;
990
+
991
+    /* lfol becomes rfol.
992
+     * NOTE: special case, don't merge if rfol is merge prev and next,
993
+     * rfol->merge_next is going to be deleted, so keep lfol's version
994
+     * instead */
995
+    lfol->base.num_blocks += rfol->base.num_blocks - 1;
996
+    if ((rfol->merge_next == NULL) ||
997
+	(rfol->merge_next->folder != (struct mscabd_folder *) rfol))
998
+    {
999
+      lfol->merge_next = rfol->merge_next;
1000
+    }
1001
+
1002
+    /* attach the rfol's folder (except the merge folder) */
1003
+    while (lfol->base.next) lfol = (struct mscabd_folder_p *) lfol->base.next;
1004
+    lfol->base.next = rfol->base.next;
1005
+
1006
+    /* free disused merge folder */
1007
+    sys->free(rfol);
1008
+
1009
+    /* attach rfol's files */
1010
+    fi = lcab->files;
1011
+    while (fi->next) fi = fi->next;
1012
+    fi->next = rcab->files;
1013
+
1014
+    /* delete all files from rfol's merge folder */
1015
+    lfi = NULL;
1016
+    for (fi = lcab->files; fi ; fi = rfi) {
1017
+      rfi = fi->next;
1018
+      /* if file's folder matches the merge folder, unlink and free it */
1019
+      if (fi->folder == (struct mscabd_folder *) rfol) {
1020
+	if (lfi) lfi->next = rfi; else lcab->files = rfi;
1021
+	sys->free(fi->filename);
1022
+	sys->free(fi);
1023
+      }
1024
+      else lfi = fi;
1025
+    }
1026
+  }
1027
+
1028
+  /* all done! fix files and folders pointers in all cabs so they all
1029
+   * point to the same list  */
1030
+  for (cab = lcab->prevcab; cab; cab = cab->prevcab) {
1031
+    cab->files   = lcab->files;
1032
+    cab->folders = lcab->folders;
1033
+  }
1034
+
1035
+  for (cab = lcab->nextcab; cab; cab = cab->nextcab) {
1036
+    cab->files   = lcab->files;
1037
+    cab->folders = lcab->folders;
1038
+  }
1039
+
1040
+  return this->error = MSPACK_ERR_OK;
1041
+}
1042
+
1043
+/***************************************
1044
+ * CABD_EXTRACT
1045
+ ***************************************
1046
+ * extracts a file from a cabinet
1047
+ */
1048
+static int cabd_extract(struct mscab_decompressor *base,
1049
+			 struct mscabd_file *file, char *filename)
1050
+{
1051
+  struct mscab_decompressor_p *this = (struct mscab_decompressor_p *) base;
1052
+  struct mscabd_folder_p *fol;
1053
+  struct mspack_system *sys;
1054
+  struct mspack_file *fh;
1055
+
1056
+  if (!this) return MSPACK_ERR_ARGS;
1057
+  if (!file) return this->error = MSPACK_ERR_ARGS;
1058
+
1059
+  sys = this->system;
1060
+  fol = (struct mscabd_folder_p *) file->folder;
1061
+
1062
+  /* check if file can be extracted */
1063
+  if ((!fol) || (fol->merge_prev) ||
1064
+      (((file->offset + file->length) / CAB_BLOCKMAX) > fol->base.num_blocks))
1065
+  {
1066
+    sys->message(NULL, "ERROR; file \"%s\" cannot be extracted, "
1067
+		 "cabinet set is incomplete.", file->filename);
1068
+    return this->error = MSPACK_ERR_DATAFORMAT;
1069
+  }
1070
+
1071
+  /* allocate generic decompression state */
1072
+  if (!this->d) {
1073
+    this->d = sys->alloc(sys, sizeof(struct mscabd_decompress_state));
1074
+    if (!this->d) return this->error = MSPACK_ERR_NOMEMORY;
1075
+    this->d->folder     = NULL;
1076
+    this->d->data       = NULL;
1077
+    this->d->sys        = *sys;
1078
+    this->d->sys.read   = &cabd_sys_read;
1079
+    this->d->sys.write  = &cabd_sys_write;
1080
+    this->d->state      = NULL;
1081
+    this->d->infh       = NULL;
1082
+    this->d->incab      = NULL;
1083
+  }
1084
+
1085
+  /* do we need to change folder or reset the current folder? */
1086
+  if ((this->d->folder != fol) || (this->d->offset > file->offset)) {
1087
+    /* do we need to open a new cab file? */
1088
+
1089
+    if (!this->d->infh || (fol->data.cab != this->d->incab)) {
1090
+      if (this->d->infh) sys->close(this->d->infh);
1091
+      this->d->incab = fol->data.cab;
1092
+
1093
+      if(fol->data.cab->base.desc) {
1094
+        this->d->infh = sys->dopen(sys, fol->data.cab->base.desc,
1095
+				MSPACK_SYS_OPEN_READ);
1096
+      } else {
1097
+        this->d->infh = sys->open(sys, fol->data.cab->base.filename,
1098
+				MSPACK_SYS_OPEN_READ);
1099
+      }
1100
+      if (!this->d->infh) return this->error = MSPACK_ERR_OPEN;
1101
+    }
1102
+
1103
+    /* seek to start of data blocks */
1104
+    if (sys->seek(this->d->infh, fol->data.offset, MSPACK_SYS_SEEK_START)) {
1105
+      return this->error = MSPACK_ERR_SEEK;
1106
+    }
1107
+
1108
+    /* set up decompressor */
1109
+    if (cabd_init_decomp(this, (unsigned int) fol->base.comp_type)) {
1110
+      return this->error;
1111
+    }
1112
+
1113
+    /* initialise new folder state */
1114
+    this->d->folder = fol;
1115
+    this->d->data   = &fol->data;
1116
+    this->d->offset = 0;
1117
+    this->d->block  = 0;
1118
+    this->d->i_ptr = this->d->i_end = &this->d->input[0];
1119
+  }
1120
+
1121
+  /* open file for output */
1122
+  if (!(fh = sys->open(sys, filename, MSPACK_SYS_OPEN_WRITE))) {
1123
+    return this->error = MSPACK_ERR_OPEN;
1124
+  }
1125
+
1126
+  this->error = MSPACK_ERR_OK;
1127
+
1128
+  /* if file has more than 0 bytes */
1129
+  if (file->length) {
1130
+    off_t bytes;
1131
+    int error;
1132
+    /* get to correct offset.
1133
+     * - use NULL fh to say 'no writing' to cabd_sys_write()
1134
+     * - MSPACK_ERR_READ returncode indicates error in cabd_sys_read(),
1135
+     *   the real error will already be stored in this->error
1136
+     */
1137
+    this->d->outfh = NULL;
1138
+    if ((bytes = file->offset - this->d->offset)) {
1139
+      error = this->d->decompress(this->d->state, bytes);
1140
+      if (error != MSPACK_ERR_READ) this->error = error;
1141
+    }
1142
+
1143
+    /* if getting to the correct offset was error free, unpack file */
1144
+    if (!this->error) {
1145
+      this->d->outfh = fh;
1146
+      error = this->d->decompress(this->d->state, (off_t) file->length);
1147
+      if (error != MSPACK_ERR_READ) this->error = error;
1148
+    }
1149
+  }
1150
+
1151
+  /* close output file */
1152
+  sys->close(fh);
1153
+  this->d->outfh = NULL;
1154
+
1155
+  return this->error;
1156
+}
1157
+
1158
+/***************************************
1159
+ * CABD_INIT_DECOMP, CABD_FREE_DECOMP
1160
+ ***************************************
1161
+ * cabd_init_decomp initialises decompression state, according to which
1162
+ * decompression method was used. relies on this->d->folder being the same
1163
+ * as when initialised.
1164
+ *
1165
+ * cabd_free_decomp frees decompression state, according to which method
1166
+ * was used.
1167
+ */
1168
+static int cabd_init_decomp(struct mscab_decompressor_p *this, unsigned int ct)
1169
+{
1170
+  struct mspack_file *fh = (struct mspack_file *) this;
1171
+
1172
+  if (!this || !this->d) {
1173
+    return this->error = MSPACK_ERR_ARGS;
1174
+  }
1175
+
1176
+  /* free any existing decompressor */
1177
+  cabd_free_decomp(this);
1178
+
1179
+  this->d->comp_type = ct;
1180
+
1181
+  switch (ct & cffoldCOMPTYPE_MASK) {
1182
+  case cffoldCOMPTYPE_NONE:
1183
+    this->d->decompress = (int (*)(void *, off_t)) &noned_decompress;
1184
+    this->d->state = noned_init(&this->d->sys, fh, fh,
1185
+				this->param[MSCABD_PARAM_DECOMPBUF]);
1186
+    break;
1187
+  case cffoldCOMPTYPE_MSZIP:
1188
+    this->d->decompress = (int (*)(void *, off_t)) &mszipd_decompress;
1189
+    this->d->state = mszipd_init(&this->d->sys, fh, fh,
1190
+				 this->param[MSCABD_PARAM_DECOMPBUF],
1191
+				 this->param[MSCABD_PARAM_FIXMSZIP]);
1192
+    break;
1193
+  case cffoldCOMPTYPE_QUANTUM:
1194
+    this->d->decompress = (int (*)(void *, off_t)) &qtmd_decompress;
1195
+    this->d->state = qtmd_init(&this->d->sys, fh, fh, (int) (ct >> 8) & 0x1f,
1196
+			       this->param[MSCABD_PARAM_DECOMPBUF]);
1197
+    break;
1198
+  case cffoldCOMPTYPE_LZX:
1199
+    this->d->decompress = (int (*)(void *, off_t)) &lzxd_decompress;
1200
+    this->d->state = lzxd_init(&this->d->sys, fh, fh, (int) (ct >> 8) & 0x1f, 0,
1201
+			       this->param[MSCABD_PARAM_DECOMPBUF], (off_t) 0);
1202
+    break;
1203
+  default:
1204
+    return this->error = MSPACK_ERR_DATAFORMAT;
1205
+  }
1206
+  return this->error = (this->d->state) ? MSPACK_ERR_OK : MSPACK_ERR_NOMEMORY;
1207
+}
1208
+
1209
+static void cabd_free_decomp(struct mscab_decompressor_p *this) {
1210
+  if (!this || !this->d || !this->d->folder || !this->d->state) return;
1211
+
1212
+  switch (this->d->comp_type & cffoldCOMPTYPE_MASK) {
1213
+  case cffoldCOMPTYPE_NONE:    noned_free(this->d->state);   break;
1214
+  case cffoldCOMPTYPE_MSZIP:   mszipd_free(this->d->state);  break;
1215
+  case cffoldCOMPTYPE_QUANTUM: qtmd_free(this->d->state);    break;
1216
+  case cffoldCOMPTYPE_LZX:     lzxd_free(this->d->state);    break;
1217
+  }
1218
+  this->d->decompress = NULL;
1219
+  this->d->state      = NULL;
1220
+}
1221
+
1222
+/***************************************
1223
+ * CABD_SYS_READ, CABD_SYS_WRITE
1224
+ ***************************************
1225
+ * cabd_sys_read is the internal reader function which the decompressors
1226
+ * use. will read data blocks (and merge split blocks) from the cabinet
1227
+ * and serve the read bytes to the decompressors
1228
+ *
1229
+ * cabd_sys_write is the internal writer function which the decompressors
1230
+ * use. it either writes data to disk (this->d->outfh) with the real
1231
+ * sys->write() function, or does nothing with the data when
1232
+ * this->d->outfh == NULL. advances this->d->offset
1233
+ */
1234
+static int cabd_sys_read(struct mspack_file *file, void *buffer, int bytes) {
1235
+  struct mscab_decompressor_p *this = (struct mscab_decompressor_p *) file;
1236
+  unsigned char *buf = (unsigned char *) buffer;
1237
+  struct mspack_system *sys = this->system;
1238
+  int avail, todo, outlen, ignore_cksum;
1239
+
1240
+  ignore_cksum = this->param[MSCABD_PARAM_FIXMSZIP] &&
1241
+    ((this->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_MSZIP);
1242
+
1243
+  todo = bytes;
1244
+  while (todo > 0) {
1245
+    avail = this->d->i_end - this->d->i_ptr;
1246
+
1247
+    /* if out of input data, read a new block */
1248
+    if (avail) {
1249
+      /* copy as many input bytes available as possible */
1250
+      if (avail > todo) avail = todo;
1251
+      sys->copy(this->d->i_ptr, buf, (size_t) avail);
1252
+      this->d->i_ptr += avail;
1253
+      buf  += avail;
1254
+      todo -= avail;
1255
+    }
1256
+    else {
1257
+      /* out of data, read a new block */
1258
+
1259
+      /* check if we're out of input blocks, advance block counter */
1260
+      if (this->d->block++ >= this->d->folder->base.num_blocks) {
1261
+	this->error = MSPACK_ERR_DATAFORMAT;
1262
+	break;
1263
+      }
1264
+
1265
+      /* read a block */
1266
+      this->error = cabd_sys_read_block(sys, this->d, &outlen, ignore_cksum);
1267
+      if (this->error) return -1;
1268
+
1269
+      /* special Quantum hack -- trailer byte to allow the decompressor
1270
+       * to realign itself. CAB Quantum blocks, unlike LZX blocks, can have
1271
+       * anything from 0 to 4 trailing null bytes. */
1272
+      if ((this->d->comp_type & cffoldCOMPTYPE_MASK)==cffoldCOMPTYPE_QUANTUM) {
1273
+	*this->d->i_end++ = 0xFF;
1274
+      }
1275
+
1276
+      /* is this the last block? */
1277
+      if (this->d->block >= this->d->folder->base.num_blocks) {
1278
+	/* last block */
1279
+	if ((this->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_LZX) {
1280
+	  /* special LZX hack -- on the last block, inform LZX of the
1281
+	   * size of the output data stream. */
1282
+	  lzxd_set_output_length(this->d->state, (off_t)
1283
+				 ((this->d->block-1) * CAB_BLOCKMAX + outlen));
1284
+	}
1285
+      }
1286
+      else {
1287
+	/* not the last block */
1288
+	if (outlen != CAB_BLOCKMAX) {
1289
+	  this->system->message(this->d->infh,
1290
+				"WARNING; non-maximal data block");
1291
+	}
1292
+      }
1293
+    } /* if (avail) */
1294
+  } /* while (todo > 0) */
1295
+  return bytes - todo;
1296
+}
1297
+
1298
+static int cabd_sys_write(struct mspack_file *file, void *buffer, int bytes) {
1299
+  struct mscab_decompressor_p *this = (struct mscab_decompressor_p *) file;
1300
+  this->d->offset += bytes;
1301
+  if (this->d->outfh) {
1302
+    return this->system->write(this->d->outfh, buffer, bytes);
1303
+  }
1304
+  return bytes;
1305
+}
1306
+
1307
+/***************************************
1308
+ * CABD_SYS_READ_BLOCK
1309
+ ***************************************
1310
+ * reads a whole data block from a cab file. the block may span more than
1311
+ * one cab file, if it does then the fragments will be reassembled
1312
+ */
1313
+static int cabd_sys_read_block(struct mspack_system *sys,
1314
+			       struct mscabd_decompress_state *d,
1315
+			       int *out, int ignore_cksum)
1316
+{
1317
+  unsigned char hdr[cfdata_SIZEOF];
1318
+  unsigned int cksum;
1319
+  int len;
1320
+
1321
+  /* reset the input block pointer and end of block pointer */
1322
+  d->i_ptr = d->i_end = &d->input[0];
1323
+
1324
+  do {
1325
+    /* read the block header */
1326
+    if (sys->read(d->infh, &hdr[0], cfdata_SIZEOF) != cfdata_SIZEOF) {
1327
+      return MSPACK_ERR_READ;
1328
+    }
1329
+
1330
+    /* skip any reserved block headers */
1331
+    if (d->data->cab->block_resv &&
1332
+	sys->seek(d->infh, (off_t) d->data->cab->block_resv,
1333
+		  MSPACK_SYS_SEEK_CUR))
1334
+    {
1335
+      return MSPACK_ERR_SEEK;
1336
+    }
1337
+
1338
+    /* blocks must not be over CAB_INPUTMAX in size */
1339
+    len = EndGetI16(&hdr[cfdata_CompressedSize]);
1340
+    if (((d->i_end - d->i_ptr) + len) > CAB_INPUTMAX) {
1341
+      D(("block size > CAB_INPUTMAX (%d + %d)", d->i_end - d->i_ptr, len))
1342
+      return MSPACK_ERR_DATAFORMAT;
1343
+    }
1344
+
1345
+     /* blocks must not expand to more than CAB_BLOCKMAX */
1346
+    if (EndGetI16(&hdr[cfdata_UncompressedSize]) > CAB_BLOCKMAX) {
1347
+      D(("block size > CAB_BLOCKMAX"))
1348
+      return MSPACK_ERR_DATAFORMAT;
1349
+    }
1350
+
1351
+    /* read the block data */
1352
+    if (sys->read(d->infh, d->i_end, len) != len) {
1353
+      return MSPACK_ERR_READ;
1354
+    }
1355
+
1356
+    /* perform checksum test on the block (if one is stored) */
1357
+    if ((cksum = EndGetI32(&hdr[cfdata_CheckSum]))) {
1358
+      unsigned int sum2 = cabd_checksum(d->i_end, (unsigned int) len, 0);
1359
+      if (cabd_checksum(&hdr[4], 4, sum2) != cksum) {
1360
+	if (!ignore_cksum) return MSPACK_ERR_CHECKSUM;
1361
+	sys->message(d->infh, "WARNING; bad block checksum found");
1362
+      }
1363
+    }
1364
+
1365
+    /* advance end of block pointer to include newly read data */
1366
+    d->i_end += len;
1367
+
1368
+    /* uncompressed size == 0 means this block was part of a split block
1369
+     * and it continues as the first block of the next cabinet in the set.
1370
+     * otherwise, this is the last part of the block, and no more block
1371
+     * reading needs to be done.
1372
+     */
1373
+    /* EXIT POINT OF LOOP -- uncompressed size != 0 */
1374
+    if ((*out = EndGetI16(&hdr[cfdata_UncompressedSize]))) {
1375
+      return MSPACK_ERR_OK;
1376
+    }
1377
+
1378
+    /* otherwise, advance to next cabinet */
1379
+
1380
+    /* close current file handle */
1381
+    sys->close(d->infh);
1382
+    d->infh = NULL;
1383
+
1384
+    /* advance to next member in the cabinet set */
1385
+    if (!(d->data = d->data->next)) {
1386
+      D(("ran out of splits in cabinet set"))
1387
+      return MSPACK_ERR_DATAFORMAT;
1388
+    }
1389
+
1390
+    /* open next cab file */
1391
+    d->incab = d->data->cab;
1392
+    if (!(d->infh = sys->open(sys, d->incab->base.filename,
1393
+			      MSPACK_SYS_OPEN_READ)))
1394
+    {
1395
+      return MSPACK_ERR_OPEN;
1396
+    }
1397
+
1398
+    /* seek to start of data blocks */
1399
+    if (sys->seek(d->infh, d->data->offset, MSPACK_SYS_SEEK_START)) {
1400
+      return MSPACK_ERR_SEEK;
1401
+    }
1402
+  } while (1);
1403
+
1404
+  /* not reached */
1405
+  return MSPACK_ERR_OK;
1406
+}
1407
+
1408
+static unsigned int cabd_checksum(unsigned char *data, unsigned int bytes,
1409
+				  unsigned int cksum)
1410
+{
1411
+  unsigned int len, ul = 0;
1412
+
1413
+  for (len = bytes >> 2; len--; data += 4) {
1414
+    cksum ^= ((data[0]) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24));
1415
+  }
1416
+
1417
+  switch (bytes & 3) {
1418
+  case 3: ul |= *data++ << 16;
1419
+  case 2: ul |= *data++ <<  8;
1420
+  case 1: ul |= *data;
1421
+  }
1422
+  cksum ^= ul;
1423
+
1424
+  return cksum;
1425
+}
1426
+
1427
+/***************************************
1428
+ * NONED_INIT, NONED_DECOMPRESS, NONED_FREE
1429
+ ***************************************
1430
+ * the "not compressed" method decompressor
1431
+ */
1432
+struct noned_state {
1433
+  struct mspack_system *sys;
1434
+  struct mspack_file *i;
1435
+  struct mspack_file *o;
1436
+  unsigned char *buf;
1437
+  int bufsize;
1438
+};
1439
+
1440
+static struct noned_state *noned_init(struct mspack_system *sys,
1441
+				      struct mspack_file *in,
1442
+				      struct mspack_file *out,
1443
+				      int bufsize)
1444
+{
1445
+  struct noned_state *state = sys->alloc(sys, sizeof(struct noned_state));
1446
+  unsigned char *buf = sys->alloc(sys, (size_t) bufsize);
1447
+  if (state && buf) {
1448
+    state->sys     = sys;
1449
+    state->i       = in;
1450
+    state->o       = out;
1451
+    state->buf     = buf;
1452
+    state->bufsize = bufsize;
1453
+  }
1454
+  else {
1455
+    sys->free(buf);
1456
+    sys->free(state);
1457
+    state = NULL;
1458
+  }
1459
+  return state;
1460
+}
1461
+
1462
+static int noned_decompress(struct noned_state *s, off_t bytes) {
1463
+  int run;
1464
+  while (bytes > 0) {
1465
+    run = (bytes > s->bufsize) ? s->bufsize : (int) bytes;
1466
+    if (s->sys->read(s->i, &s->buf[0], run) != run) return MSPACK_ERR_READ;
1467
+    if (s->sys->write(s->o, &s->buf[0], run) != run) return MSPACK_ERR_WRITE;
1468
+    bytes -= run;
1469
+  }
1470
+  return MSPACK_ERR_OK;
1471
+}
1472
+
1473
+static void noned_free(struct noned_state *state) {
1474
+  struct mspack_system *sys;
1475
+  if (state) {
1476
+    sys = state->sys;
1477
+    sys->free(state->buf);
1478
+    sys->free(state);
1479
+  }
1480
+}
1481
+
1482
+
1483
+/***************************************
1484
+ * CABD_PARAM
1485
+ ***************************************
1486
+ * allows a parameter to be set
1487
+ */
1488
+static int cabd_param(struct mscab_decompressor *base, int param, int value) {
1489
+  struct mscab_decompressor_p *this = (struct mscab_decompressor_p *) base;
1490
+  if (!this) return MSPACK_ERR_ARGS;
1491
+
1492
+  switch (param) {
1493
+  case MSCABD_PARAM_SEARCHBUF:
1494
+    if (value < 4) return MSPACK_ERR_ARGS;
1495
+    this->param[MSCABD_PARAM_SEARCHBUF] = value;
1496
+    break;
1497
+  case MSCABD_PARAM_FIXMSZIP:
1498
+    this->param[MSCABD_PARAM_FIXMSZIP] = value;
1499
+    break;
1500
+  case MSCABD_PARAM_DECOMPBUF:
1501
+    if (value < 4) return MSPACK_ERR_ARGS;
1502
+    this->param[MSCABD_PARAM_DECOMPBUF] = value;
1503
+    break;
1504
+  default:
1505
+    return MSPACK_ERR_ARGS;
1506
+  }
1507
+  return MSPACK_ERR_OK;
1508
+}
1509
+
1510
+/***************************************
1511
+ * CABD_ERROR
1512
+ ***************************************
1513
+ * returns the last error that occurred
1514
+ */
1515
+static int cabd_error(struct mscab_decompressor *base) {
1516
+  struct mscab_decompressor_p *this = (struct mscab_decompressor_p *) base;
1517
+  return (this) ? this->error : MSPACK_ERR_ARGS;
1518
+}
0 1519
new file mode 100644
... ...
@@ -0,0 +1,167 @@
0
+/* This file is part of libmspack.
1
+ * (C) 2003-2004 Stuart Caie.
2
+ *
3
+ * The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
4
+ * by Microsoft Corporation.
5
+ *
6
+ * libmspack is free software; you can redistribute it and/or modify it under
7
+ * the terms of the GNU Lesser General Public License (LGPL) version 2.1
8
+ *
9
+ * For further details, see the file COPYING.LIB distributed with libmspack
10
+ */
11
+
12
+#ifndef MSPACK_LZX_H
13
+#define MSPACK_LZX_H 1
14
+
15
+/* LZX compression / decompression definitions */
16
+
17
+/* some constants defined by the LZX specification */
18
+#define LZX_MIN_MATCH                (2)
19
+#define LZX_MAX_MATCH                (257)
20
+#define LZX_NUM_CHARS                (256)
21
+#define LZX_BLOCKTYPE_INVALID        (0)   /* also blocktypes 4-7 invalid */
22
+#define LZX_BLOCKTYPE_VERBATIM       (1)
23
+#define LZX_BLOCKTYPE_ALIGNED        (2)
24
+#define LZX_BLOCKTYPE_UNCOMPRESSED   (3)
25
+#define LZX_PRETREE_NUM_ELEMENTS     (20)
26
+#define LZX_ALIGNED_NUM_ELEMENTS     (8)   /* aligned offset tree #elements */
27
+#define LZX_NUM_PRIMARY_LENGTHS      (7)   /* this one missing from spec! */
28
+#define LZX_NUM_SECONDARY_LENGTHS    (249) /* length tree #elements */
29
+
30
+/* LZX huffman defines: tweak tablebits as desired */
31
+#define LZX_PRETREE_MAXSYMBOLS  (LZX_PRETREE_NUM_ELEMENTS)
32
+#define LZX_PRETREE_TABLEBITS   (6)
33
+#define LZX_MAINTREE_MAXSYMBOLS (LZX_NUM_CHARS + 50*8)
34
+#define LZX_MAINTREE_TABLEBITS  (12)
35
+#define LZX_LENGTH_MAXSYMBOLS   (LZX_NUM_SECONDARY_LENGTHS+1)
36
+#define LZX_LENGTH_TABLEBITS    (12)
37
+#define LZX_ALIGNED_MAXSYMBOLS  (LZX_ALIGNED_NUM_ELEMENTS)
38
+#define LZX_ALIGNED_TABLEBITS   (7)
39
+#define LZX_LENTABLE_SAFETY (64)  /* table decoding overruns are allowed */
40
+
41
+#define LZX_FRAME_SIZE (32768) /* the size of a frame in LZX */
42
+
43
+struct lzxd_stream {
44
+  struct mspack_system *sys;      /* I/O routines                            */
45
+  struct mspack_file   *input;    /* input file handle                       */
46
+  struct mspack_file   *output;   /* output file handle                      */
47
+
48
+  off_t   offset;                 /* number of bytes actually output         */
49
+  off_t   length;                 /* overall decompressed length of stream   */
50
+
51
+  unsigned char *window;          /* decoding window                         */
52
+  unsigned int   window_size;     /* window size                             */
53
+  unsigned int   window_posn;     /* decompression offset within window      */
54
+  unsigned int   frame_posn;      /* current frame offset within in window   */
55
+  unsigned int   frame;           /* the number of 32kb frames processed     */
56
+  unsigned int   reset_interval;  /* which frame do we reset the compressor? */
57
+
58
+  unsigned int   R0, R1, R2;      /* for the LRU offset system               */
59
+  unsigned int   block_length;    /* uncompressed length of this LZX block   */
60
+  unsigned int   block_remaining; /* uncompressed bytes still left to decode */
61
+
62
+  signed int     intel_filesize;  /* magic header value used for transform   */
63
+  signed int     intel_curpos;    /* current offset in transform space       */
64
+
65
+  unsigned char  intel_started;   /* has intel E8 decoding started?          */
66
+  unsigned char  block_type;      /* type of the current block               */
67
+  unsigned char  header_read;     /* have we started decoding at all yet?    */
68
+  unsigned char  posn_slots;      /* how many posn slots in stream?          */
69
+  unsigned char  input_end;       /* have we reached the end of input?       */
70
+
71
+  int error;
72
+
73
+  /* I/O buffering */
74
+  unsigned char *inbuf, *i_ptr, *i_end, *o_ptr, *o_end;
75
+  unsigned int  bit_buffer, bits_left, inbuf_size;
76
+
77
+  /* huffman code lengths */
78
+  unsigned char PRETREE_len  [LZX_PRETREE_MAXSYMBOLS  + LZX_LENTABLE_SAFETY];
79
+  unsigned char MAINTREE_len [LZX_MAINTREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
80
+  unsigned char LENGTH_len   [LZX_LENGTH_MAXSYMBOLS   + LZX_LENTABLE_SAFETY];
81
+  unsigned char ALIGNED_len  [LZX_ALIGNED_MAXSYMBOLS  + LZX_LENTABLE_SAFETY];
82
+
83
+  /* huffman decoding tables */
84
+  unsigned short PRETREE_table [(1 << LZX_PRETREE_TABLEBITS) +
85
+				(LZX_PRETREE_MAXSYMBOLS * 2)];
86
+  unsigned short MAINTREE_table[(1 << LZX_MAINTREE_TABLEBITS) +
87
+				(LZX_MAINTREE_MAXSYMBOLS * 2)];
88
+  unsigned short LENGTH_table  [(1 << LZX_LENGTH_TABLEBITS) +
89
+				(LZX_LENGTH_MAXSYMBOLS * 2)];
90
+  unsigned short ALIGNED_table [(1 << LZX_ALIGNED_TABLEBITS) +
91
+				(LZX_ALIGNED_MAXSYMBOLS * 2)];
92
+
93
+  /* this is used purely for doing the intel E8 transform */
94
+  unsigned char  e8_buf[LZX_FRAME_SIZE];
95
+};
96
+
97
+/* allocates LZX decompression state for decoding the given stream.
98
+ *
99
+ * - returns NULL if window_bits is outwith the range 15 to 21 (inclusive).
100
+ *
101
+ * - uses system->alloc() to allocate memory
102
+ *
103
+ * - returns NULL if not enough memory
104
+ *
105
+ * - window_bits is the size of the LZX window, from 32Kb (15) to 2Mb (21).
106
+ *
107
+ * - reset_interval is how often the bitstream is reset, measured in
108
+ *   multiples of 32Kb bytes output. For CAB LZX streams, this is always 0
109
+ *   (does not occur).
110
+ *
111
+ * - input_buffer_size is how many bytes to use as an input bitstream buffer
112
+ *
113
+ * - output_length is the length in bytes of the entirely decompressed
114
+ *   output stream, if known in advance. It is used to correctly perform
115
+ *   the Intel E8 transformation, which must stop 6 bytes before the very
116
+ *   end of the decompressed stream. It is not otherwise used or adhered
117
+ *   to. If the full decompressed length is known in advance, set it here.
118
+ *   If it is NOT known, use the value 0, and call lzxd_set_output_length()
119
+ *   once it is known. If never set, 4 of the final 6 bytes of the output
120
+ *   stream may be incorrect.
121
+ */
122
+extern struct lzxd_stream *lzxd_init(struct mspack_system *system,
123
+				     struct mspack_file *input,
124
+				     struct mspack_file *output,
125
+				     int window_bits,
126
+				     int reset_interval,
127
+				     int input_buffer_size,
128
+				     off_t output_length);
129
+
130
+/* see description of output_length in lzxd_init() */
131
+extern void lzxd_set_output_length(struct lzxd_stream *lzx,
132
+				   off_t output_length);
133
+
134
+/* decompresses, or decompresses more of, an LZX stream.
135
+ *
136
+ * - out_bytes of data will be decompressed and the function will return
137
+ *   with an MSPACK_ERR_OK return code.
138
+ *
139
+ * - decompressing will stop as soon as out_bytes is reached. if the true
140
+ *   amount of bytes decoded spills over that amount, they will be kept for
141
+ *   a later invocation of lzxd_decompress().
142
+ *
143
+ * - the output bytes will be passed to the system->write() function given in
144
+ *   lzxd_init(), using the output file handle given in lzxd_init(). More
145
+ *   than one call may be made to system->write().
146
+ *
147
+ * - LZX will read input bytes as necessary using the system->read() function
148
+ *   given in lzxd_init(), using the input file handle given in lzxd_init().
149
+ *   This will continue until system->read() returns 0 bytes, or an error.
150
+ *   input streams should convey an "end of input stream" by refusing to
151
+ *   supply all the bytes that LZX asks for when they reach the end of the
152
+ *   stream, rather than return an error code.
153
+ *
154
+ * - if an error code other than MSPACK_ERR_OK is returned, the stream should
155
+ *   be considered unusable and lzxd_decompress() should not be called again
156
+ *   on this stream.
157
+ */
158
+extern int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes);
159
+
160
+/* frees all state associated with an LZX data stream
161
+ *
162
+ * - calls system->free() using the system pointer given in lzxd_init()
163
+ */
164
+void lzxd_free(struct lzxd_stream *lzx);
165
+
166
+#endif
0 167
new file mode 100644
... ...
@@ -0,0 +1,901 @@
0
+/* This file is part of libmspack.
1
+ * (C) 2003-2004 Stuart Caie.
2
+ *
3
+ * The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
4
+ * by Microsoft Corporation.
5
+ *
6
+ * libmspack is free software; you can redistribute it and/or modify it under
7
+ * the terms of the GNU Lesser General Public License (LGPL) version 2.1
8
+ *
9
+ * For further details, see the file COPYING.LIB distributed with libmspack
10
+ */
11
+
12
+/* LZX decompression implementation */
13
+
14
+#if HAVE_CONFIG_H
15
+#include "clamav-config.h"
16
+#endif
17
+
18
+#include <mspack.h>
19
+#include <system.h>
20
+#include <lzx.h>
21
+
22
+/* Microsoft's LZX document and their implementation of the
23
+ * com.ms.util.cab Java package do not concur.
24
+ *
25
+ * In the LZX document, there is a table showing the correlation between
26
+ * window size and the number of position slots. It states that the 1MB
27
+ * window = 40 slots and the 2MB window = 42 slots. In the implementation,
28
+ * 1MB = 42 slots, 2MB = 50 slots. The actual calculation is 'find the
29
+ * first slot whose position base is equal to or more than the required
30
+ * window size'. This would explain why other tables in the document refer
31
+ * to 50 slots rather than 42.
32
+ *
33
+ * The constant NUM_PRIMARY_LENGTHS used in the decompression pseudocode
34
+ * is not defined in the specification.
35
+ *
36
+ * The LZX document does not state the uncompressed block has an
37
+ * uncompressed length field. Where does this length field come from, so
38
+ * we can know how large the block is? The implementation has it as the 24
39
+ * bits following after the 3 blocktype bits, before the alignment
40
+ * padding.
41
+ *
42
+ * The LZX document states that aligned offset blocks have their aligned
43
+ * offset huffman tree AFTER the main and length trees. The implementation
44
+ * suggests that the aligned offset tree is BEFORE the main and length
45
+ * trees.
46
+ *
47
+ * The LZX document decoding algorithm states that, in an aligned offset
48
+ * block, if an extra_bits value is 1, 2 or 3, then that number of bits
49
+ * should be read and the result added to the match offset. This is
50
+ * correct for 1 and 2, but not 3, where just a huffman symbol (using the
51
+ * aligned tree) should be read.
52
+ *
53
+ * Regarding the E8 preprocessing, the LZX document states 'No translation
54
+ * may be performed on the last 6 bytes of the input block'. This is
55
+ * correct.  However, the pseudocode provided checks for the *E8 leader*
56
+ * up to the last 6 bytes. If the leader appears between -10 and -7 bytes
57
+ * from the end, this would cause the next four bytes to be modified, at
58
+ * least one of which would be in the last 6 bytes, which is not allowed
59
+ * according to the spec.
60
+ *
61
+ * The specification states that the huffman trees must always contain at
62
+ * least one element. However, many CAB files contain blocks where the
63
+ * length tree is completely empty (because there are no matches), and
64
+ * this is expected to succeed.
65
+ */
66
+
67
+
68
+/* LZX decompressor input macros
69
+ *
70
+ * STORE_BITS        stores bitstream state in lzxd_stream structure
71
+ * RESTORE_BITS      restores bitstream state from lzxd_stream structure
72
+ * READ_BITS(var,n)  takes N bits from the buffer and puts them in var
73
+ * ENSURE_BITS(n)    ensures there are at least N bits in the bit buffer.
74
+ * PEEK_BITS(n)      extracts without removing N bits from the bit buffer
75
+ * REMOVE_BITS(n)    removes N bits from the bit buffer
76
+ *
77
+ * These bit access routines work by using the area beyond the MSB and the
78
+ * LSB as a free source of zeroes when shifting. This avoids having to
79
+ * mask any bits. So we have to know the bit width of the bit buffer
80
+ * variable.
81
+ *
82
+ * The bit buffer datatype should be at least 32 bits wide: it must be
83
+ * possible to ENSURE_BITS(16), so it must be possible to add 16 new bits
84
+ * to the bit buffer when the bit buffer already has 1 to 15 bits left.
85
+ */
86
+
87
+#if HAVE_LIMITS_H
88
+# include <limits.h>
89
+#endif
90
+#ifndef CHAR_BIT
91
+# define CHAR_BIT (8)
92
+#endif
93
+#define BITBUF_WIDTH (sizeof(bit_buffer) * CHAR_BIT)
94
+
95
+#define STORE_BITS do {                                                 \
96
+  lzx->i_ptr      = i_ptr;                                              \
97
+  lzx->i_end      = i_end;                                              \
98
+  lzx->bit_buffer = bit_buffer;                                         \
99
+  lzx->bits_left  = bits_left;                                          \
100
+} while (0)
101
+
102
+#define RESTORE_BITS do {                                               \
103
+  i_ptr      = lzx->i_ptr;                                              \
104
+  i_end      = lzx->i_end;                                              \
105
+  bit_buffer = lzx->bit_buffer;                                         \
106
+  bits_left  = lzx->bits_left;                                          \
107
+} while (0)
108
+
109
+#define ENSURE_BITS(nbits)                                              \
110
+  while (bits_left < (nbits)) {                                         \
111
+    if (i_ptr >= i_end) {                                               \
112
+      if (lzxd_read_input(lzx)) return lzx->error;                      \
113
+      i_ptr = lzx->i_ptr;                                               \
114
+      i_end = lzx->i_end;                                               \
115
+    }                                                                   \
116
+    bit_buffer |= ((i_ptr[1] << 8) | i_ptr[0])                          \
117
+                  << (BITBUF_WIDTH - 16 - bits_left);                   \
118
+    bits_left  += 16;                                                   \
119
+    i_ptr      += 2;                                                    \
120
+  }
121
+
122
+#define PEEK_BITS(nbits) (bit_buffer >> (BITBUF_WIDTH - (nbits)))
123
+
124
+#define REMOVE_BITS(nbits) ((bit_buffer <<= (nbits)), (bits_left -= (nbits)))
125
+
126
+#define READ_BITS(val, nbits) do {                                      \
127
+  ENSURE_BITS(nbits);                                                   \
128
+  (val) = PEEK_BITS(nbits);                                             \
129
+  REMOVE_BITS(nbits);                                                   \
130
+} while (0)
131
+
132
+static int lzxd_read_input(struct lzxd_stream *lzx) {
133
+  int read = lzx->sys->read(lzx->input, &lzx->inbuf[0], (int)lzx->inbuf_size);
134
+  if (read < 0) return lzx->error = MSPACK_ERR_READ;
135
+
136
+  /* huff decode's ENSURE_BYTES(16) might overrun the input stream, even
137
+   * if those bits aren't used, so fake 2 more bytes */
138
+  if (read == 0) {
139
+    if (lzx->input_end) {
140
+      D(("out of input bytes"))
141
+      return lzx->error = MSPACK_ERR_READ;
142
+    }
143
+    else {
144
+      read = 2;
145
+      lzx->inbuf[0] = lzx->inbuf[1] = 0;
146
+      lzx->input_end = 1;
147
+    }
148
+  }
149
+
150
+  lzx->i_ptr = &lzx->inbuf[0];
151
+  lzx->i_end = &lzx->inbuf[read];
152
+
153
+  return MSPACK_ERR_OK;
154
+}
155
+
156
+/* Huffman decoding macros */
157
+
158
+/* READ_HUFFSYM(tablename, var) decodes one huffman symbol from the
159
+ * bitstream using the stated table and puts it in var.
160
+ */
161
+#define READ_HUFFSYM(tbl, var) do {                                     \
162
+  /* huffman symbols can be up to 16 bits long */                       \
163
+  ENSURE_BITS(16);                                                      \
164
+  /* immediate table lookup of [tablebits] bits of the code */          \
165
+  sym = lzx->tbl##_table[PEEK_BITS(LZX_##tbl##_TABLEBITS)];             \
166
+  /* is the symbol is longer than [tablebits] bits? (i=node index) */   \
167
+  if (sym >= LZX_##tbl##_MAXSYMBOLS) {                                  \
168
+    /* decode remaining bits by tree traversal */                       \
169
+    i = 1 << (BITBUF_WIDTH - LZX_##tbl##_TABLEBITS);                    \
170
+    do {                                                                \
171
+      /* one less bit. error if we run out of bits before decode */     \
172
+      i >>= 1;                                                          \
173
+      if (i == 0) {                                                     \
174
+        D(("out of bits in huffman decode"))                            \
175
+        return lzx->error = MSPACK_ERR_DECRUNCH;                        \
176
+      }                                                                 \
177
+      /* double node index and add 0 (left branch) or 1 (right) */      \
178
+      sym <<= 1; sym |= (bit_buffer & i) ? 1 : 0;                       \
179
+      /* hop to next node index / decoded symbol */                     \
180
+      sym = lzx->tbl##_table[sym];                                      \
181
+      /* while we are still in node indicies, not decoded symbols */    \
182
+    } while (sym >= LZX_##tbl##_MAXSYMBOLS);                            \
183
+  }                                                                     \
184
+  /* result */                                                          \
185
+  (var) = sym;                                                          \
186
+  /* look up the code length of that symbol and discard those bits */   \
187
+  i = lzx->tbl##_len[sym];                                              \
188
+  REMOVE_BITS(i);                                                       \
189
+} while (0)
190
+
191
+/* BUILD_TABLE(tbl) builds a huffman lookup table from code lengths */
192
+#define BUILD_TABLE(tbl)                                                \
193
+  if (make_decode_table(LZX_##tbl##_MAXSYMBOLS, LZX_##tbl##_TABLEBITS,  \
194
+			&lzx->tbl##_len[0], &lzx->tbl##_table[0]))      \
195
+  {                                                                     \
196
+    D(("failed to build %s table", #tbl))                               \
197
+    return lzx->error = MSPACK_ERR_DECRUNCH;                            \
198
+  }
199
+
200
+/* make_decode_table(nsyms, nbits, length[], table[])
201
+ *
202
+ * This function was coded by David Tritscher. It builds a fast huffman
203
+ * decoding table from a canonical huffman code lengths table.
204
+ *
205
+ * nsyms  = total number of symbols in this huffman tree.
206
+ * nbits  = any symbols with a code length of nbits or less can be decoded
207
+ *          in one lookup of the table.
208
+ * length = A table to get code lengths from [0 to syms-1]
209
+ * table  = The table to fill up with decoded symbols and pointers.
210
+ *
211
+ * Returns 0 for OK or 1 for error
212
+ */
213
+
214
+static int make_decode_table(unsigned int nsyms, unsigned int nbits,
215
+			     unsigned char *length, unsigned short *table)
216
+{
217
+  register unsigned short sym;
218
+  register unsigned int leaf, fill;
219
+  register unsigned char bit_num;
220
+  unsigned int pos         = 0; /* the current position in the decode table */
221
+  unsigned int table_mask  = 1 << nbits;
222
+  unsigned int bit_mask    = table_mask >> 1; /* don't do 0 length codes */
223
+  unsigned int next_symbol = bit_mask; /* base of allocation for long codes */
224
+
225
+  /* fill entries for codes short enough for a direct mapping */
226
+  for (bit_num = 1; bit_num <= nbits; bit_num++) {
227
+    for (sym = 0; sym < nsyms; sym++) {
228
+      if (length[sym] != bit_num) continue;
229
+      leaf = pos;
230
+      if((pos += bit_mask) > table_mask) return 1; /* table overrun */
231
+      /* fill all possible lookups of this symbol with the symbol itself */
232
+      for (fill = bit_mask; fill-- > 0;) table[leaf++] = sym;
233
+    }
234
+    bit_mask >>= 1;
235
+  }
236
+
237
+  /* full table already? */
238
+  if (pos == table_mask) return 0;
239
+
240
+  /* clear the remainder of the table */
241
+  for (sym = pos; sym < table_mask; sym++) table[sym] = 0xFFFF;
242
+
243
+  /* allow codes to be up to nbits+16 long, instead of nbits */
244
+  pos <<= 16;
245
+  table_mask <<= 16;
246
+  bit_mask = 1 << 15;
247
+
248
+  for (bit_num = nbits+1; bit_num <= 16; bit_num++) {
249
+    for (sym = 0; sym < nsyms; sym++) {
250
+      if (length[sym] != bit_num) continue;
251
+
252
+      leaf = pos >> 16;
253
+      for (fill = 0; fill < bit_num - nbits; fill++) {
254
+	/* if this path hasn't been taken yet, 'allocate' two entries */
255
+	if (table[leaf] == 0xFFFF) {
256
+	  table[(next_symbol << 1)] = 0xFFFF;
257
+	  table[(next_symbol << 1) + 1] = 0xFFFF;
258
+	  table[leaf] = next_symbol++;
259
+	}
260
+	/* follow the path and select either left or right for next bit */
261
+	leaf = table[leaf] << 1;
262
+	if ((pos >> (15-fill)) & 1) leaf++;
263
+      }
264
+      table[leaf] = sym;
265
+
266
+      if ((pos += bit_mask) > table_mask) return 1; /* table overflow */
267
+    }
268
+    bit_mask >>= 1;
269
+  }
270
+
271
+  /* full table? */
272
+  if (pos == table_mask) return 0;
273
+
274
+  /* either erroneous table, or all elements are 0 - let's find out. */
275
+  for (sym = 0; sym < nsyms; sym++) if (length[sym]) return 1;
276
+  return 0;
277
+}
278
+
279
+
280
+/* READ_LENGTHS(tablename, first, last) reads in code lengths for symbols
281
+ * first to last in the given table. The code lengths are stored in their
282
+ * own special LZX way.
283
+ */
284
+#define READ_LENGTHS(tbl, first, last) do {                            \
285
+  STORE_BITS;                                                          \
286
+  if (lzxd_read_lens(lzx, &lzx->tbl##_len[0], (first),                 \
287
+    (unsigned int)(last))) return lzx->error;                          \
288
+  RESTORE_BITS;                                                        \
289
+} while (0)
290
+
291
+static int lzxd_read_lens(struct lzxd_stream *lzx, unsigned char *lens,
292
+			  unsigned int first, unsigned int last)
293
+{
294
+  /* bit buffer and huffman symbol decode variables */
295
+  register unsigned int bit_buffer;
296
+  register int bits_left, i;
297
+  register unsigned short sym;
298
+  unsigned char *i_ptr, *i_end;
299
+
300
+  unsigned int x, y;
301
+  int z;
302
+
303
+  RESTORE_BITS;
304
+  
305
+  /* read lengths for pretree (20 symbols, lengths stored in fixed 4 bits) */
306
+  for (x = 0; x < 20; x++) {
307
+    READ_BITS(y, 4);
308
+    lzx->PRETREE_len[x] = y;
309
+  }
310
+  BUILD_TABLE(PRETREE);
311
+
312
+  for (x = first; x < last; ) {
313
+    READ_HUFFSYM(PRETREE, z);
314
+    if (z == 17) {
315
+      /* code = 17, run of ([read 4 bits]+4) zeros */
316
+      READ_BITS(y, 4); y += 4;
317
+      while (y--) lens[x++] = 0;
318
+    }
319
+    else if (z == 18) {
320
+      /* code = 18, run of ([read 5 bits]+20) zeros */
321
+      READ_BITS(y, 5); y += 20;
322
+      while (y--) lens[x++] = 0;
323
+    }
324
+    else if (z == 19) {
325
+      /* code = 19, run of ([read 1 bit]+4) [read huffman symbol] */
326
+      READ_BITS(y, 1); y += 4;
327
+      READ_HUFFSYM(PRETREE, z);
328
+      z = lens[x] - z; if (z < 0) z += 17;
329
+      while (y--) lens[x++] = z;
330
+    }
331
+    else {
332
+      /* code = 0 to 16, delta current length entry */
333
+      z = lens[x] - z; if (z < 0) z += 17;
334
+      lens[x++] = z;
335
+    }
336
+  }
337
+
338
+  STORE_BITS;
339
+
340
+  return MSPACK_ERR_OK;
341
+}
342
+
343
+/* LZX static data tables:
344
+ *
345
+ * LZX uses 'position slots' to represent match offsets.  For every match,
346
+ * a small 'position slot' number and a small offset from that slot are
347
+ * encoded instead of one large offset.
348
+ *
349
+ * position_base[] is an index to the position slot bases
350
+ *
351
+ * extra_bits[] states how many bits of offset-from-base data is needed.
352
+ */
353
+static unsigned int  position_base[51];
354
+static unsigned char extra_bits[51];
355
+
356
+static void lzxd_static_init() {
357
+  int i, j;
358
+
359
+  for (i = 0, j = 0; i < 51; i += 2) {
360
+    extra_bits[i]   = j; /* 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7... */
361
+    extra_bits[i+1] = j;
362
+    if ((i != 0) && (j < 17)) j++; /* 0,0,1,2,3,4...15,16,17,17,17,17... */
363
+  }
364
+
365
+  for (i = 0, j = 0; i < 51; i++) {
366
+    position_base[i] = j; /* 0,1,2,3,4,6,8,12,16,24,32,... */
367
+    j += 1 << extra_bits[i]; /* 1,1,1,1,2,2,4,4,8,8,16,16,32,32,... */
368
+  }
369
+}
370
+
371
+static void lzxd_reset_state(struct lzxd_stream *lzx) {
372
+  int i;
373
+
374
+  lzx->R0              = 1;
375
+  lzx->R1              = 1;
376
+  lzx->R2              = 1;
377
+  lzx->header_read     = 0;
378
+  lzx->block_remaining = 0;
379
+  lzx->block_type      = LZX_BLOCKTYPE_INVALID;
380
+
381
+  /* initialise tables to 0 (because deltas will be applied to them) */
382
+  for (i = 0; i < LZX_MAINTREE_MAXSYMBOLS; i++) lzx->MAINTREE_len[i] = 0;
383
+  for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++)   lzx->LENGTH_len[i]   = 0;
384
+}
385
+
386
+/*-------- main LZX code --------*/
387
+
388
+struct lzxd_stream *lzxd_init(struct mspack_system *system,
389
+			      struct mspack_file *input,
390
+			      struct mspack_file *output,
391
+			      int window_bits,
392
+			      int reset_interval,
393
+			      int input_buffer_size,
394
+			      off_t output_length)
395
+{
396
+  unsigned int window_size = 1 << window_bits;
397
+  struct lzxd_stream *lzx;
398
+
399
+  if (!system) return NULL;
400
+
401
+  /* LZX supports window sizes of 2^15 (32Kb) through 2^21 (2Mb) */
402
+  if (window_bits < 15 || window_bits > 21) return NULL;
403
+
404
+  input_buffer_size = (input_buffer_size + 1) & -2;
405
+  if (!input_buffer_size) return NULL;
406
+
407
+  /* initialise static data */
408
+  lzxd_static_init();
409
+
410
+  /* allocate decompression state */
411
+  if (!(lzx = system->alloc(system, sizeof(struct lzxd_stream)))) {
412
+    return NULL;
413
+  }
414
+
415
+  /* allocate decompression window and input buffer */
416
+  lzx->window = system->alloc(system, (size_t) window_size);
417
+  lzx->inbuf  = system->alloc(system, (size_t) input_buffer_size);
418
+  if (!lzx->window || !lzx->inbuf) {
419
+    system->free(lzx->window);
420
+    system->free(lzx->inbuf);
421
+    system->free(lzx);
422
+    return NULL;
423
+  }
424
+
425
+  /* initialise decompression state */
426
+  lzx->sys             = system;
427
+  lzx->input           = input;
428
+  lzx->output          = output;
429
+  lzx->offset          = 0;
430
+  lzx->length          = output_length;
431
+
432
+  lzx->inbuf_size      = input_buffer_size;
433
+  lzx->window_size     = 1 << window_bits;
434
+  lzx->window_posn     = 0;
435
+  lzx->frame_posn      = 0;
436
+  lzx->frame           = 0;
437
+  lzx->reset_interval  = reset_interval;
438
+  lzx->intel_filesize  = 0;
439
+  lzx->intel_curpos    = 0;
440
+
441
+  /* window bits:    15  16  17  18  19  20  21
442
+   * position slots: 30  32  34  36  38  42  50  */
443
+  lzx->posn_slots      = ((window_bits == 21) ? 50 :
444
+			  ((window_bits == 20) ? 42 : (window_bits << 1)));
445
+  lzx->intel_started   = 0;
446
+  lzx->input_end       = 0;
447
+
448
+  lzx->error = MSPACK_ERR_OK;
449
+
450
+  lzx->i_ptr = lzx->i_end = &lzx->inbuf[0];
451
+  lzx->o_ptr = lzx->o_end = &lzx->e8_buf[0];
452
+  lzx->bit_buffer = lzx->bits_left = 0;
453
+
454
+  lzxd_reset_state(lzx);
455
+  return lzx;
456
+}
457
+
458
+void lzxd_set_output_length(struct lzxd_stream *lzx, off_t out_bytes) {
459
+  if (lzx) lzx->length = out_bytes;
460
+}
461
+
462
+int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
463
+  /* bitstream reading and huffman variables */
464
+  register unsigned int bit_buffer;
465
+  register int bits_left, i=0;
466
+  register unsigned short sym;
467
+  unsigned char *i_ptr, *i_end;
468
+
469
+  int match_length, length_footer, extra, verbatim_bits, bytes_todo;
470
+  int this_run, main_element, aligned_bits, j;
471
+  unsigned char *window, *runsrc, *rundest, buf[12];
472
+  unsigned int frame_size=0, end_frame, match_offset, window_posn;
473
+  unsigned int R0, R1, R2;
474
+
475
+  /* easy answers */
476
+  if (!lzx || (out_bytes < 0)) return MSPACK_ERR_ARGS;
477
+  if (lzx->error) return lzx->error;
478
+
479
+  /* flush out any stored-up bytes before we begin */
480
+  i = lzx->o_end - lzx->o_ptr;
481
+  if ((off_t) i > out_bytes) i = (int) out_bytes;
482
+  if (i) {
483
+    if (lzx->sys->write(lzx->output, lzx->o_ptr, i) != i) {
484
+      return lzx->error = MSPACK_ERR_WRITE;
485
+    }
486
+    lzx->o_ptr  += i;
487
+    lzx->offset += i;
488
+    out_bytes   -= i;
489
+  }
490
+  if (out_bytes == 0) return MSPACK_ERR_OK;
491
+
492
+  /* restore local state */
493
+  RESTORE_BITS;
494
+  window = lzx->window;
495
+  window_posn = lzx->window_posn;
496
+  R0 = lzx->R0;
497
+  R1 = lzx->R1;
498
+  R2 = lzx->R2;
499
+
500
+  end_frame = (unsigned int)((lzx->offset + out_bytes) / LZX_FRAME_SIZE) + 1;
501
+
502
+  while (lzx->frame < end_frame) {
503
+    /* have we reached the reset interval? (if there is one?) */
504
+    if (lzx->reset_interval && ((lzx->frame % lzx->reset_interval) == 0)) {
505
+      if (lzx->block_remaining) {
506
+	D(("%d bytes remaining at reset interval", lzx->block_remaining))
507
+	return lzx->error = MSPACK_ERR_DECRUNCH;
508
+      }
509
+
510
+      /* re-read the intel header and reset the huffman lengths */
511
+      lzxd_reset_state(lzx);
512
+    }
513
+
514
+    /* read header if necessary */
515
+    if (!lzx->header_read) {
516
+      /* read 1 bit. if bit=0, intel filesize = 0.
517
+       * if bit=1, read intel filesize (32 bits) */
518
+      j = 0; READ_BITS(i, 1); if (i) { READ_BITS(i, 16); READ_BITS(j, 16); }
519
+      lzx->intel_filesize = (i << 16) | j;
520
+      lzx->header_read = 1;
521
+    } 
522
+
523
+    /* calculate size of frame: all frames are 32k except the final frame
524
+     * which is 32kb or less. this can only be calculated when lzx->length
525
+     * has been filled in. */
526
+    frame_size = LZX_FRAME_SIZE;
527
+    if (lzx->length && (lzx->length - lzx->offset) < (off_t)frame_size) {
528
+      frame_size = lzx->length - lzx->offset;
529
+    }
530
+
531
+    /* decode until one more frame is available */
532
+    bytes_todo = lzx->frame_posn + frame_size - window_posn;
533
+    while (bytes_todo > 0) {
534
+      /* initialise new block, if one is needed */
535
+      if (lzx->block_remaining == 0) {
536
+	/* realign if previous block was an odd-sized UNCOMPRESSED block */
537
+	if ((lzx->block_type == LZX_BLOCKTYPE_UNCOMPRESSED) &&
538
+	    (lzx->block_length & 1))
539
+	{
540
+	  if (i_ptr == i_end) {
541
+	    if (lzxd_read_input(lzx)) return lzx->error;
542
+	    i_ptr = lzx->i_ptr;
543
+	    i_end = lzx->i_end;
544
+	  }
545
+	  i_ptr++;
546
+	}
547
+
548
+	/* read block type (3 bits) and block length (24 bits) */
549
+	READ_BITS(lzx->block_type, 3);
550
+	READ_BITS(i, 16); READ_BITS(j, 8);
551
+	lzx->block_remaining = lzx->block_length = (i << 8) | j;
552
+	/*D(("new block t%d len %u", lzx->block_type, lzx->block_length))*/
553
+
554
+	/* read individual block headers */
555
+	switch (lzx->block_type) {
556
+	case LZX_BLOCKTYPE_ALIGNED:
557
+	  /* read lengths of and build aligned huffman decoding tree */
558
+	  for (i = 0; i < 8; i++) { READ_BITS(j, 3); lzx->ALIGNED_len[i] = j; }
559
+	  BUILD_TABLE(ALIGNED);
560
+	  /* no break -- rest of aligned header is same as verbatim */
561
+	case LZX_BLOCKTYPE_VERBATIM:
562
+	  /* read lengths of and build main huffman decoding tree */
563
+	  READ_LENGTHS(MAINTREE, 0, 256);
564
+	  READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + (lzx->posn_slots << 3));
565
+	  BUILD_TABLE(MAINTREE);
566
+	  /* if the literal 0xE8 is anywhere in the block... */
567
+	  if (lzx->MAINTREE_len[0xE8] != 0) lzx->intel_started = 1;
568
+	  /* read lengths of and build lengths huffman decoding tree */
569
+	  READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS);
570
+	  BUILD_TABLE(LENGTH);
571
+	  break;
572
+
573
+	case LZX_BLOCKTYPE_UNCOMPRESSED:
574
+	  /* because we can't assume otherwise */
575
+	  lzx->intel_started = 1;
576
+
577
+	  /* read 1-16 (not 0-15) bits to align to bytes */
578
+	  ENSURE_BITS(16);
579
+	  if (bits_left > 16) i_ptr -= 2;
580
+	  bits_left = 0; bit_buffer = 0;
581
+
582
+	  /* read 12 bytes of stored R0 / R1 / R2 values */
583
+	  for (rundest = &buf[0], i = 0; i < 12; i++) {
584
+	    if (i_ptr == i_end) {
585
+	      if (lzxd_read_input(lzx)) return lzx->error;
586
+	      i_ptr = lzx->i_ptr;
587
+	      i_end = lzx->i_end;
588
+	    }
589
+	    *rundest++ = *i_ptr++;
590
+	  }
591
+	  R0 = buf[0] | (buf[1] << 8) | (buf[2]  << 16) | (buf[3]  << 24);
592
+	  R1 = buf[4] | (buf[5] << 8) | (buf[6]  << 16) | (buf[7]  << 24);
593
+	  R2 = buf[8] | (buf[9] << 8) | (buf[10] << 16) | (buf[11] << 24);
594
+	  break;
595
+
596
+	default:
597
+	  D(("bad block type"))
598
+	  return lzx->error = MSPACK_ERR_DECRUNCH;
599
+	}
600
+      }
601
+
602
+      /* decode more of the block:
603
+       * run = min(what's available, what's needed) */
604
+      this_run = lzx->block_remaining;
605
+      if (this_run > bytes_todo) this_run = bytes_todo;
606
+
607
+      /* assume we decode exactly this_run bytes, for now */
608
+      bytes_todo           -= this_run;
609
+      lzx->block_remaining -= this_run;
610
+
611
+      /* decode at least this_run bytes */
612
+      switch (lzx->block_type) {
613
+      case LZX_BLOCKTYPE_VERBATIM:
614
+	while (this_run > 0) {
615
+	  READ_HUFFSYM(MAINTREE, main_element);
616
+	  if (main_element < LZX_NUM_CHARS) {
617
+	    /* literal: 0 to LZX_NUM_CHARS-1 */
618
+	    window[window_posn++] = main_element;
619
+	    this_run--;
620
+	  }
621
+	  else {
622
+	    /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
623
+	    main_element -= LZX_NUM_CHARS;
624
+
625
+	    /* get match length */
626
+	    match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
627
+	    if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
628
+	      READ_HUFFSYM(LENGTH, length_footer);
629
+	      match_length += length_footer;
630
+	    }
631
+	    match_length += LZX_MIN_MATCH;
632
+	  
633
+	    /* get match offset */
634
+	    switch ((match_offset = (main_element >> 3))) {
635
+	    case 0: match_offset = R0;                                  break;
636
+	    case 1: match_offset = R1; R1=R0;        R0 = match_offset; break;
637
+	    case 2: match_offset = R2; R2=R0;        R0 = match_offset; break;
638
+	    case 3: match_offset = 1;  R2=R1; R1=R0; R0 = match_offset; break;
639
+	    default:
640
+	      extra = extra_bits[match_offset];
641
+	      READ_BITS(verbatim_bits, extra);
642
+	      match_offset = position_base[match_offset] - 2 + verbatim_bits;
643
+	      R2 = R1; R1 = R0; R0 = match_offset;
644
+	    }
645
+
646
+	    if ((window_posn + match_length) > lzx->window_size) {
647
+	      D(("match ran over window wrap"))
648
+	      return lzx->error = MSPACK_ERR_DECRUNCH;
649
+	    }
650
+	    
651
+	    /* copy match */
652
+	    rundest = &window[window_posn];
653
+	    i = match_length;
654
+	    /* does match offset wrap the window? */
655
+	    if (match_offset > window_posn) {
656
+	      /* j = length from match offset to end of window */
657
+	      j = match_offset - window_posn;
658
+	      if (j > (int) lzx->window_size) {
659
+		D(("match offset beyond window boundaries"))
660
+		return lzx->error = MSPACK_ERR_DECRUNCH;
661
+	      }
662
+	      runsrc = &window[lzx->window_size - j];
663
+	      if (j < i) {
664
+		/* if match goes over the window edge, do two copy runs */
665
+		i -= j; while (j-- > 0) *rundest++ = *runsrc++;
666
+		runsrc = window;
667
+	      }
668
+	      while (i-- > 0) *rundest++ = *runsrc++;
669
+	    }
670
+	    else {
671
+	      runsrc = rundest - match_offset;
672
+	      while (i-- > 0) *rundest++ = *runsrc++;
673
+	    }
674
+
675
+	    this_run    -= match_length;
676
+	    window_posn += match_length;
677
+	  }
678
+	} /* while (this_run > 0) */
679
+	break;
680
+
681
+      case LZX_BLOCKTYPE_ALIGNED:
682
+	while (this_run > 0) {
683
+	  READ_HUFFSYM(MAINTREE, main_element);
684
+	  if (main_element < LZX_NUM_CHARS) {
685
+	    /* literal: 0 to LZX_NUM_CHARS-1 */
686
+	    window[window_posn++] = main_element;
687
+	    this_run--;
688
+	  }
689
+	  else {
690
+	    /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
691
+	    main_element -= LZX_NUM_CHARS;
692
+
693
+	    /* get match length */
694
+	    match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
695
+	    if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
696
+	      READ_HUFFSYM(LENGTH, length_footer);
697
+	      match_length += length_footer;
698
+	    }
699
+	    match_length += LZX_MIN_MATCH;
700
+
701
+	    /* get match offset */
702
+	    switch ((match_offset = (main_element >> 3))) {
703
+	    case 0: match_offset = R0;                             break;
704
+	    case 1: match_offset = R1; R1 = R0; R0 = match_offset; break;
705
+	    case 2: match_offset = R2; R2 = R0; R0 = match_offset; break;
706
+	    default:
707
+	      extra = extra_bits[match_offset];
708
+	      match_offset = position_base[match_offset] - 2;
709
+	      if (extra > 3) {
710
+		/* verbatim and aligned bits */
711
+		extra -= 3;
712
+		READ_BITS(verbatim_bits, extra);
713
+		match_offset += (verbatim_bits << 3);
714
+		READ_HUFFSYM(ALIGNED, aligned_bits);
715
+		match_offset += aligned_bits;
716
+	      }
717
+	      else if (extra == 3) {
718
+		/* aligned bits only */
719
+		READ_HUFFSYM(ALIGNED, aligned_bits);
720
+		match_offset += aligned_bits;
721
+	      }
722
+	      else if (extra > 0) { /* extra==1, extra==2 */
723
+		/* verbatim bits only */
724
+		READ_BITS(verbatim_bits, extra);
725
+		match_offset += verbatim_bits;
726
+	      }
727
+	      else /* extra == 0 */ {
728
+		/* ??? not defined in LZX specification! */
729
+		match_offset = 1;
730
+	      }
731
+	      /* update repeated offset LRU queue */
732
+	      R2 = R1; R1 = R0; R0 = match_offset;
733
+	    }
734
+
735
+	    if ((window_posn + match_length) > lzx->window_size) {
736
+	      D(("match ran over window wrap"))
737
+	      return lzx->error = MSPACK_ERR_DECRUNCH;
738
+	    }
739
+
740
+	    /* copy match */
741
+	    rundest = &window[window_posn];
742
+	    i = match_length;
743
+	    /* does match offset wrap the window? */
744
+	    if (match_offset > window_posn) {
745
+	      /* j = length from match offset to end of window */
746
+	      j = match_offset - window_posn;
747
+	      if (j > (int) lzx->window_size) {
748
+		D(("match offset beyond window boundaries"))
749
+		return lzx->error = MSPACK_ERR_DECRUNCH;
750
+	      }
751
+	      runsrc = &window[lzx->window_size - j];
752
+	      if (j < i) {
753
+		/* if match goes over the window edge, do two copy runs */
754
+		i -= j; while (j-- > 0) *rundest++ = *runsrc++;
755
+		runsrc = window;
756
+	      }
757
+	      while (i-- > 0) *rundest++ = *runsrc++;
758
+	    }
759
+	    else {
760
+	      runsrc = rundest - match_offset;
761
+	      while (i-- > 0) *rundest++ = *runsrc++;
762
+	    }
763
+
764
+	    this_run    -= match_length;
765
+	    window_posn += match_length;
766
+	  }
767
+	} /* while (this_run > 0) */
768
+	break;
769
+
770
+      case LZX_BLOCKTYPE_UNCOMPRESSED:
771
+	/* as this_run is limited not to wrap a frame, this also means it
772
+	 * won't wrap the window (as the window is a multiple of 32k) */
773
+	rundest = &window[window_posn];
774
+	window_posn += this_run;
775
+	while (this_run > 0) {
776
+	  if ((i = i_end - i_ptr)) {
777
+	    if (i > this_run) i = this_run;
778
+	    lzx->sys->copy(i_ptr, rundest, (size_t) i);
779
+	    rundest  += i;
780
+	    i_ptr    += i;
781
+	    this_run -= i;
782
+	  }
783
+	  else {
784
+	    if (lzxd_read_input(lzx)) return lzx->error;
785
+	    i_ptr = lzx->i_ptr;
786
+	    i_end = lzx->i_end;
787
+	  }
788
+	}
789
+	break;
790
+
791
+      default:
792
+	return lzx->error = MSPACK_ERR_DECRUNCH; /* might as well */
793
+      }
794
+
795
+      /* did the final match overrun our desired this_run length? */
796
+      if (this_run < 0) {
797
+	if ((unsigned int)(-this_run) > lzx->block_remaining) {
798
+	  D(("overrun went past end of block by %d (%d remaining)",
799
+	     -this_run, lzx->block_remaining ))
800
+	  return lzx->error = MSPACK_ERR_DECRUNCH;
801
+	}
802
+	lzx->block_remaining -= -this_run;
803
+      }
804
+    } /* while (bytes_todo > 0) */
805
+
806
+    /* streams don't extend over frame boundaries */
807
+    if ((window_posn - lzx->frame_posn) != frame_size) {
808
+      D(("decode beyond output frame limits! %d != %d",
809
+	 window_posn - lzx->frame_posn, frame_size))
810
+      return lzx->error = MSPACK_ERR_DECRUNCH;
811
+    }
812
+
813
+    /* re-align input bitstream */
814
+    if (bits_left > 0) ENSURE_BITS(16);
815
+    if (bits_left & 15) REMOVE_BITS(bits_left & 15);
816
+
817
+    /* check that we've used all of the previous frame first */
818
+    if (lzx->o_ptr != lzx->o_end) {
819
+      D(("%d avail bytes, new %d frame", lzx->o_end-lzx->o_ptr, frame_size))
820
+      return lzx->error = MSPACK_ERR_DECRUNCH;
821
+    }
822
+
823
+    /* does this intel block _really_ need decoding? */
824
+    if (lzx->intel_started && lzx->intel_filesize &&
825
+	(lzx->frame <= 32768) && (frame_size > 10))
826
+    {
827
+      unsigned char *data    = &lzx->e8_buf[0];
828
+      unsigned char *dataend = &lzx->e8_buf[frame_size - 10];
829
+      signed int curpos      = lzx->intel_curpos;
830
+      signed int filesize    = lzx->intel_filesize;
831
+      signed int abs_off, rel_off;
832
+
833
+      /* copy e8 block to the e8 buffer and tweak if needed */
834
+      lzx->o_ptr = data;
835
+      lzx->sys->copy(&lzx->window[lzx->frame_posn], data, frame_size);
836
+
837
+      while (data < dataend) {
838
+	if (*data++ != 0xE8) { curpos++; continue; }
839
+	abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);
840
+	if ((abs_off >= -curpos) && (abs_off < filesize)) {
841
+	  rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize;
842
+	  data[0] = (unsigned char) rel_off;
843
+	  data[1] = (unsigned char) (rel_off >> 8);
844
+	  data[2] = (unsigned char) (rel_off >> 16);
845
+	  data[3] = (unsigned char) (rel_off >> 24);
846
+	}
847
+	data += 4;
848
+	curpos += 5;
849
+      }
850
+      lzx->intel_curpos += frame_size;
851
+    }
852
+    else {
853
+      lzx->o_ptr = &lzx->window[lzx->frame_posn];
854
+      if (lzx->intel_filesize) lzx->intel_curpos += frame_size;
855
+    }
856
+    lzx->o_end = &lzx->o_ptr[frame_size];
857
+
858
+    /* write a frame */
859
+    i = (out_bytes < (off_t)frame_size) ? (unsigned int)out_bytes : frame_size;
860
+    if (lzx->sys->write(lzx->output, lzx->o_ptr, i) != i) {
861
+      return lzx->error = MSPACK_ERR_WRITE;
862
+    }
863
+    lzx->o_ptr  += i;
864
+    lzx->offset += i;
865
+    out_bytes   -= i;
866
+
867
+    /* advance frame start position */
868
+    lzx->frame_posn += frame_size;
869
+    lzx->frame++;
870
+
871
+    /* wrap window / frame position pointers */
872
+    if (window_posn == lzx->window_size)     window_posn = 0;
873
+    if (lzx->frame_posn == lzx->window_size) lzx->frame_posn = 0;
874
+
875
+  } /* while (lzx->frame < end_frame) */
876
+
877
+  if (out_bytes) {
878
+    D(("bytes left to output"))
879
+    return lzx->error = MSPACK_ERR_DECRUNCH;
880
+  }
881
+
882
+  /* store local state */
883
+  STORE_BITS;
884
+  lzx->window_posn = window_posn;
885
+  lzx->R0 = R0;
886
+  lzx->R1 = R1;
887
+  lzx->R2 = R2;
888
+
889
+  return MSPACK_ERR_OK;
890
+}
891
+
892
+void lzxd_free(struct lzxd_stream *lzx) {
893
+  struct mspack_system *sys;
894
+  if (lzx) {
895
+    sys = lzx->sys;
896
+    sys->free(lzx->inbuf);
897
+    sys->free(lzx->window);
898
+    sys->free(lzx);
899
+  }
900
+}
0 901
new file mode 100644
... ...
@@ -0,0 +1,1494 @@
0
+/* WARNING: This version also supports dopen for descriptor opening and
1
+ *	    is not compatible with the original version. -- T. Kojm
2
+ *
3
+ * libmspack -- a library for working with Microsoft compression formats.
4
+ * (C) 2003-2004 Stuart Caie <kyzer@4u.net>
5
+ *
6
+ * libmspack is free software; you can redistribute it and/or modify it under
7
+ * the terms of the GNU Lesser General Public License (LGPL) version 2.1
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ * GNU Lesser General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU Lesser General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+/** \mainpage
20
+ *
21
+ * \section intro Introduction
22
+ *
23
+ * libmspack is a library which provides compressors and decompressors,
24
+ * archivers and dearchivers for Microsoft compression formats.
25
+ *
26
+ * \section formats Formats supported
27
+ *
28
+ * The following file formats are supported:
29
+ * - SZDD files, which use LZSS compression
30
+ * - KWAJ files, which use LZSS, LZSS+Huffman or deflate compression
31
+ * - .HLP (MS Help) files, which use LZSS compression
32
+ * - .CAB (MS Cabinet) files, which use deflate, LZX or Quantum compression
33
+ * - .CHM (HTML Help) files, which use LZX compression
34
+ * - .LIT (MS EBook) files, which use LZX compression and DES encryption
35
+ *
36
+ * To determine the capabilities of the library, and the binary
37
+ * compatibility version of any particular compressor or decompressor, use
38
+ * the mspack_version() function. The UNIX library interface version is
39
+ * defined as the highest-versioned library component.
40
+ *
41
+ * \section starting Getting started
42
+ *
43
+ * The macro MSPACK_SYS_SELFTEST() should be used to ensure the library can
44
+ * be used. In particular, it checks if the caller is using 32-bit file I/O
45
+ * when the library is compiled for 64-bit file I/O and vice versa.
46
+ *
47
+ * If compiled normally, the library includes basic file I/O and memory
48
+ * management functionality using the standard C library. This can be
49
+ * customised and replaced entirely by creating a mspack_system structure.
50
+ *
51
+ * A compressor or decompressor for the required format must be
52
+ * instantiated before it can be used. Each construction function takes
53
+ * one parameter, which is either a pointer to a custom mspack_system
54
+ * structure, or NULL to use the default. The instantiation returned, if
55
+ * not NULL, contains function pointers (methods) to work with the given
56
+ * file format.
57
+ * 
58
+ * For compression:
59
+ * - mspack_create_cab_compressor() creates a mscab_compressor
60
+ * - mspack_create_chm_compressor() creates a mschm_compressor
61
+ * - mspack_create_lit_compressor() creates a mslit_compressor
62
+ * - mspack_create_hlp_compressor() creates a mshlp_compressor
63
+ * - mspack_create_szdd_compressor() creates a msszdd_compressor
64
+ * - mspack_create_kwaj_compressor() creates a mskwaj_compressor
65
+ *
66
+ * For decompression:
67
+ * - mspack_create_cab_decompressor() creates a mscab_decompressor
68
+ * - mspack_create_chm_decompressor() creates a mschm_decompressor
69
+ * - mspack_create_lit_decompressor() creates a mslit_decompressor
70
+ * - mspack_create_hlp_decompressor() creates a mshlp_decompressor
71
+ * - mspack_create_szdd_decompressor() creates a msszdd_decompressor
72
+ * - mspack_create_kwaj_decompressor() creates a mskwaj_decompressor
73
+ *
74
+ * Once finished working with a format, each kind of
75
+ * compressor/decompressor has its own specific destructor:
76
+ * - mspack_destroy_cab_compressor()
77
+ * - mspack_destroy_cab_decompressor()
78
+ * - mspack_destroy_chm_compressor()
79
+ * - mspack_destroy_chm_decompressor()
80
+ * - mspack_destroy_lit_compressor()
81
+ * - mspack_destroy_lit_decompressor()
82
+ * - mspack_destroy_hlp_compressor()
83
+ * - mspack_destroy_hlp_decompressor()
84
+ * - mspack_destroy_szdd_compressor()
85
+ * - mspack_destroy_szdd_decompressor()
86
+ * - mspack_destroy_kwaj_compressor()
87
+ * - mspack_destroy_kwaj_decompressor()
88
+ *
89
+ * Destroying a compressor or decompressor does not destroy any objects,
90
+ * structures or handles that have been created using that compressor or
91
+ * decompressor. Ensure that everything created or opened is destroyed or
92
+ * closed before compressor/decompressor is itself destroyed.
93
+ *
94
+ * \section errors Error codes
95
+ *
96
+ * All compressors and decompressors use the same set of error codes. Most
97
+ * methods return an error code directly. For methods which do not
98
+ * return error codes directly, the error code can be obtained with the
99
+ * last_error() method.
100
+ *
101
+ * - #MSPACK_ERR_OK is used to indicate success. This error code is defined
102
+ *   as zero, all other code are non-zero.
103
+ * - #MSPACK_ERR_ARGS indicates that a method was called with inappropriate
104
+ *   arguments.
105
+ * - #MSPACK_ERR_OPEN indicates that mspack_system::open() failed.
106
+ * - #MSPACK_ERR_READ indicates that mspack_system::read() failed.
107
+ * - #MSPACK_ERR_WRITE indicates that mspack_system::write() failed.
108
+ * - #MSPACK_ERR_SEEK indicates that mspack_system::seek() failed.
109
+ * - #MSPACK_ERR_NOMEMORY indicates that mspack_system::alloc() failed.
110
+ * - #MSPACK_ERR_SIGNATURE indicates that the file being read does not
111
+ *   have the correct "signature". It is probably not a valid file for
112
+ *   whatever format is being read.
113
+ * - #MSPACK_ERR_DATAFORMAT indicates that the file being used or read
114
+ *   is corrupt.
115
+ * - #MSPACK_ERR_CHECKSUM indicates that a data checksum has failed.
116
+ * - #MSPACK_ERR_CRUNCH indicates an error occured during compression.
117
+ * - #MSPACK_ERR_DECRUNCH indicates an error occured during decompression.
118
+ */
119
+
120
+#ifndef LIB_MSPACK_H
121
+#define LIB_MSPACK_H 1
122
+
123
+#ifdef __cplusplus
124
+extern "C" {
125
+#endif
126
+
127
+#include <sys/types.h>
128
+#include <unistd.h>
129
+
130
+/**
131
+ * System self-test function, to ensure both library and calling program
132
+ * can use one another.
133
+ *
134
+ * A result of MSPACK_ERR_OK means the library and caller are
135
+ * compatible. Any other result indicates that the library and caller are
136
+ * not compatible and should not be used. In particular, a value of
137
+ * MSPACK_ERR_SEEK means the library and caller use different off_t
138
+ * datatypes.
139
+ *
140
+ * It should be used like so:
141
+ *
142
+ * @code
143
+ * int selftest_result;
144
+ * MSPACK_SYS_SELFTEST(selftest_result);
145
+ * if (selftest_result != MSPACK_ERR_OK) {
146
+ *   fprintf(stderr, "incompatible with this build of libmspack\n");
147
+ *   exit(0);
148
+ * }
149
+ * @endcode
150
+ *
151
+ * @param  result   an int variable to store the result of the self-test
152
+ */
153
+#define MSPACK_SYS_SELFTEST(result)  do { \
154
+  (result) = mspack_sys_selftest_internal(sizeof(off_t)); \
155
+} while (0)
156
+
157
+/** Part of the MSPACK_SYS_SELFTEST() macro, must not be used directly. */
158
+extern int mspack_sys_selftest_internal(int);
159
+
160
+/**
161
+ * Enquire about the binary compatibility version of a specific interface in
162
+ * the library. Currently, the following interfaces are defined:
163
+ *
164
+ * - #MSPACK_VER_LIBRARY: the overall library
165
+ * - #MSPACK_VER_SYSTEM: the mspack_system interface
166
+ * - #MSPACK_VER_MSCABD: the mscab_decompressor interface
167
+ * - #MSPACK_VER_MSCABC: the mscab_compressor interface
168
+ * - #MSPACK_VER_MSCHMD: the mschm_decompressor interface
169
+ * - #MSPACK_VER_MSCHMC: the mschm_compressor interface
170
+ * - #MSPACK_VER_MSLITD: the mslit_decompressor interface
171
+ * - #MSPACK_VER_MSLITC: the mslit_compressor interface
172
+ * - #MSPACK_VER_MSHLPD: the mshlp_decompressor interface
173
+ * - #MSPACK_VER_MSHLPC: the mshlp_compressor interface
174
+ * - #MSPACK_VER_MSSZDDD: the msszdd_decompressor interface
175
+ * - #MSPACK_VER_MSSZDDC: the msszdd_compressor interface
176
+ * - #MSPACK_VER_MSKWAJD: the mskwaj_decompressor interface
177
+ * - #MSPACK_VER_MSKWAJC: the mskwaj_compressor interface
178
+ *
179
+ * The result of the function should be interpreted as follows:
180
+ * - -1: this interface is completely unknown to the library
181
+ * - 0: this interface is known, but non-functioning
182
+ * - 1: this interface has all basic functionality
183
+ * - 2, 3, ...: this interface has additional functionality, clearly marked
184
+ *   in the documentation as "version 2", "version 3" and so on.
185
+ *
186
+ * @param interface the interface to request current version of
187
+ * @return the version of the requested interface
188
+ */
189
+extern int mspack_version(int interface);
190
+
191
+/** Pass to mspack_version() to get the overall library version */
192
+#define MSPACK_VER_LIBRARY   (0)
193
+/** Pass to mspack_version() to get the mspack_system version */
194
+#define MSPACK_VER_SYSTEM    (1)
195
+/** Pass to mspack_version() to get the mscab_decompressor version */
196
+#define MSPACK_VER_MSCABD    (2)
197
+/** Pass to mspack_version() to get the mscab_compressor version */
198
+#define MSPACK_VER_MSCABC    (3)
199
+/** Pass to mspack_version() to get the mschm_decompressor version */
200
+#define MSPACK_VER_MSCHMD    (4)
201
+/** Pass to mspack_version() to get the mschm_compressor version */
202
+#define MSPACK_VER_MSCHMC    (5)
203
+/** Pass to mspack_version() to get the mslit_decompressor version */
204
+#define MSPACK_VER_MSLITD    (6)
205
+/** Pass to mspack_version() to get the mslit_compressor version */
206
+#define MSPACK_VER_MSLITC    (7)
207
+/** Pass to mspack_version() to get the mshlp_decompressor version */
208
+#define MSPACK_VER_MSHLPD    (8)
209
+/** Pass to mspack_version() to get the mshlp_compressor version */
210
+#define MSPACK_VER_MSHLPC    (9)
211
+/** Pass to mspack_version() to get the msszdd_decompressor version */
212
+#define MSPACK_VER_MSSZDDD   (10)
213
+/** Pass to mspack_version() to get the msszdd_compressor version */
214
+#define MSPACK_VER_MSSZDDC   (11)
215
+/** Pass to mspack_version() to get the mskwaj_decompressor version */
216
+#define MSPACK_VER_MSKWAJD   (12)
217
+/** Pass to mspack_version() to get the mskwaj_compressor version */
218
+#define MSPACK_VER_MSKWAJC   (13)
219
+
220
+/* --- file I/O abstraction ------------------------------------------------ */
221
+
222
+/**
223
+ * A structure which abstracts file I/O and memory management.
224
+ *
225
+ * The library always uses the mspack_system structure for interaction
226
+ * with the file system and to allocate, free and copy all memory. It also
227
+ * uses it to send literal messages to the library user.
228
+ *
229
+ * When the library is compiled normally, passing NULL to a compressor or
230
+ * decompressor constructor will result in a default mspack_system being
231
+ * used, where all methods are implemented with the standard C library.
232
+ * However, all constructors support being given a custom created
233
+ * mspack_system structure, with the library user's own methods. This
234
+ * allows for more abstract interaction, such as reading and writing files
235
+ * directly to memory, or from a network socket or pipe.
236
+ *
237
+ * Implementors of an mspack_system structure should read all
238
+ * documentation entries for every structure member, and write methods
239
+ * which conform to those standards.
240
+ */
241
+struct mspack_system {
242
+  /**
243
+   * Opens a file for reading, writing, appending or updating.
244
+   *
245
+   * @param this     a self-referential pointer to the mspack_system
246
+   *                 structure whose open() method is being called. If
247
+   *                 this pointer is required by close(), read(), write(),
248
+   *                 seek() or tell(), it should be stored in the result
249
+   *                 structure at this time.
250
+   * @param filename the file to be opened. It is passed directly from the
251
+   *                 library caller without being modified, so it is up to
252
+   *                 the caller what this parameter actually represents.
253
+   * @param mode     one of #MSPACK_SYS_OPEN_READ (open an existing file
254
+   *                 for reading), #MSPACK_SYS_OPEN_WRITE (open a new file
255
+   *                 for writing), #MSPACK_SYS_OPEN_UPDATE (open an existing
256
+   *                 file for reading/writing from the start of the file) or
257
+   *                 #MSPACK_SYS_OPEN_APPEND (open an existing file for
258
+   *                 reading/writing from the end of the file)
259
+   * @return a pointer to a mspack_file structure. This structure officially
260
+   *         contains no members, its true contents are up to the
261
+   *         mspack_system implementor. It should contain whatever is needed
262
+   *         for other mspack_system methods to operate.
263
+   * @see close(), read(), write(), seek(), tell(), message()
264
+   */
265
+  struct mspack_file * (*open)(struct mspack_system *this,
266
+			       char *filename,
267
+			       int mode);
268
+
269
+  struct mspack_file * (*dopen)(struct mspack_system *this,
270
+			       int desc,
271
+			       int mode);
272
+
273
+  /**
274
+   * Closes a previously opened file. If any memory was allocated for this
275
+   * particular file handle, it should be freed at this time.
276
+   * 
277
+   * @param file the file to close
278
+   * @see open()
279
+   */
280
+  void (*close)(struct mspack_file *file);
281
+
282
+  /**
283
+   * Reads a given number of bytes from an open file.
284
+   *
285
+   * @param file    the file to read from
286
+   * @param buffer  the location where the read bytes should be stored
287
+   * @param bytes   the number of bytes to read from the file.
288
+   * @return the number of bytes successfully read (this can be less than
289
+   *         the number requested), zero to mark the end of file, or less
290
+   *         than zero to indicate an error.
291
+   * @see open(), write()
292
+   */
293
+  int (*read)(struct mspack_file *file,
294
+	      void *buffer,
295
+	      int bytes);
296
+
297
+  /**
298
+   * Writes a given number of bytes to an open file.
299
+   *
300
+   * @param file    the file to write to
301
+   * @param buffer  the location where the written bytes should be read from
302
+   * @param bytes   the number of bytes to write to the file.
303
+   * @return the number of bytes successfully written, this can be less
304
+   *         than the number requested. Zero or less can indicate an error
305
+   *         where no bytes at all could be written. All cases where less
306
+   *         bytes were written than requested are considered by the library
307
+   *         to be an error.
308
+   * @see open(), read()
309
+   */
310
+  int (*write)(struct mspack_file *file,
311
+	       void *buffer,
312
+	       int bytes);
313
+
314
+  /**
315
+   * Seeks to a specific file offset within an open file.
316
+   *
317
+   * Sometimes the library needs to know the length of a file. It does
318
+   * this by seeking to the end of the file with seek(file, 0,
319
+   * MSPACK_SYS_SEEK_END), then calling tell(). Implementations may want
320
+   * to make a special case for this.
321
+   *
322
+   * Due to the potentially varying 32/64 bit datatype off_t on some
323
+   * architectures, the #MSPACK_SYS_SELFTEST macro MUST be used before
324
+   * using the library. If not, the error caused by the library passing an
325
+   * inappropriate stackframe to seek() is subtle and hard to trace.
326
+   *
327
+   * @param file   the file to be seeked
328
+   * @param offset an offset to seek, measured in bytes
329
+   * @param mode   one of #MSPACK_SYS_SEEK_START (the offset should be
330
+   *               measured from the start of the file), #MSPACK_SYS_SEEK_CUR
331
+   *               (the offset should be measured from the current file offset)
332
+   *               or #MSPACK_SYS_SEEK_END (the offset should be measured from
333
+   *               the end of the file)
334
+   * @return zero for success, non-zero for an error
335
+   * @see open(), tell()
336
+   */
337
+  int (*seek)(struct mspack_file *file,
338
+	      off_t offset,
339
+	      int mode);
340
+
341
+  /**
342
+   * Returns the current file position (in bytes) of the given file.
343
+   *
344
+   * @param file the file whose file position is wanted
345
+   * @return the current file position of the file
346
+   * @see open(), seek()
347
+   */
348
+  off_t (*tell)(struct mspack_file *file);
349
+  
350
+  /**
351
+   * Used to send messages from the library to the user.
352
+   *
353
+   * Occasionally, the library generates warnings or other messages in
354
+   * plain english to inform the human user. These are informational only
355
+   * and can be ignored if not wanted.
356
+   *
357
+   * @param file   may be a file handle returned from open() if this message
358
+   *               pertains to a specific open file, or NULL if not related to
359
+   *               a specific file.
360
+   * @param format a printf() style format string. It does NOT include a
361
+   *               trailing newline.
362
+   * @see open()
363
+   */
364
+  void (*message)(struct mspack_file *file,
365
+		  char *format,
366
+		  ...);
367
+
368
+  /**
369
+   * Allocates memory.
370
+   *
371
+   * @param this     a self-referential pointer to the mspack_system
372
+   *                 structure whose alloc() method is being called.
373
+   * @param bytes    the number of bytes to allocate
374
+   * @result a pointer to the requested number of bytes, or NULL if
375
+   *         not enough memory is available
376
+   * @see free()
377
+   */
378
+  void * (*alloc)(struct mspack_system *this,
379
+		  size_t bytes);
380
+  
381
+  /**
382
+   * Frees memory.
383
+   * 
384
+   * @param ptr the memory to be freed.
385
+   * @see alloc()
386
+   */
387
+  void (*free)(void *ptr);
388
+
389
+  /**
390
+   * Copies from one region of memory to another.
391
+   * 
392
+   * The regions of memory are guaranteed not to overlap, are usually less
393
+   * than 256 bytes, and may not be aligned. Please note that the source
394
+   * parameter comes before the destination parameter, unlike the standard
395
+   * C function memcpy().
396
+   *
397
+   * @param src   the region of memory to copy from
398
+   * @param dest  the region of memory to copy to
399
+   * @param bytes the size of the memory region, in bytes
400
+   */
401
+  void (*copy)(void *src,
402
+	       void *dest,
403
+	       size_t bytes);
404
+
405
+  /**
406
+   * A null pointer to mark the end of mspack_system. It must equal NULL.
407
+   *
408
+   * Should the mspack_system structure extend in the future, this NULL
409
+   * will be seen, rather than have an invalid method pointer called.
410
+   */
411
+  void *null_ptr;
412
+};
413
+
414
+/** mspack_system::open() mode: open existing file for reading. */
415
+#define MSPACK_SYS_OPEN_READ   (0)
416
+/** mspack_system::open() mode: open new file for writing */
417
+#define MSPACK_SYS_OPEN_WRITE  (1)
418
+/** mspack_system::open() mode: open existing file for writing */
419
+#define MSPACK_SYS_OPEN_UPDATE (2)
420
+/** mspack_system::open() mode: open existing file for writing */
421
+#define MSPACK_SYS_OPEN_APPEND (3)
422
+
423
+/** mspack_system::seek() mode: seek relative to start of file */
424
+#define MSPACK_SYS_SEEK_START  (0)
425
+/** mspack_system::seek() mode: seek relative to current offset */
426
+#define MSPACK_SYS_SEEK_CUR    (1)
427
+/** mspack_system::seek() mode: seek relative to end of file */
428
+#define MSPACK_SYS_SEEK_END    (2)
429
+
430
+/** 
431
+ * A structure which represents an open file handle. The contents of this
432
+ * structure are determined by the implementation of the
433
+ * mspack_system::open() method.
434
+ */
435
+struct mspack_file {
436
+  int dummy;
437
+};
438
+
439
+/* --- error codes --------------------------------------------------------- */
440
+
441
+/** Error code: no error */
442
+#define MSPACK_ERR_OK          (0)
443
+/** Error code: bad arguments to method */
444
+#define MSPACK_ERR_ARGS        (1)
445
+/** Error code: error opening file */
446
+#define MSPACK_ERR_OPEN        (2)
447
+/** Error code: error reading file */
448
+#define MSPACK_ERR_READ        (3)
449
+/** Error code: error writing file */
450
+#define MSPACK_ERR_WRITE       (4)
451
+/** Error code: seek error */
452
+#define MSPACK_ERR_SEEK        (5)
453
+/** Error code: out of memory */
454
+#define MSPACK_ERR_NOMEMORY    (6)
455
+/** Error code: bad "magic id" in file */
456
+#define MSPACK_ERR_SIGNATURE   (7)
457
+/** Error code: bad or corrupt file format */
458
+#define MSPACK_ERR_DATAFORMAT  (8)
459
+/** Error code: bad checksum or CRC */
460
+#define MSPACK_ERR_CHECKSUM    (9)
461
+/** Error code: error during compression */
462
+#define MSPACK_ERR_CRUNCH      (10)
463
+/** Error code: error during decompression */
464
+#define MSPACK_ERR_DECRUNCH    (11)
465
+
466
+/* --- functions available in library -------------------------------------- */
467
+
468
+/** Creates a new CAB compressor.
469
+ * @param sys a custom mspack_system structure, or NULL to use the default
470
+ * @return a #mscab_compressor or NULL
471
+ */
472
+extern struct mscab_compressor *
473
+  mspack_create_cab_compressor(struct mspack_system *sys);
474
+
475
+/** Creates a new CAB decompressor.
476
+ * @param sys a custom mspack_system structure, or NULL to use the default
477
+ * @return a #mscab_decompressor or NULL
478
+ */
479
+extern struct mscab_decompressor *
480
+  mspack_create_cab_decompressor(struct mspack_system *sys);
481
+
482
+/** Destroys an existing CAB compressor.
483
+ * @param this the #mscab_compressor to destroy
484
+ */
485
+extern void mspack_destroy_cab_compressor(struct mscab_compressor *this);
486
+
487
+/** Destroys an existing CAB decompressor.
488
+ * @param this the #mscab_decompressor to destroy
489
+ */
490
+extern void mspack_destroy_cab_decompressor(struct mscab_decompressor *this);
491
+
492
+
493
+/** Creates a new CHM compressor.
494
+ * @param sys a custom mspack_system structure, or NULL to use the default
495
+ * @return a #mschm_compressor or NULL
496
+ */
497
+extern struct mschm_compressor *
498
+  mspack_create_chm_compressor(struct mspack_system *sys);
499
+
500
+/** Creates a new CHM decompressor.
501
+ * @param sys a custom mspack_system structure, or NULL to use the default
502
+ * @return a #mschm_decompressor or NULL
503
+ */
504
+extern struct mschm_decompressor *
505
+  mspack_create_chm_decompressor(struct mspack_system *sys);
506
+
507
+/** Destroys an existing CHM compressor.
508
+ * @param this the #mschm_compressor to destroy
509
+ */
510
+extern void mspack_destroy_chm_compressor(struct mschm_compressor *this);
511
+
512
+/** Destroys an existing CHM decompressor.
513
+ * @param this the #mschm_decompressor to destroy
514
+ */
515
+extern void mspack_destroy_chm_decompressor(struct mschm_decompressor *this);
516
+
517
+
518
+/** Creates a new LIT compressor.
519
+ * @param sys a custom mspack_system structure, or NULL to use the default
520
+ * @return a #mslit_compressor or NULL
521
+ */
522
+extern struct mslit_compressor *
523
+  mspack_create_lit_compressor(struct mspack_system *sys);
524
+
525
+/** Creates a new LIT decompressor.
526
+ * @param sys a custom mspack_system structure, or NULL to use the default
527
+ * @return a #mslit_decompressor or NULL
528
+ */
529
+extern struct mslit_decompressor *
530
+  mspack_create_lit_decompressor(struct mspack_system *sys);
531
+
532
+/** Destroys an existing LIT compressor.
533
+ * @param this the #mslit_compressor to destroy
534
+ */
535
+extern void mspack_destroy_lit_compressor(struct mslit_compressor *this);
536
+
537
+/** Destroys an existing LIT decompressor.
538
+ * @param this the #mslit_decompressor to destroy
539
+ */
540
+extern void mspack_destroy_lit_decompressor(struct mslit_decompressor *this);
541
+
542
+
543
+/** Creates a new HLP compressor.
544
+ * @param sys a custom mspack_system structure, or NULL to use the default
545
+ * @return a #mshlp_compressor or NULL
546
+ */
547
+extern struct mshlp_compressor *
548
+  mspack_create_hlp_compressor(struct mspack_system *sys);
549
+
550
+/** Creates a new HLP decompressor.
551
+ * @param sys a custom mspack_system structure, or NULL to use the default
552
+ * @return a #mshlp_decompressor or NULL
553
+ */
554
+extern struct mshlp_decompressor *
555
+  mspack_create_hlp_decompressor(struct mspack_system *sys);
556
+
557
+/** Destroys an existing hlp compressor.
558
+ * @param this the #mshlp_compressor to destroy
559
+ */
560
+extern void mspack_destroy_hlp_compressor(struct mshlp_compressor *this);
561
+
562
+/** Destroys an existing hlp decompressor.
563
+ * @param this the #mshlp_decompressor to destroy
564
+ */
565
+extern void mspack_destroy_hlp_decompressor(struct mshlp_decompressor *this);
566
+
567
+
568
+/** Creates a new SZDD compressor.
569
+ * @param sys a custom mspack_system structure, or NULL to use the default
570
+ * @return a #msszdd_compressor or NULL
571
+ */
572
+extern struct msszdd_compressor *
573
+  mspack_create_szdd_compressor(struct mspack_system *sys);
574
+
575
+/** Creates a new SZDD decompressor.
576
+ * @param sys a custom mspack_system structure, or NULL to use the default
577
+ * @return a #msszdd_decompressor or NULL
578
+ */
579
+extern struct msszdd_decompressor *
580
+  mspack_create_szdd_decompressor(struct mspack_system *sys);
581
+
582
+/** Destroys an existing SZDD compressor.
583
+ * @param this the #msszdd_compressor to destroy
584
+ */
585
+extern void mspack_destroy_szdd_compressor(struct msszdd_compressor *this);
586
+
587
+/** Destroys an existing SZDD decompressor.
588
+ * @param this the #msszdd_decompressor to destroy
589
+ */
590
+extern void mspack_destroy_szdd_decompressor(struct msszdd_decompressor *this);
591
+
592
+
593
+/** Creates a new KWAJ compressor.
594
+ * @param sys a custom mspack_system structure, or NULL to use the default
595
+ * @return a #mskwaj_compressor or NULL
596
+ */
597
+extern struct mskwaj_compressor *
598
+  mspack_create_kwaj_compressor(struct mspack_system *sys);
599
+
600
+/** Creates a new KWAJ decompressor.
601
+ * @param sys a custom mspack_system structure, or NULL to use the default
602
+ * @return a #mskwaj_decompressor or NULL
603
+ */
604
+extern struct mskwaj_decompressor *
605
+  mspack_create_kwaj_decompressor(struct mspack_system *sys);
606
+
607
+/** Destroys an existing KWAJ compressor.
608
+ * @param this the #mskwaj_compressor to destroy
609
+ */
610
+extern void mspack_destroy_kwaj_compressor(struct mskwaj_compressor *this);
611
+
612
+/** Destroys an existing KWAJ decompressor.
613
+ * @param this the #mskwaj_decompressor to destroy
614
+ */
615
+extern void mspack_destroy_kwaj_decompressor(struct mskwaj_decompressor *this);
616
+
617
+
618
+/* --- support for .CAB (MS Cabinet) file format --------------------------- */
619
+
620
+/**
621
+ * A structure which represents a single cabinet file.
622
+ *
623
+ * All fields are READ ONLY.
624
+ *
625
+ * If this cabinet is part of a merged cabinet set, the #files and #folders
626
+ * fields are common to all cabinets in the set, and will be identical.
627
+ *
628
+ * @see mscab_decompressor::open(), mscab_decompressor::close(),
629
+ *      mscab_decompressor::search()
630
+ */
631
+struct mscabd_cabinet {
632
+  /**
633
+   * The next cabinet in a chained list, if this cabinet was opened with
634
+   * mscab_decompressor::search(). May be NULL to mark the end of the
635
+   * list.
636
+   */
637
+  struct mscabd_cabinet *next;
638
+
639
+  /**
640
+   * The filename of the cabinet. More correctly, the filename of the
641
+   * physical file that the cabinet resides in. This is given by the
642
+   * library user and may be in any format.
643
+   */
644
+  char *filename;
645
+
646
+  int desc;
647
+
648
+  
649
+  /** The file offset of cabinet within the physical file it resides in. */
650
+  off_t base_offset;
651
+
652
+  /** The length of the cabinet file in bytes. */
653
+  unsigned int length;
654
+
655
+  /** The previous cabinet in a cabinet set, or NULL. */
656
+  struct mscabd_cabinet *prevcab;
657
+
658
+  /** The next cabinet in a cabinet set, or NULL. */
659
+  struct mscabd_cabinet *nextcab;
660
+
661
+  /** The filename of the previous cabinet in a cabinet set, or NULL. */
662
+  char *prevname;
663
+
664
+  /** The filename of the next cabinet in a cabinet set, or NULL. */
665
+  char *nextname;
666
+
667
+  /** The name of the disk containing the previous cabinet in a cabinet
668
+   * set, or NULL.
669
+   */
670
+  char *previnfo;
671
+
672
+  /** The name of the disk containing the next cabinet in a cabinet set,
673
+   * or NULL.
674
+   */
675
+  char *nextinfo;
676
+
677
+  /** A list of all files in the cabinet or cabinet set. */
678
+  struct mscabd_file *files;
679
+
680
+  /** A list of all folders in the cabinet or cabinet set. */
681
+  struct mscabd_folder *folders;
682
+
683
+  /** 
684
+   * The set ID of the cabinet. All cabinets in the same set should have
685
+   * the same set ID.
686
+   */
687
+  unsigned short set_id;
688
+
689
+  /**
690
+   * The index number of the cabinet within the set. Numbering should
691
+   * start from 0 for the first cabinet in the set, and increment by 1 for
692
+   * each following cabinet.
693
+   */
694
+  unsigned short set_index;
695
+
696
+  /**
697
+   * The number of bytes reserved in the header area of the cabinet.
698
+   *
699
+   * If this is non-zero and flags has MSCAB_HDR_RESV set, this data can
700
+   * be read by the calling application. It is of the given length,
701
+   * located at offset (base_offset + MSCAB_HDR_RESV_OFFSET) in the
702
+   * cabinet file.
703
+   *
704
+   * @see flags
705
+   */
706
+  unsigned short header_resv;
707
+
708
+  /**
709
+   * Header flags.
710
+   *
711
+   * - MSCAB_HDR_PREVCAB indicates the cabinet is part of a cabinet set, and
712
+   *                     has a predecessor cabinet.
713
+   * - MSCAB_HDR_NEXTCAB indicates the cabinet is part of a cabinet set, and
714
+   *                     has a successor cabinet.
715
+   * - MSCAB_HDR_RESV indicates the cabinet has reserved header space.
716
+   *
717
+   * @see prevname, previnfo, nextname, nextinfo, header_resv
718
+   */
719
+  int flags;
720
+};
721
+
722
+/** Offset from start of cabinet to the reserved header data (if present). */
723
+#define MSCAB_HDR_RESV_OFFSET (0x28)
724
+
725
+/** Cabinet header flag: cabinet has a predecessor */
726
+#define MSCAB_HDR_PREVCAB (0x01)
727
+/** Cabinet header flag: cabinet has a successor */
728
+#define MSCAB_HDR_NEXTCAB (0x02)
729
+/** Cabinet header flag: cabinet has reserved header space */
730
+#define MSCAB_HDR_RESV    (0x04)
731
+
732
+/**
733
+ * A structure which represents a single folder in a cabinet or cabinet set.
734
+ *
735
+ * All fields are READ ONLY.
736
+ *
737
+ * A folder is a single compressed stream of data. When uncompressed, it
738
+ * holds the data of one or more files. A folder may be split across more
739
+ * than one cabinet.
740
+ */
741
+struct mscabd_folder {
742
+  /**
743
+   * A pointer to the next folder in this cabinet or cabinet set, or NULL
744
+   * if this is the final folder.
745
+   */
746
+  struct mscabd_folder *next;
747
+
748
+  /** 
749
+   * The compression format used by this folder.
750
+   *
751
+   * The macro MSCABD_COMP_METHOD() should be used on this field to get
752
+   * the algorithm used. The macro MSCABD_COMP_LEVEL() should be used to get
753
+   * the "compression level".
754
+   *
755
+   * @see MSCABD_COMP_METHOD(), MSCABD_COMP_LEVEL()
756
+   */
757
+  int comp_type;
758
+
759
+  /**
760
+   * The total number of data blocks used by this folder. This includes
761
+   * data blocks present in other files, if this folder spans more than
762
+   * one cabinet.
763
+   */
764
+  unsigned int num_blocks;
765
+};
766
+
767
+/**
768
+ * Returns the compression method used by a folder.
769
+ *
770
+ * @param comp_type a mscabd_folder::comp_type value
771
+ * @return one of #MSCAB_COMP_NONE, #MSCAB_COMP_MSZIP, #MSCAB_COMP_QUANTUM
772
+ *         or #MSCAB_COMP_LZX
773
+ */
774
+#define MSCABD_COMP_METHOD(comp_type) ((comp_type) & 0x0F)
775
+/**
776
+ * Returns the compression level used by a folder.
777
+ *
778
+ * @param comp_type a mscabd_folder::comp_type value
779
+ * @return the compression level. This is only defined by LZX and Quantum
780
+ *         compression
781
+ */
782
+#define MSCABD_COMP_LEVEL(comp_type) (((comp_type) >> 8) & 0x1F)
783
+
784
+/** Compression mode: no compression. */
785
+#define MSCAB_COMP_NONE       (0)
786
+/** Compression mode: MSZIP (deflate) compression. */
787
+#define MSCAB_COMP_MSZIP      (1)
788
+/** Compression mode: Quantum compression */
789
+#define MSCAB_COMP_QUANTUM    (2)
790
+/** Compression mode: LZX compression */
791
+#define MSCAB_COMP_LZX        (3)
792
+
793
+/**
794
+ * A structure which represents a single file in a cabinet or cabinet set.
795
+ *
796
+ * All fields are READ ONLY.
797
+ */
798
+struct mscabd_file {
799
+  /**
800
+   * The next file in the cabinet or cabinet set, or NULL if this is the
801
+   * final file.
802
+   */
803
+  struct mscabd_file *next;
804
+
805
+  /**
806
+   * The filename of the file.
807
+   *
808
+   * A null terminated string of up to 255 bytes in length, it may be in
809
+   * either ISO-8859-1 or UTF8 format, depending on the file attributes.
810
+   *
811
+   * @see attribs
812
+   */
813
+  char *filename;
814
+
815
+  /** The uncompressed length of the file, in bytes. */
816
+  unsigned int length;
817
+
818
+  /**
819
+   * File attributes.
820
+   *
821
+   * The following attributes are defined:
822
+   * - #MSCAB_ATTRIB_RDONLY indicates the file is write protected.
823
+   * - #MSCAB_ATTRIB_HIDDEN indicates the file is hidden.
824
+   * - #MSCAB_ATTRIB_SYSTEM indicates the file is a operating system file.
825
+   * - #MSCAB_ATTRIB_ARCH indicates the file is "archived".
826
+   * - #MSCAB_ATTRIB_EXEC indicates the file is an executable program.
827
+   * - #MSCAB_ATTRIB_UTF_NAME indicates the filename is in UTF8 format rather
828
+   *   than ISO-8859-1.
829
+   */
830
+  int attribs;
831
+
832
+  /** File's last modified time, hour field. */
833
+  char time_h;
834
+  /** File's last modified time, minute field. */
835
+  char time_m;
836
+  /** File's last modified time, second field. */
837
+  char time_s;
838
+
839
+  /** File's last modified date, day field. */
840
+  char date_d;
841
+  /** File's last modified date, month field. */
842
+  char date_m;
843
+  /** File's last modified date, year field. */
844
+  int date_y;
845
+
846
+  /** A pointer to the folder that contains this file. */
847
+  struct mscabd_folder *folder;
848
+
849
+  /** The uncompressed offset of this file in its folder. */
850
+  unsigned int offset;
851
+};
852
+
853
+/** mscabd_file::attribs attribute: file is read-only. */
854
+#define MSCAB_ATTRIB_RDONLY   (0x01)
855
+/** mscabd_file::attribs attribute: file is hidden. */
856
+#define MSCAB_ATTRIB_HIDDEN   (0x02)
857
+/** mscabd_file::attribs attribute: file is an operating system file. */
858
+#define MSCAB_ATTRIB_SYSTEM   (0x04)
859
+/** mscabd_file::attribs attribute: file is "archived". */
860
+#define MSCAB_ATTRIB_ARCH     (0x20)
861
+/** mscabd_file::attribs attribute: file is an executable program. */
862
+#define MSCAB_ATTRIB_EXEC     (0x40)
863
+/** mscabd_file::attribs attribute: filename is UTF8, not ISO-8859-1. */
864
+#define MSCAB_ATTRIB_UTF_NAME (0x80)
865
+
866
+/** mscab_decompressor::set_param() parameter: search buffer size. */
867
+#define MSCABD_PARAM_SEARCHBUF (0)
868
+/** mscab_decompressor::set_param() parameter: repair MS-ZIP streams? */
869
+#define MSCABD_PARAM_FIXMSZIP  (1)
870
+/** mscab_decompressor::set_param() parameter: size of decompression buffer */
871
+#define MSCABD_PARAM_DECOMPBUF (2)
872
+
873
+/** TODO */
874
+struct mscab_compressor {
875
+  int dummy; 
876
+};
877
+
878
+/**
879
+ * A decompressor for .CAB (Microsoft Cabinet) files
880
+ *
881
+ * All fields are READ ONLY.
882
+ *
883
+ * @see mspack_create_cab_decompressor(), mspack_destroy_cab_decompressor()
884
+ */
885
+struct mscab_decompressor {
886
+  /**
887
+   * Opens a cabinet file and reads its contents.
888
+   *
889
+   * If the file opened is a valid cabinet file, all headers will be read
890
+   * and a mscabd_cabinet structure will be returned, with a full list of
891
+   * folders and files.
892
+   *
893
+   * In the case of an error occuring, NULL is returned and the error code
894
+   * is available from last_error().
895
+   *
896
+   * The filename pointer should be considered "in use" until close() is
897
+   * called on the cabinet.
898
+   *
899
+   * @param  this     a self-referential pointer to the mscab_decompressor
900
+   *                  instance being called
901
+   * @param  filename the filename of the cabinet file. This is passed
902
+   *                  directly to mspack_system::open().
903
+   * @return a pointer to a mscabd_cabinet structure, or NULL on failure
904
+   * @see close(), search(), last_error()
905
+   */
906
+  struct mscabd_cabinet * (*open) (struct mscab_decompressor *this,
907
+				   char *filename);
908
+
909
+  struct mscabd_cabinet * (*dopen) (struct mscab_decompressor *this,
910
+				   int desc);
911
+  /**
912
+   * Closes a previously opened cabinet or cabinet set.
913
+   *
914
+   * This closes a cabinet, all cabinets associated with it via the
915
+   * mscabd_cabinet::next, mscabd_cabinet::prevcab and
916
+   * mscabd_cabinet::nextcab pointers, and all folders and files. All
917
+   * memory used by these entities is freed.
918
+   *
919
+   * The cabinet pointer is now invalid and cannot be used again. All
920
+   * mscabd_folder and mscabd_file pointers from that cabinet or cabinet
921
+   * set are also now invalid, and cannot be used again.
922
+   *
923
+   * If the cabinet pointer given was created using search(), it MUST be
924
+   * the cabinet pointer returned by search() and not one of the later
925
+   * cabinet pointers further along the mscabd_cabinet::next chain.
926
+
927
+   * If extra cabinets have been added using append() or prepend(), these
928
+   * will all be freed, even if the cabinet pointer given is not the first
929
+   * cabinet in the set. Do NOT close() more than one cabinet in the set.
930
+   *
931
+   * The mscabd_cabinet::filename is not freed by the library, as it is
932
+   * not allocated by the library. The caller should free this itself if
933
+   * necessary, before it is lost forever.
934
+   *
935
+   * @param  this     a self-referential pointer to the mscab_decompressor
936
+   *                  instance being called
937
+   * @param  cab      the cabinet to close
938
+   * @see open(), search(), append(), prepend()
939
+   */
940
+  void (*close)(struct mscab_decompressor *this,
941
+		struct mscabd_cabinet *cab);
942
+
943
+  /**
944
+   * Searches a regular file for embedded cabinets.
945
+   *
946
+   * This opens a normal file with the given filename and will search the
947
+   * entire file for embedded cabinet files
948
+   *
949
+   * If any cabinets are found, the equivalent of open() is called on each
950
+   * potential cabinet file at the offset it was found. All successfully
951
+   * open()ed cabinets are kept in a list.
952
+   *
953
+   * The first cabinet found will be returned directly as the result of
954
+   * this method. Any further cabinets found will be chained in a list
955
+   * using the mscabd_cabinet::next field.
956
+   *
957
+   * In the case of an error occuring anywhere other than the simulated
958
+   * open(), NULL is returned and the error code is available from
959
+   * last_error().
960
+   *
961
+   * If no error occurs, but no cabinets can be found in the file, NULL is
962
+   * returned and last_error() returns MSPACK_ERR_OK.
963
+   *
964
+   * The filename pointer should be considered in use until close() is
965
+   * called on the cabinet.
966
+   *
967
+   * close() should only be called on the result of search(), not on any
968
+   * subsequent cabinets in the mscabd_cabinet::next chain.
969
+   *
970
+   * @param  this     a self-referential pointer to the mscab_decompressor
971
+   *                  instance being called
972
+   * @param  filename the filename of the file to search for cabinets. This
973
+   *                  is passed directly to mspack_system::open().
974
+   * @return a pointer to a mscabd_cabinet structure, or NULL
975
+   * @see close(), open(), last_error()
976
+   */
977
+  struct mscabd_cabinet * (*search) (struct mscab_decompressor *this,
978
+				     char *filename);
979
+
980
+  struct mscabd_cabinet * (*dsearch) (struct mscab_decompressor *this,
981
+				     int desc);
982
+
983
+  /**
984
+   * Appends one mscabd_cabinet to another, forming or extending a cabinet
985
+   * set.
986
+   *
987
+   * This will attempt to append one cabinet to another such that
988
+   * <tt>(cab->nextcab == nextcab) && (nextcab->prevcab == cab)</tt> and
989
+   * any folders split between the two cabinets are merged.
990
+   *
991
+   * The cabinets MUST be part of a cabinet set -- a cabinet set is a
992
+   * cabinet that spans more than one physical cabinet file on disk -- and
993
+   * must be appropriately matched.
994
+   *
995
+   * It can be determined if a cabinet has further parts to load by
996
+   * examining the mscabd_cabinet::flags field:
997
+   *
998
+   * - if <tt>(flags & MSCAB_HDR_PREVCAB)</tt> is non-zero, there is a
999
+   *   predecessor cabinet to open() and prepend(). Its MS-DOS
1000
+   *   case-insensitive filename is mscabd_cabinet::prevname
1001
+   * - if <tt>(flags & MSCAB_HDR_NEXTCAB)</tt> is non-zero, there is a
1002
+   *   successor cabinet to open() and append(). Its MS-DOS case-insensitive
1003
+   *   filename is mscabd_cabinet::nextname
1004
+   *
1005
+   * If the cabinets do not match, an error code will be returned. Neither
1006
+   * cabinet has been altered, and both should be closed seperately.
1007
+   *
1008
+   * Files and folders in a cabinet set are a single entity. All cabinets
1009
+   * in a set use the same file list, which is updated as cabinets in the
1010
+   * set are added. All pointers to mscabd_folder and mscabd_file
1011
+   * structures in either cabinet must be discarded and re-obtained after
1012
+   * merging.
1013
+   *
1014
+   * @param  this     a self-referential pointer to the mscab_decompressor
1015
+   *                  instance being called
1016
+   * @param  cab      the cabinet which will be appended to,
1017
+   *                  predecessor of nextcab
1018
+   * @param  nextcab  the cabinet which will be appended,
1019
+   *                  successor of cab
1020
+   * @return an error code, or MSPACK_ERR_OK if successful
1021
+   * @see prepend(), open(), close()
1022
+   */
1023
+  int (*append) (struct mscab_decompressor *this,
1024
+		 struct mscabd_cabinet *cab,
1025
+		 struct mscabd_cabinet *nextcab);
1026
+
1027
+  /**
1028
+   * Prepends one mscabd_cabinet to another, forming or extending a
1029
+   * cabinet set.
1030
+   *
1031
+   * This will attempt to prepend one cabinet to another, such that
1032
+   * <tt>(cab->prevcab == prevcab) && (prevcab->nextcab == cab)</tt>. In
1033
+   * all other respects, it is identical to append(). See append() for the
1034
+   * full documentation.
1035
+   *
1036
+   * @param  this     a self-referential pointer to the mscab_decompressor
1037
+   *                  instance being called
1038
+   * @param  cab      the cabinet which will be prepended to,
1039
+   *                  successor of prevcab
1040
+   * @param  prevcab  the cabinet which will be prepended,
1041
+   *                  predecessor of cab
1042
+   * @return an error code, or MSPACK_ERR_OK if successful
1043
+   * @see append(), open(), close()
1044
+   */
1045
+  int (*prepend) (struct mscab_decompressor *this,
1046
+		  struct mscabd_cabinet *cab,
1047
+		  struct mscabd_cabinet *prevcab);
1048
+
1049
+  /**
1050
+   * Extracts a file from a cabinet or cabinet set.
1051
+   *
1052
+   * This extracts a compressed file in a cabinet and writes it to the given
1053
+   * filename.
1054
+   *
1055
+   * The MS-DOS filename of the file, mscabd_file::filename, is NOT USED
1056
+   * by extract(). The caller must examine this MS-DOS filename, copy and
1057
+   * change it as necessary, create directories as necessary, and provide
1058
+   * the correct filename as a parameter, which will be passed unchanged
1059
+   * to the decompressor's mspack_system::open()
1060
+   *
1061
+   * If the file belongs to a split folder in a multi-part cabinet set,
1062
+   * and not enough parts of the cabinet set have been loaded and appended
1063
+   * or prepended, an error will be returned immediately.
1064
+   *
1065
+   * @param  this     a self-referential pointer to the mscab_decompressor
1066
+   *                  instance being called
1067
+   * @param  file     the file to be decompressed
1068
+   * @param  filename the filename of the file being written to
1069
+   * @return an error code, or MSPACK_ERR_OK if successful
1070
+   */
1071
+  int (*extract)(struct mscab_decompressor *this,
1072
+		 struct mscabd_file *file,
1073
+		 char *filename);
1074
+
1075
+  /**
1076
+   * Sets a CAB decompression engine parameter.
1077
+   *
1078
+   * The following parameters are defined:
1079
+   * - #MSCABD_PARAM_SEARCHBUF: How many bytes should be allocated as a
1080
+   *   buffer when using search()? The minimum value is 4.  The default
1081
+   *   value is 32768.
1082
+   * - #MSCABD_PARAM_FIXMSZIP: If non-zero, extract() will ignore bad
1083
+   *   checksums and recover from decompression errors in MS-ZIP
1084
+   *   compressed folders. The default value is 0 (don't recover).
1085
+   * - #MSCABD_PARAM_DECOMPBUF: How many bytes should be used as an input
1086
+   *   bit buffer by decompressors? The minimum value is 4. The default
1087
+   *   value is 4096.
1088
+   *
1089
+   * @param  this     a self-referential pointer to the mscab_decompressor
1090
+   *                  instance being called
1091
+   * @param  param    the parameter to set
1092
+   * @param  value    the value to set the parameter to
1093
+   * @return MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS if there
1094
+   *         is a problem with either parameter or value.
1095
+   * @see search(), extract()
1096
+   */
1097
+  int (*set_param)(struct mscab_decompressor *this,
1098
+		   int param,
1099
+		   int value);
1100
+
1101
+  /**
1102
+   * Returns the error code set by the most recently called method.
1103
+   *
1104
+   * This is useful for open() and search(), which do not return an error
1105
+   * code directly.
1106
+   *
1107
+   * @param  this     a self-referential pointer to the mscab_decompressor
1108
+   *                  instance being called
1109
+   * @return the most recent error code
1110
+   * @see open(), search()
1111
+   */
1112
+  int (*last_error)(struct mscab_decompressor *);
1113
+};
1114
+
1115
+/* --- support for .CHM (HTMLHelp) file format ----------------------------- */
1116
+
1117
+/**
1118
+ * A structure which represents a section of a CHM helpfile.
1119
+ *
1120
+ * All fields are READ ONLY.
1121
+ *
1122
+ * Not used directly, but used as a generic base type for
1123
+ * mschmd_sec_uncompressed and mschmd_sec_mscompressed.
1124
+ */
1125
+struct mschmd_section {
1126
+  /** A pointer to the CHM helpfile that contains this section. */
1127
+  struct mschmd_header *chm;
1128
+
1129
+  /**
1130
+   * The section ID. Either 0 for the uncompressed section
1131
+   * mschmd_sec_uncompressed, or 1 for the LZX compressed section
1132
+   * mschmd_sec_mscompressed. No other section IDs are known.
1133
+   */
1134
+  unsigned int id;
1135
+};
1136
+
1137
+/**
1138
+ * A structure which represents the uncompressed section of a CHM helpfile.
1139
+ * 
1140
+ * All fields are READ ONLY.
1141
+ */
1142
+struct mschmd_sec_uncompressed {
1143
+  /** Generic section data. */
1144
+  struct mschmd_section base;
1145
+
1146
+  /** The file offset of where this section begins in the CHM helpfile. */
1147
+  off_t offset;
1148
+};
1149
+
1150
+/**
1151
+ * A structure which represents the compressed section of a CHM helpfile. 
1152
+ * 
1153
+ * All fields are READ ONLY.
1154
+ */
1155
+struct mschmd_sec_mscompressed {
1156
+  /** Generic section data. */
1157
+  struct mschmd_section base;
1158
+
1159
+  /** A pointer to the meta-file which represents all LZX compressed data. */
1160
+  struct mschmd_file *content;
1161
+
1162
+  /** A pointer to the file which contains the LZX control data. */
1163
+  struct mschmd_file *control;
1164
+
1165
+  /** A pointer to the file which contains the LZX reset table. */
1166
+  struct mschmd_file *rtable;
1167
+};
1168
+
1169
+/**
1170
+ * A structure which represents a CHM helpfile.
1171
+ * 
1172
+ * All fields are READ ONLY.
1173
+ */
1174
+struct mschmd_header {
1175
+  /** The version of the CHM file format used in this file. */
1176
+  unsigned int version;
1177
+
1178
+  /**
1179
+   * The "timestamp" of the CHM helpfile. 
1180
+   *
1181
+   * It is the lower 32 bits of a 64-bit value representing the number of
1182
+   * centiseconds since 1601-01-01 00:00:00 UTC, plus 42. It is not useful
1183
+   * as a timestamp, but it is useful as a semi-unique ID.
1184
+   */
1185
+  unsigned int timestamp;
1186
+
1187
+      
1188
+  /**
1189
+   * The default Language and Country ID (LCID) of the user who ran the
1190
+   * HTMLHelp Compiler. This is not the language of the CHM file itself.
1191
+   */
1192
+  unsigned int language;
1193
+
1194
+  /**
1195
+   * The filename of the CHM helpfile. This is given by the library user
1196
+   * and may be in any format.
1197
+   */
1198
+  char *filename;
1199
+
1200
+  /** The length of the CHM helpfile, in bytes. */
1201
+  off_t length;
1202
+
1203
+  /** A list of all non-system files in the CHM helpfile. */
1204
+  struct mschmd_file *files;
1205
+
1206
+  /**
1207
+   * A list of all system files in the CHM helpfile.
1208
+   *
1209
+   * System files are files which begin with "::". They are meta-files
1210
+   * generated by the CHM creation process.
1211
+   */
1212
+  struct mschmd_file *sysfiles;
1213
+
1214
+  /** The section 0 (uncompressed) data in this CHM helpfile. */
1215
+  struct mschmd_sec_uncompressed sec0;
1216
+
1217
+  /** The section 1 (MSCompressed) data in this CHM helpfile. */
1218
+  struct mschmd_sec_mscompressed sec1;
1219
+
1220
+  /** The file offset of the first PMGL/PMGI directory chunk. */
1221
+  off_t dir_offset;
1222
+
1223
+  /** The number of PMGL/PMGI directory chunks in this CHM helpfile. */
1224
+  unsigned int num_chunks;
1225
+
1226
+  /** The size of each PMGL/PMGI chunk, in bytes. */
1227
+  unsigned int chunk_size;
1228
+
1229
+  /** The "density" of the quick-reference section in PMGL/PMGI chunks. */
1230
+  unsigned int density;
1231
+
1232
+  /** The depth of the index tree.
1233
+   *
1234
+   * - if 1, there are no PMGI chunks, only PMGL chunks.
1235
+   * - if 2, there is 1 PMGI chunk. All chunk indices point to PMGL chunks.
1236
+   * - if 3, the root PMGI chunk points to secondary PMGI chunks, which in
1237
+   *         turn point to PMGL chunks.
1238
+   * - and so on...
1239
+   */
1240
+  unsigned int depth;
1241
+
1242
+  /**
1243
+   * The number of the root PGMI chunk.
1244
+   *
1245
+   * If there is no index in the CHM helpfile, this will be 0xFFFFFFFF.
1246
+   */
1247
+  unsigned int index_root;
1248
+};
1249
+
1250
+/**
1251
+ * A structure which represents a file stored in a CHM helpfile.
1252
+ * 
1253
+ * All fields are READ ONLY.
1254
+ */
1255
+struct mschmd_file {
1256
+  /**
1257
+   * A pointer to the next file in the list, or NULL if this is the final
1258
+   * file.
1259
+   */
1260
+  struct mschmd_file *next;
1261
+
1262
+  /**
1263
+   * A pointer to the section that this file is located in. Indirectly,
1264
+   * it also points to the CHM helpfile the file is located in.
1265
+   */
1266
+  struct mschmd_section *section;
1267
+
1268
+  /** The offset within the section data that this file is located at. */
1269
+  off_t offset;
1270
+
1271
+  /** The length of this file, in bytes */
1272
+  off_t length;
1273
+
1274
+  /** The filename of this file -- a null terminated string in UTF8. */
1275
+  char *filename;
1276
+};
1277
+
1278
+/** TODO */
1279
+struct mschm_compressor {
1280
+  int dummy;
1281
+};
1282
+
1283
+/**
1284
+ * A decompressor for .CHM (Microsoft HTMLHelp) files
1285
+ *
1286
+ * All fields are READ ONLY.
1287
+ *
1288
+ * @see mspack_create_chm_decompressor(), mspack_destroy_chm_decompressor()
1289
+ */
1290
+struct mschm_decompressor {
1291
+  /**
1292
+   * Opens a CHM helpfile and reads its contents.
1293
+   *
1294
+   * If the file opened is a valid CHM helpfile, all headers will be read
1295
+   * and a mschmd_header structure will be returned, with a full list of
1296
+   * files.
1297
+   *
1298
+   * In the case of an error occuring, NULL is returned and the error code
1299
+   * is available from last_error().
1300
+   *
1301
+   * The filename pointer should be considered "in use" until close() is
1302
+   * called on the CHM helpfile.
1303
+   *
1304
+   * @param  this     a self-referential pointer to the mschm_decompressor
1305
+   *                  instance being called
1306
+   * @param  filename the filename of the CHM helpfile. This is passed
1307
+   *                  directly to mspack_system::open().
1308
+   * @return a pointer to a mschmd_header structure, or NULL on failure
1309
+   * @see close()
1310
+   */
1311
+  struct mschmd_header *(*open)(struct mschm_decompressor *this,
1312
+				char *filename);
1313
+
1314
+  /**
1315
+   * Closes a previously opened CHM helpfile.
1316
+   *
1317
+   * This closes a CHM helpfile, frees the mschmd_header and all
1318
+   * mschmd_file structures associated with it (if any). This works on
1319
+   * both helpfiles opened with open() and helpfiles opened with
1320
+   * fast_open().
1321
+   *
1322
+   * The CHM header pointer is now invalid and cannot be used again. All
1323
+   * mschmd_file pointers referencing that CHM are also now invalid, and
1324
+   * cannot be used again.
1325
+   *
1326
+   * @param  this     a self-referential pointer to the mschm_decompressor
1327
+   *                  instance being called
1328
+   * @param  chm      the CHM helpfile to close
1329
+   * @see open(), fast_open()
1330
+   */
1331
+  void (*close)(struct mschm_decompressor *this,
1332
+		struct mschmd_header *chm);
1333
+
1334
+  /**
1335
+   * Extracts a file from a CHM helpfile.
1336
+   *
1337
+   * This extracts a file from a CHM helpfile and writes it to the given
1338
+   * filename. The filename of the file, mscabd_file::filename, is not
1339
+   * used by extract(), but can be used by the caller as a guide for
1340
+   * constructing an appropriate filename.
1341
+   *
1342
+   * This method works both with files found in the mschmd_header::files
1343
+   * and mschmd_header::sysfiles list and mschmd_file structures generated
1344
+   * on the fly by fast_find().
1345
+   *
1346
+   * @param  this     a self-referential pointer to the mscab_decompressor
1347
+   *                  instance being called
1348
+   * @param  file     the file to be decompressed
1349
+   * @param  filename the filename of the file being written to
1350
+   * @return an error code, or MSPACK_ERR_OK if successful
1351
+   */
1352
+  int (*extract)(struct mschm_decompressor *this,
1353
+		 struct mschmd_file *file,
1354
+		 char *filename);
1355
+
1356
+  /**
1357
+   * Returns the error code set by the most recently called method.
1358
+   *
1359
+   * This is useful for open() and fast_open(), which do not return an
1360
+   * error code directly.
1361
+   *
1362
+   * @param  this     a self-referential pointer to the mschm_decompressor
1363
+   *                  instance being called
1364
+   * @return the most recent error code
1365
+   * @see open(), search()
1366
+   */
1367
+  int (*last_error)(struct mschm_decompressor *this);
1368
+
1369
+  /**
1370
+   * Opens a CHM helpfile quickly.
1371
+   *
1372
+   * If the file opened is a valid CHM helpfile, only essential headers
1373
+   * will be read. A mschmd_header structure will be still be returned, as
1374
+   * with open(), but the mschmd_header::files field will be NULL. No
1375
+   * files details will be automatically read.  The fast_find() method
1376
+   * must be used to obtain file details.
1377
+   *
1378
+   * In the case of an error occuring, NULL is returned and the error code
1379
+   * is available from last_error().
1380
+   *
1381
+   * The filename pointer should be considered "in use" until close() is
1382
+   * called on the CHM helpfile.
1383
+   *
1384
+   * @param  this     a self-referential pointer to the mschm_decompressor
1385
+   *                  instance being called
1386
+   * @param  filename the filename of the CHM helpfile. This is passed
1387
+   *                  directly to mspack_system::open().
1388
+   * @return a pointer to a mschmd_header structure, or NULL on failure
1389
+   * @see open(), close(), fast_find(), extract()
1390
+   */
1391
+  struct mschmd_header *(*fast_open)(struct mschm_decompressor *this,
1392
+				     char *filename);
1393
+
1394
+  /**
1395
+   * Finds file details quickly.
1396
+   *
1397
+   * Instead of reading all CHM helpfile headers and building a list of
1398
+   * files, fast_open() and fast_find() are intended for finding file
1399
+   * details only when they are needed. The CHM file format includes an
1400
+   * on-disk file index to allow this.
1401
+   *
1402
+   * Given a case-sensitive filename, fast_find() will search the on-disk
1403
+   * index for that file.
1404
+   *
1405
+   * If the file was found, the caller-provided mschmd_file structure will
1406
+   * be filled out like so:
1407
+   * - section: the correct value for the found file
1408
+   * - offset: the correct value for the found file
1409
+   * - length: the correct value for the found file
1410
+   * - all other structure elements: NULL or 0
1411
+   *
1412
+   * If the file was not found, MSPACK_ERR_OK will still be returned as the
1413
+   * result, but the caller-provided structure will be filled out like so:
1414
+   * - section: NULL
1415
+   * - offset: 0
1416
+   * - length: 0
1417
+   * - all other structure elements: NULL or 0
1418
+   *
1419
+   * This method is intended to be used in conjunction with CHM helpfiles
1420
+   * opened with fast_open(), but it also works with helpfiles opened
1421
+   * using the regular open().
1422
+   *
1423
+   * @param  this     a self-referential pointer to the mschm_decompressor
1424
+   *                  instance being called
1425
+   * @param  chm      the CHM helpfile to search for the file
1426
+   * @param  filename the filename of the file to search for
1427
+   * @param  f_ptr    a pointer to a caller-provded mschmd_file structure
1428
+   * @param  f_size   <tt>sizeof(struct mschmd_file)</tt>
1429
+   * @return MSPACK_ERR_OK, or an error code
1430
+   * @see open(), close(), fast_find(), extract()
1431
+   */
1432
+  int (*fast_find)(struct mschm_decompressor *this,
1433
+		   struct mschmd_header *chm,
1434
+		   char *filename,
1435
+		   struct mschmd_file *f_ptr,
1436
+		   int f_size);
1437
+};
1438
+
1439
+/* --- support for .LIT (EBook) file format -------------------------------- */
1440
+
1441
+/** TODO */
1442
+struct mslit_compressor {
1443
+  int dummy; 
1444
+};
1445
+
1446
+/** TODO */
1447
+struct mslit_decompressor {
1448
+  int dummy; 
1449
+};
1450
+
1451
+
1452
+/* --- support for .HLP (MS Help) file format ------------------------------ */
1453
+
1454
+/** TODO */
1455
+struct mshlp_compressor {
1456
+  int dummy; 
1457
+};
1458
+
1459
+/** TODO */
1460
+struct mshlp_decompressor {
1461
+  int dummy; 
1462
+};
1463
+
1464
+
1465
+/* --- support for SZDD file format ---------------------------------------- */
1466
+
1467
+/** TODO */
1468
+struct msszdd_compressor {
1469
+  int dummy; 
1470
+};
1471
+
1472
+/** TODO */
1473
+struct msszdd_decompressor {
1474
+  int dummy; 
1475
+};
1476
+
1477
+/* --- support for KWAJ file format ---------------------------------------- */
1478
+
1479
+/** TODO */
1480
+struct mskwaj_compressor {
1481
+  int dummy; 
1482
+};
1483
+
1484
+/** TODO */
1485
+struct mskwaj_decompressor {
1486
+  int dummy; 
1487
+};
1488
+
1489
+#ifdef __cplusplus
1490
+};
1491
+#endif
1492
+
1493
+#endif
0 1494
new file mode 100644
... ...
@@ -0,0 +1,114 @@
0
+/* This file is part of libmspack.
1
+ * (C) 2003-2004 Stuart Caie.
2
+ *
3
+ * The deflate method was created by Phil Katz. MSZIP is equivalent to the
4
+ * deflate method.
5
+ *
6
+ * libmspack is free software; you can redistribute it and/or modify it under
7
+ * the terms of the GNU Lesser General Public License (LGPL) version 2.1
8
+ *
9
+ * For further details, see the file COPYING.LIB distributed with libmspack
10
+ */
11
+
12
+#ifndef MSPACK_MSZIP_H
13
+#define MSPACK_MSZIP_H 1
14
+
15
+/* MSZIP (deflate) compression / (inflate) decompression definitions */
16
+
17
+#define MSZIP_FRAME_SIZE          (32768) /* size of LZ history window */
18
+#define MSZIP_MAX_HUFFBITS        (16)    /* maximum huffman code length */
19
+#define MSZIP_LITERAL_MAXSYMBOLS  (288)   /* literal/length huffman tree */
20
+#define MSZIP_LITERAL_TABLEBITS   (9)
21
+#define MSZIP_DISTANCE_MAXSYMBOLS (32)    /* distance huffman tree */
22
+#define MSZIP_DISTANCE_TABLEBITS  (6)
23
+
24
+/* if there are less direct lookup entries than symbols, the longer
25
+ * code pointers will be <= maxsymbols. This must not happen, or we
26
+ * will decode entries badly */
27
+#if (1 << MSZIP_LITERAL_TABLEBITS) < (MSZIP_LITERAL_MAXSYMBOLS * 2)
28
+# define MSZIP_LITERAL_TABLESIZE (MSZIP_LITERAL_MAXSYMBOLS * 4)
29
+#else
30
+# define MSZIP_LITERAL_TABLESIZE ((1 << MSZIP_LITERAL_TABLEBITS) + \
31
+				  (MSZIP_LITERAL_MAXSYMBOLS * 2))
32
+#endif
33
+
34
+#if (1 << MSZIP_DISTANCE_TABLEBITS) < (MSZIP_DISTANCE_MAXSYMBOLS * 2)
35
+# define MSZIP_DISTANCE_TABLESIZE (MSZIP_DISTANCE_MAXSYMBOLS * 4)
36
+#else
37
+# define MSZIP_DISTANCE_TABLESIZE ((1 << MSZIP_DISTANCE_TABLEBITS) + \
38
+				  (MSZIP_DISTANCE_MAXSYMBOLS * 2))
39
+#endif
40
+
41
+struct mszipd_stream {
42
+  struct mspack_system *sys;            /* I/O routines          */
43
+  struct mspack_file   *input;          /* input file handle     */
44
+  struct mspack_file   *output;         /* output file handle    */
45
+  unsigned int window_posn;             /* offset within window  */
46
+
47
+  /* inflate() will call this whenever the window should be emptied. */
48
+  int (*flush_window)(struct mszipd_stream *, unsigned int);
49
+
50
+  int error, repair_mode, bytes_output;
51
+
52
+  /* I/O buffering */
53
+  unsigned char *inbuf, *i_ptr, *i_end, *o_ptr, *o_end;
54
+  unsigned int bit_buffer, bits_left, inbuf_size;
55
+
56
+
57
+  /* huffman code lengths */
58
+  unsigned char  LITERAL_len[MSZIP_LITERAL_MAXSYMBOLS];
59
+  unsigned char  DISTANCE_len[MSZIP_DISTANCE_MAXSYMBOLS];
60
+
61
+  /* huffman decoding tables */
62
+  unsigned short LITERAL_table [MSZIP_LITERAL_TABLESIZE];
63
+  unsigned short DISTANCE_table[MSZIP_DISTANCE_TABLESIZE];
64
+
65
+  /* 32kb history window */
66
+  unsigned char window[MSZIP_FRAME_SIZE];
67
+};
68
+
69
+/* allocates MS-ZIP decompression stream for decoding the given stream.
70
+ *
71
+ * - uses system->alloc() to allocate memory
72
+ *
73
+ * - returns NULL if not enough memory
74
+ *
75
+ * - input_buffer_size is how many bytes to use as an input bitstream buffer
76
+ *
77
+ * - if repair_mode is non-zero, errors in decompression will be skipped
78
+ *   and 'holes' left will be filled with zero bytes. This allows at least
79
+ *   a partial recovery of erroneous data.
80
+ */
81
+extern struct mszipd_stream *mszipd_init(struct mspack_system *system,
82
+					struct mspack_file *input,
83
+					struct mspack_file *output,
84
+					int input_buffer_size,
85
+					int repair_mode);
86
+
87
+/* decompresses, or decompresses more of, an MS-ZIP stream.
88
+ *
89
+ * - out_bytes of data will be decompressed and the function will return
90
+ *   with an MSPACK_ERR_OK return code.
91
+ *
92
+ * - decompressing will stop as soon as out_bytes is reached. if the true
93
+ *   amount of bytes decoded spills over that amount, they will be kept for
94
+ *   a later invocation of mszipd_decompress().
95
+ *
96
+ * - the output bytes will be passed to the system->write() function given in
97
+ *   mszipd_init(), using the output file handle given in mszipd_init(). More
98
+ *   than one call may be made to system->write()
99
+ *
100
+ * - MS-ZIP will read input bytes as necessary using the system->read()
101
+ *   function given in mszipd_init(), using the input file handle given in
102
+ *   mszipd_init(). This will continue until system->read() returns 0 bytes,
103
+ *   or an error.
104
+ */
105
+extern int mszipd_decompress(struct mszipd_stream *zip, off_t out_bytes);
106
+
107
+/* frees all stream associated with an MS-ZIP data stream
108
+ *
109
+ * - calls system->free() using the system pointer given in mszipd_init()
110
+ */
111
+void mszipd_free(struct mszipd_stream *zip);
112
+
113
+#endif
0 114
new file mode 100644
... ...
@@ -0,0 +1,652 @@
0
+/* This file is part of libmspack.
1
+ * (C) 2003-2004 Stuart Caie.
2
+ *
3
+ * The deflate method was created by Phil Katz. MSZIP is equivalent to the
4
+ * deflate method.
5
+ *
6
+ * libmspack is free software; you can redistribute it and/or modify it under
7
+ * the terms of the GNU Lesser General Public License (LGPL) version 2.1
8
+ *
9
+ * For further details, see the file COPYING.LIB distributed with libmspack
10
+ */
11
+
12
+/* MS-ZIP decompression implementation. */
13
+
14
+#if HAVE_CONFIG_H
15
+#include "clamav-config.h"
16
+#endif
17
+
18
+#include <mspack.h>
19
+#include <system.h>
20
+#include <mszip.h>
21
+
22
+/* match lengths for literal codes 257.. 285 */
23
+static const unsigned short lit_lengths[29] = {
24
+  3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27,
25
+  31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
26
+};
27
+
28
+/* match offsets for distance codes 0 .. 29 */
29
+static const unsigned short dist_offsets[30] = {
30
+  1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385,
31
+  513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577
32
+};
33
+
34
+/* extra bits required for literal codes 257.. 285 */
35
+static const unsigned char lit_extrabits[29] = {
36
+  0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2,
37
+  2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
38
+};
39
+
40
+/* extra bits required for distance codes 0 .. 29 */
41
+static const unsigned char dist_extrabits[30] = {
42
+  0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6,
43
+  6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13
44
+};
45
+
46
+/* the order of the bit length Huffman code lengths */
47
+static const unsigned char bitlen_order[19] = {
48
+  16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
49
+};
50
+
51
+/* ANDing with bit_mask[n] masks the lower n bits */
52
+static const unsigned short bit_mask[17] = {
53
+ 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
54
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
55
+};
56
+
57
+#define STORE_BITS do {                                                 \
58
+  zip->i_ptr      = i_ptr;                                              \
59
+  zip->i_end      = i_end;                                              \
60
+  zip->bit_buffer = bit_buffer;                                         \
61
+  zip->bits_left  = bits_left;                                          \
62
+} while (0)
63
+
64
+#define RESTORE_BITS do {                                               \
65
+  i_ptr      = zip->i_ptr;                                              \
66
+  i_end      = zip->i_end;                                              \
67
+  bit_buffer = zip->bit_buffer;                                         \
68
+  bits_left  = zip->bits_left;                                          \
69
+} while (0)
70
+
71
+#define ENSURE_BITS(nbits) do {                                         \
72
+  while (bits_left < (nbits)) {                                         \
73
+    if (i_ptr >= i_end) {                                               \
74
+      if (zipd_read_input(zip)) return zip->error;                      \
75
+      i_ptr = zip->i_ptr;                                               \
76
+      i_end = zip->i_end;                                               \
77
+    }                                                                   \
78
+    bit_buffer |= *i_ptr++ << bits_left; bits_left  += 8;               \
79
+  }                                                                     \
80
+} while (0)
81
+
82
+#define PEEK_BITS(nbits)   (bit_buffer & ((1<<(nbits))-1))
83
+#define PEEK_BITS_T(nbits) (bit_buffer & bit_mask[(nbits)])
84
+
85
+#define REMOVE_BITS(nbits) ((bit_buffer >>= (nbits)), (bits_left -= (nbits)))
86
+
87
+#define READ_BITS(val, nbits) do {                                      \
88
+  ENSURE_BITS(nbits); (val) = PEEK_BITS(nbits); REMOVE_BITS(nbits);     \
89
+} while (0)
90
+
91
+#define READ_BITS_T(val, nbits) do {                                    \
92
+  ENSURE_BITS(nbits); (val) = PEEK_BITS_T(nbits); REMOVE_BITS(nbits);   \
93
+} while (0)
94
+
95
+static int zipd_read_input(struct mszipd_stream *zip) {
96
+  int read = zip->sys->read(zip->input, &zip->inbuf[0], (int)zip->inbuf_size);
97
+  if (read < 0) return zip->error = MSPACK_ERR_READ;
98
+  zip->i_ptr = &zip->inbuf[0];
99
+  zip->i_end = &zip->inbuf[read];
100
+
101
+  return MSPACK_ERR_OK;
102
+}
103
+
104
+/* inflate() error codes */
105
+#define INF_ERR_BLOCKTYPE   (-1)  /* unknown block type                      */
106
+#define INF_ERR_COMPLEMENT  (-2)  /* block size complement mismatch          */
107
+#define INF_ERR_FLUSH       (-3)  /* error from flush_window() callback      */
108
+#define INF_ERR_BITBUF      (-4)  /* too many bits in bit buffer             */
109
+#define INF_ERR_SYMLENS     (-5)  /* too many symbols in blocktype 2 header  */
110
+#define INF_ERR_BITLENTBL   (-6)  /* failed to build bitlens huffman table   */
111
+#define INF_ERR_LITERALTBL  (-7)  /* failed to build literals huffman table  */
112
+#define INF_ERR_DISTANCETBL (-8)  /* failed to build distance huffman table  */
113
+#define INF_ERR_BITOVERRUN  (-9)  /* bitlen RLE code goes over table size    */
114
+#define INF_ERR_BADBITLEN   (-10) /* invalid bit-length code                 */
115
+#define INF_ERR_LITCODE     (-11) /* out-of-range literal code               */
116
+#define INF_ERR_DISTCODE    (-12) /* out-of-range distance code              */
117
+#define INF_ERR_DISTANCE    (-13) /* somehow, distance is beyond 32k         */
118
+#define INF_ERR_HUFFSYM     (-14) /* out of bits decoding huffman symbol     */
119
+
120
+/* make_decode_table(nsyms, nbits, length[], table[])
121
+ *
122
+ * This function was coded by David Tritscher. It builds a fast huffman
123
+ * decoding table out of just a canonical huffman code lengths table.
124
+ *
125
+ * NOTE: this is NOT identical to the make_decode_table() in lzxd.c. This
126
+ * one reverses the quick-lookup bit pattern. Bits are read MSB to LSB in LZX,
127
+ * but LSB to MSB in MSZIP.
128
+ *
129
+ * nsyms  = total number of symbols in this huffman tree.
130
+ * nbits  = any symbols with a code length of nbits or less can be decoded
131
+ *          in one lookup of the table.
132
+ * length = A table to get code lengths from [0 to nsyms-1]
133
+ * table  = The table to fill up with decoded symbols and pointers.
134
+ *
135
+ * Returns 0 for OK or 1 for error
136
+ */
137
+static int make_decode_table(unsigned int nsyms, unsigned int nbits,
138
+			     unsigned char *length, unsigned short *table)
139
+{
140
+  register unsigned int leaf, reverse, fill;
141
+  register unsigned short sym, next_sym;
142
+  register unsigned char bit_num;
143
+  unsigned int pos         = 0; /* the current position in the decode table */
144
+  unsigned int table_mask  = 1 << nbits;
145
+  unsigned int bit_mask    = table_mask >> 1; /* don't do 0 length codes */
146
+
147
+  /* fill entries for codes short enough for a direct mapping */
148
+  for (bit_num = 1; bit_num <= nbits; bit_num++) {
149
+    for (sym = 0; sym < nsyms; sym++) {
150
+      if (length[sym] != bit_num) continue;
151
+
152
+      /* reverse the significant bits */
153
+      fill = length[sym]; reverse = pos >> (nbits - fill); leaf = 0;
154
+      do {leaf <<= 1; leaf |= reverse & 1; reverse >>= 1;} while (--fill);
155
+
156
+      if((pos += bit_mask) > table_mask) return 1; /* table overrun */
157
+
158
+      /* fill all possible lookups of this symbol with the symbol itself */
159
+      fill = bit_mask; next_sym = 1 << bit_num;
160
+      do { table[leaf] = sym; leaf += next_sym; } while (--fill);
161
+    }
162
+    bit_mask >>= 1;
163
+  }
164
+
165
+  /* exit with success if table is now complete */
166
+  if (pos == table_mask) return 0;
167
+
168
+  /* mark all remaining table entries as unused */
169
+  for (sym = pos; sym < table_mask; sym++) {
170
+    reverse = sym; leaf = 0; fill = nbits;
171
+    do { leaf <<= 1; leaf |= reverse & 1; reverse >>= 1; } while (--fill);
172
+    table[leaf] = 0xFFFF;
173
+  }
174
+
175
+  /* where should the longer codes be allocated from? */
176
+  next_sym = ((table_mask >> 1) < nsyms) ? nsyms : (table_mask >> 1);
177
+
178
+  /* give ourselves room for codes to grow by up to 16 more bits.
179
+   * codes now start at bit nbits+16 and end at (nbits+16-codelength) */
180
+  pos <<= 16;
181
+  table_mask <<= 16;
182
+  bit_mask = 1 << 15;
183
+
184
+  for (bit_num = nbits+1; bit_num <= MSZIP_MAX_HUFFBITS; bit_num++) {
185
+    for (sym = 0; sym < nsyms; sym++) {
186
+      if (length[sym] != bit_num) continue;
187
+
188
+      /* leaf = the first nbits of the code, reversed */
189
+      reverse = pos >> 16; leaf = 0; fill = nbits;
190
+      do {leaf <<= 1; leaf |= reverse & 1; reverse >>= 1;} while (--fill);
191
+
192
+      for (fill = 0; fill < (bit_num - nbits); fill++) {
193
+	/* if this path hasn't been taken yet, 'allocate' two entries */
194
+	if (table[leaf] == 0xFFFF) {
195
+	  table[(next_sym << 1)     ] = 0xFFFF;
196
+	  table[(next_sym << 1) + 1 ] = 0xFFFF;
197
+	  table[leaf] = next_sym++;
198
+	}
199
+	/* follow the path and select either left or right for next bit */
200
+	leaf = (table[leaf] << 1) | ((pos >> (15 - fill)) & 1);
201
+      }
202
+      table[leaf] = sym;
203
+
204
+      if ((pos += bit_mask) > table_mask) return 1; /* table overflow */
205
+    }
206
+    bit_mask >>= 1;
207
+  }
208
+
209
+  /* full table? */
210
+  return (pos != table_mask) ? 1 : 0;
211
+}
212
+
213
+/* READ_HUFFSYM(tablename, var) decodes one huffman symbol from the
214
+ * bitstream using the stated table and puts it in var.
215
+ */
216
+#define READ_HUFFSYM(tbl, var) do {                                     \
217
+  /* huffman symbols can be up to 16 bits long */                       \
218
+  ENSURE_BITS(MSZIP_MAX_HUFFBITS);                                      \
219
+  /* immediate table lookup of [tablebits] bits of the code */          \
220
+  sym = zip->tbl##_table[PEEK_BITS(MSZIP_##tbl##_TABLEBITS)];		\
221
+  /* is the symbol is longer than [tablebits] bits? (i=node index) */   \
222
+  if (sym >= MSZIP_##tbl##_MAXSYMBOLS) {                                \
223
+    /* decode remaining bits by tree traversal */                       \
224
+    i = MSZIP_##tbl##_TABLEBITS - 1;					\
225
+    do {                                                                \
226
+      /* check next bit. error if we run out of bits before decode */	\
227
+      if (i++ > MSZIP_MAX_HUFFBITS) {					\
228
+        D(("out of bits in huffman decode"))                            \
229
+        return INF_ERR_HUFFSYM;                                         \
230
+      }                                                                 \
231
+      /* double node index and add 0 (left branch) or 1 (right) */	\
232
+      sym = zip->tbl##_table[(sym << 1) | ((bit_buffer >> i) & 1)];	\
233
+      /* while we are still in node indicies, not decoded symbols */    \
234
+    } while (sym >= MSZIP_##tbl##_MAXSYMBOLS);                          \
235
+  }                                                                     \
236
+  /* result */                                                          \
237
+  (var) = sym;                                                          \
238
+  /* look up the code length of that symbol and discard those bits */   \
239
+  i = zip->tbl##_len[sym];                                              \
240
+  REMOVE_BITS(i);                                                       \
241
+} while (0)
242
+
243
+static int zip_read_lens(struct mszipd_stream *zip) {
244
+  /* for the bit buffer and huffman decoding */
245
+  register unsigned int bit_buffer;
246
+  register int bits_left;
247
+  unsigned char *i_ptr, *i_end;
248
+
249
+  /* bitlen Huffman codes -- immediate lookup, 7 bit max code length */
250
+  unsigned short bl_table[(1 << 7)];
251
+  unsigned char bl_len[19];
252
+
253
+  unsigned char lens[MSZIP_LITERAL_MAXSYMBOLS + MSZIP_DISTANCE_MAXSYMBOLS];
254
+  unsigned int lit_codes, dist_codes, code, last_code=0, bitlen_codes, i, run;
255
+
256
+  RESTORE_BITS;
257
+
258
+  /* read the number of codes */
259
+  READ_BITS(lit_codes,    5); lit_codes    += 257;
260
+  READ_BITS(dist_codes,   5); dist_codes   += 1;
261
+  READ_BITS(bitlen_codes, 4); bitlen_codes += 4;
262
+  if (lit_codes  > MSZIP_LITERAL_MAXSYMBOLS)  return INF_ERR_SYMLENS;
263
+  if (dist_codes > MSZIP_DISTANCE_MAXSYMBOLS) return INF_ERR_SYMLENS;
264
+
265
+  /* read in the bit lengths in their unusual order */
266
+  for (i = 0; i < bitlen_codes; i++) READ_BITS(bl_len[bitlen_order[i]], 3);
267
+  while (i < 19) bl_len[bitlen_order[i++]] = 0;
268
+
269
+  /* create decoding table with an immediate lookup */
270
+  if (make_decode_table(19, 7, &bl_len[0], &bl_table[0])) {
271
+    return INF_ERR_BITLENTBL;
272
+  }
273
+
274
+  /* read literal / distance code lengths */
275
+  for (i = 0; i < (lit_codes + dist_codes); i++) {
276
+    /* single-level huffman lookup */
277
+    ENSURE_BITS(7);
278
+    code = bl_table[PEEK_BITS(7)];
279
+    REMOVE_BITS(bl_len[code]);
280
+
281
+    if (code < 16) lens[i] = last_code = code;
282
+    else {
283
+      switch (code) {
284
+      case 16: READ_BITS(run, 2); run += 3;  code = last_code; break;
285
+      case 17: READ_BITS(run, 3); run += 3;  code = 0;         break;
286
+      case 18: READ_BITS(run, 7); run += 11; code = 0;         break;
287
+      default: D(("bad code!: %u", code)) return INF_ERR_BADBITLEN;
288
+      }
289
+      if ((i + run) > (lit_codes + dist_codes)) return INF_ERR_BITOVERRUN;
290
+      while (run--) lens[i++] = code;
291
+      i--;
292
+    }
293
+  }
294
+
295
+  /* copy LITERAL code lengths and clear any remaining */
296
+  i = lit_codes;
297
+  zip->sys->copy(&lens[0], &zip->LITERAL_len[0], i);
298
+  while (i < MSZIP_LITERAL_MAXSYMBOLS) zip->LITERAL_len[i++] = 0;
299
+
300
+  i = dist_codes;
301
+  zip->sys->copy(&lens[lit_codes], &zip->DISTANCE_len[0], i);
302
+  while (i < MSZIP_DISTANCE_MAXSYMBOLS) zip->DISTANCE_len[i++] = 0;
303
+
304
+  STORE_BITS;
305
+  return 0;
306
+}
307
+
308
+/* a clean implementation of RFC 1951 / inflate */
309
+static int inflate(struct mszipd_stream *zip) {
310
+  unsigned int last_block, block_type, distance, length, this_run, i;
311
+
312
+  /* for the bit buffer and huffman decoding */
313
+  register unsigned int bit_buffer;
314
+  register int bits_left;
315
+  register unsigned short sym;
316
+  unsigned char *i_ptr, *i_end;
317
+
318
+  RESTORE_BITS;
319
+
320
+  do {
321
+    /* read in last block bit */
322
+    READ_BITS(last_block, 1);
323
+
324
+    /* read in block type */
325
+    READ_BITS(block_type, 2);
326
+    D(("block_type=%u last_block=%u", block_type, last_block))
327
+
328
+    if (block_type == 0) {
329
+      /* uncompressed block */
330
+      unsigned char lens_buf[4];
331
+
332
+      /* go to byte boundary */
333
+      i = bits_left & 7; REMOVE_BITS(i);
334
+
335
+      /* read 4 bytes of data, emptying the bit-buffer if necessary */
336
+      for (i = 0; (bits_left >= 8); i++) {
337
+	if (i == 4) return INF_ERR_BITBUF;
338
+	lens_buf[i] = PEEK_BITS(8);
339
+	REMOVE_BITS(8);
340
+      }
341
+      if (bits_left != 0) return INF_ERR_BITBUF;
342
+      while (i < 4) {
343
+	if (i_ptr >= i_end) {
344
+	  if (zipd_read_input(zip)) return zip->error;
345
+	  i_ptr = zip->i_ptr;
346
+	  i_end = zip->i_end;
347
+	}
348
+	lens_buf[i++] = *i_ptr++;
349
+      }
350
+
351
+      /* get the length and its complement */
352
+      length = lens_buf[0] | (lens_buf[1] << 8);
353
+      i      = lens_buf[2] | (lens_buf[3] << 8);
354
+      if (length != (~i & 0xFFFF)) return INF_ERR_COMPLEMENT;
355
+
356
+      /* read and copy the uncompressed data into the window */
357
+      while (length > 0) {
358
+	if (i_ptr >= i_end) {
359
+	  if (zipd_read_input(zip)) return zip->error;
360
+	  i_ptr = zip->i_ptr;
361
+	  i_end = zip->i_end;
362
+	}
363
+
364
+	this_run = length;
365
+	if (this_run > (unsigned int)(i_end - i_ptr)) this_run = i_end - i_ptr;
366
+	if (this_run > (MSZIP_FRAME_SIZE - zip->window_posn))
367
+	  this_run = MSZIP_FRAME_SIZE - zip->window_posn;
368
+
369
+	zip->sys->copy(i_ptr, &zip->window[zip->window_posn], this_run);
370
+	zip->window_posn += this_run;
371
+	i_ptr    += this_run;
372
+	length   -= this_run;
373
+
374
+	if (zip->window_posn == MSZIP_FRAME_SIZE) {
375
+	  if (zip->flush_window(zip, MSZIP_FRAME_SIZE)) return INF_ERR_FLUSH;
376
+	  zip->window_posn = 0;
377
+	}
378
+      }
379
+    }
380
+    else if ((block_type == 1) || (block_type == 2)) {
381
+      /* Huffman-compressed LZ77 block */
382
+      unsigned int window_posn, match_posn, code;
383
+
384
+      if (block_type == 1) {
385
+	/* block with fixed Huffman codes */
386
+	i = 0;
387
+	while (i < 144) zip->LITERAL_len[i++] = 8;
388
+	while (i < 256) zip->LITERAL_len[i++] = 9;
389
+	while (i < 280) zip->LITERAL_len[i++] = 7;
390
+	while (i < 288) zip->LITERAL_len[i++] = 8;
391
+	for (i = 0; i < 32; i++) zip->DISTANCE_len[i] = 5;
392
+      }
393
+      else {
394
+	/* block with dynamic Huffman codes */
395
+	STORE_BITS;
396
+	if ((i = zip_read_lens(zip))) return i;
397
+	RESTORE_BITS;
398
+      }
399
+
400
+      /* now huffman lengths are read for either kind of block, 
401
+       * create huffman decoding tables */
402
+      if (make_decode_table(MSZIP_LITERAL_MAXSYMBOLS, MSZIP_LITERAL_TABLEBITS,
403
+			    &zip->LITERAL_len[0], &zip->LITERAL_table[0]))
404
+      {
405
+	return INF_ERR_LITERALTBL;
406
+      }
407
+
408
+      if (make_decode_table(MSZIP_DISTANCE_MAXSYMBOLS,MSZIP_DISTANCE_TABLEBITS,
409
+			    &zip->DISTANCE_len[0], &zip->DISTANCE_table[0]))
410
+      {
411
+	return INF_ERR_DISTANCETBL;
412
+      }
413
+
414
+      /* decode forever until end of block code */
415
+      window_posn = zip->window_posn;
416
+      while (1) {
417
+	READ_HUFFSYM(LITERAL, code);
418
+	if (code < 256) {
419
+	  zip->window[window_posn++] = (unsigned char) code;
420
+	  if (window_posn == MSZIP_FRAME_SIZE) {
421
+	    if (zip->flush_window(zip, MSZIP_FRAME_SIZE)) return INF_ERR_FLUSH;
422
+	    window_posn = 0;
423
+	  }
424
+	}
425
+	else if (code == 256) {
426
+	  /* END OF BLOCK CODE: loop break point */
427
+	  break;
428
+	}
429
+	else {
430
+	  code -= 257;
431
+	  if (code > 29) return INF_ERR_LITCODE;
432
+	  READ_BITS_T(length, lit_extrabits[code]);
433
+	  length += lit_lengths[code];
434
+
435
+	  READ_HUFFSYM(DISTANCE, code);
436
+	  if (code > 30) return INF_ERR_DISTCODE;
437
+	  READ_BITS_T(distance, dist_extrabits[code]);
438
+	  distance += dist_offsets[code];
439
+
440
+	  /* match position is window position minus distance. If distance
441
+	   * is more than window position numerically, it must 'wrap
442
+	   * around' the frame size. */ 
443
+	  match_posn = ((distance > window_posn) ? MSZIP_FRAME_SIZE : 0)
444
+	    + window_posn - distance;
445
+
446
+	  /* copy match */
447
+	  if (length < 12) {
448
+	    /* short match, use slower loop but no loop setup code */
449
+	    while (length--) {
450
+	      zip->window[window_posn++] = zip->window[match_posn++];
451
+	      match_posn &= MSZIP_FRAME_SIZE - 1;
452
+
453
+	      if (window_posn == MSZIP_FRAME_SIZE) {
454
+		if (zip->flush_window(zip, MSZIP_FRAME_SIZE))
455
+		  return INF_ERR_FLUSH;
456
+		window_posn = 0;
457
+	      }
458
+	    }
459
+	  }
460
+	  else {
461
+	    /* longer match, use faster loop but with setup expense */
462
+	    unsigned char *runsrc, *rundest;
463
+	    do {
464
+	      this_run = length;
465
+	      if ((match_posn + this_run) > MSZIP_FRAME_SIZE)
466
+		this_run = MSZIP_FRAME_SIZE - match_posn;
467
+	      if ((window_posn + this_run) > MSZIP_FRAME_SIZE)
468
+		this_run = MSZIP_FRAME_SIZE - window_posn;
469
+
470
+	      rundest = &zip->window[window_posn]; window_posn += this_run;
471
+	      runsrc  = &zip->window[match_posn];  match_posn  += this_run;
472
+	      length -= this_run;
473
+	      while (this_run--) *rundest++ = *runsrc++;
474
+
475
+	      /* flush if necessary */
476
+	      if (window_posn == MSZIP_FRAME_SIZE) {
477
+		if (zip->flush_window(zip, MSZIP_FRAME_SIZE))
478
+		  return INF_ERR_FLUSH;
479
+		window_posn = 0;
480
+	      }
481
+	      if (match_posn == MSZIP_FRAME_SIZE) match_posn = 0;
482
+	    } while (length > 0);
483
+	  }
484
+
485
+	} /* else (code >= 257) */
486
+
487
+      } /* while (forever) -- break point at 'code == 256' */
488
+      zip->window_posn = window_posn;
489
+    }
490
+    else {
491
+      /* block_type == 3 -- bad block type */
492
+      return INF_ERR_BLOCKTYPE;
493
+    }
494
+  } while (!last_block);
495
+
496
+  /* flush the remaining data */
497
+  if (zip->window_posn) {
498
+    if (zip->flush_window(zip, zip->window_posn)) return INF_ERR_FLUSH;
499
+  }
500
+  STORE_BITS;
501
+
502
+  /* return success */
503
+  return 0;
504
+}
505
+
506
+/* inflate() calls this whenever the window should be flushed. As
507
+ * MSZIP only expands to the size of the window, the implementation used
508
+ * simply keeps track of the amount of data flushed, and if more than 32k
509
+ * is flushed, an error is raised.
510
+ */  
511
+static int mszipd_flush_window(struct mszipd_stream *zip,
512
+			       unsigned int data_flushed)
513
+{
514
+  zip->bytes_output += data_flushed;
515
+  if (zip->bytes_output > MSZIP_FRAME_SIZE) {
516
+    D(("overflow: %u bytes flushed, total is now %u",
517
+       data_flushed, zip->bytes_output))
518
+    return 1;
519
+  }
520
+  return 0;
521
+}
522
+
523
+struct mszipd_stream *mszipd_init(struct mspack_system *system,
524
+				  struct mspack_file *input,
525
+				  struct mspack_file *output,
526
+				  int input_buffer_size,
527
+				  int repair_mode)
528
+{
529
+  struct mszipd_stream *zip;
530
+
531
+  if (!system) return NULL;
532
+
533
+  input_buffer_size = (input_buffer_size + 1) & -2;
534
+  if (!input_buffer_size) return NULL;
535
+
536
+  /* allocate decompression state */
537
+  if (!(zip = system->alloc(system, sizeof(struct mszipd_stream)))) {
538
+    return NULL;
539
+  }
540
+
541
+  /* allocate input buffer */
542
+  zip->inbuf  = system->alloc(system, (size_t) input_buffer_size);
543
+  if (!zip->inbuf) {
544
+    system->free(zip);
545
+    return NULL;
546
+  }
547
+
548
+  /* initialise decompression state */
549
+  zip->sys             = system;
550
+  zip->input           = input;
551
+  zip->output          = output;
552
+  zip->inbuf_size      = input_buffer_size;
553
+  zip->error           = MSPACK_ERR_OK;
554
+  zip->repair_mode     = repair_mode;
555
+  zip->flush_window    = &mszipd_flush_window;
556
+
557
+  zip->i_ptr = zip->i_end = &zip->inbuf[0];
558
+  zip->o_ptr = zip->o_end = NULL;
559
+  zip->bit_buffer = 0; zip->bits_left = 0;
560
+  return zip;
561
+}
562
+
563
+int mszipd_decompress(struct mszipd_stream *zip, off_t out_bytes) {
564
+  /* for the bit buffer */
565
+  register unsigned int bit_buffer;
566
+  register int bits_left;
567
+  unsigned char *i_ptr, *i_end;
568
+
569
+  int i, state, error;
570
+
571
+  /* easy answers */
572
+  if (!zip || (out_bytes < 0)) return MSPACK_ERR_ARGS;
573
+  if (zip->error) return zip->error;
574
+
575
+  /* flush out any stored-up bytes before we begin */
576
+  i = zip->o_end - zip->o_ptr;
577
+  if ((off_t) i > out_bytes) i = (int) out_bytes;
578
+  if (i) {
579
+    if (zip->sys->write(zip->output, zip->o_ptr, i) != i) {
580
+      return zip->error = MSPACK_ERR_WRITE;
581
+    }
582
+    zip->o_ptr  += i;
583
+    out_bytes   -= i;
584
+  }
585
+  if (out_bytes == 0) return MSPACK_ERR_OK;
586
+
587
+
588
+  while (out_bytes > 0) {
589
+    /* unpack another block */
590
+    RESTORE_BITS;
591
+
592
+    /* skip to next read 'CK' header */
593
+    i = bits_left & 7; REMOVE_BITS(i); /* align to bytestream */
594
+    state = 0;
595
+    do {
596
+      READ_BITS(i, 8);
597
+      if (i == 'C') state = 1;
598
+      else if ((state == 1) && (i == 'K')) state = 2;
599
+      else state = 0;
600
+    } while (state != 2);
601
+
602
+    /* inflate a block, repair and realign if necessary */
603
+    zip->window_posn = 0;
604
+    zip->bytes_output = 0;
605
+    STORE_BITS;
606
+    if ((error = inflate(zip))) {
607
+      D(("inflate error %d", i))
608
+      if (zip->repair_mode) {
609
+	zip->sys->message(NULL, "MSZIP error, %u bytes of data lost.",
610
+			  MSZIP_FRAME_SIZE - zip->bytes_output);
611
+	for (i = zip->bytes_output; i < MSZIP_FRAME_SIZE; i++) {
612
+	  zip->window[i] = '\0';
613
+	}
614
+	zip->bytes_output = MSZIP_FRAME_SIZE;
615
+      }
616
+      else {
617
+	return zip->error = (error > 0) ? error : MSPACK_ERR_DECRUNCH;
618
+      }
619
+    }
620
+    zip->o_ptr = &zip->window[0];
621
+    zip->o_end = &zip->o_ptr[zip->bytes_output];
622
+
623
+    /* write a frame */
624
+    i = (out_bytes < (off_t)zip->bytes_output) ?
625
+      (int)out_bytes : zip->bytes_output;
626
+    if (zip->sys->write(zip->output, zip->o_ptr, i) != i) {
627
+      return zip->error = MSPACK_ERR_WRITE;
628
+    }
629
+
630
+    /* mspack errors (i.e. read errors) are fatal and can't be recovered */
631
+    if ((error > 0) && zip->repair_mode) return error;
632
+
633
+    zip->o_ptr  += i;
634
+    out_bytes   -= i;
635
+  }
636
+
637
+  if (out_bytes) {
638
+    D(("bytes left to output"))
639
+    return zip->error = MSPACK_ERR_DECRUNCH;
640
+  }
641
+  return MSPACK_ERR_OK;
642
+}
643
+
644
+void mszipd_free(struct mszipd_stream *zip) {
645
+  struct mspack_system *sys;
646
+  if (zip) {
647
+    sys = zip->sys;
648
+    sys->free(zip->inbuf);
649
+    sys->free(zip);
650
+  }
651
+}
0 652
new file mode 100644
... ...
@@ -0,0 +1,120 @@
0
+/* This file is part of libmspack.
1
+ * (C) 2003-2004 Stuart Caie.
2
+ *
3
+ * The Quantum method was created by David Stafford, adapted by Microsoft
4
+ * Corporation.
5
+ *
6
+ * libmspack is free software; you can redistribute it and/or modify it under
7
+ * the terms of the GNU Lesser General Public License (LGPL) version 2.1
8
+ *
9
+ * For further details, see the file COPYING.LIB distributed with libmspack
10
+ */
11
+
12
+#ifndef MSPACK_QTM_H
13
+#define MSPACK_QTM_H 1
14
+
15
+/* Quantum compression / decompression definitions */
16
+
17
+#define QTM_FRAME_SIZE (32768)
18
+
19
+struct qtmd_modelsym {
20
+  unsigned short sym, cumfreq;
21
+};
22
+
23
+struct qtmd_model {
24
+  int shiftsleft, entries;
25
+  struct qtmd_modelsym *syms;
26
+};
27
+
28
+struct qtmd_stream {
29
+  struct mspack_system *sys;      /* I/O routines                            */
30
+  struct mspack_file   *input;    /* input file handle                       */
31
+  struct mspack_file   *output;   /* output file handle                      */
32
+
33
+  unsigned char *window;          /* decoding window                         */
34
+  unsigned int window_size;       /* window size                             */
35
+  unsigned int window_posn;       /* decompression offset within window      */
36
+  unsigned int frame_start;       /* start of current frame within window    */
37
+
38
+  unsigned short H, L, C;         /* high/low/current: arith coding state    */
39
+  unsigned char header_read;      /* have we started decoding a new frame?   */
40
+
41
+  int error;
42
+
43
+  /* I/O buffers */
44
+  unsigned char *inbuf, *i_ptr, *i_end, *o_ptr, *o_end;
45
+  unsigned int  bit_buffer, inbuf_size;
46
+  unsigned char bits_left;
47
+
48
+  /* four literal models, each representing 64 symbols
49
+   * model0 for literals from   0 to  63 (selector = 0)
50
+   * model1 for literals from  64 to 127 (selector = 1)
51
+   * model2 for literals from 128 to 191 (selector = 2)
52
+   * model3 for literals from 129 to 255 (selector = 3) */
53
+  struct qtmd_model model0, model1, model2, model3;
54
+
55
+  /* three match models.
56
+   * model4 for match with fixed length of 3 bytes
57
+   * model5 for match with fixed length of 4 bytes
58
+   * model6 for variable length match, encoded with model6len model */
59
+  struct qtmd_model model4, model5, model6, model6len;
60
+
61
+  /* selector model. 0-6 to say literal (0,1,2,3) or match (4,5,6) */
62
+  struct qtmd_model model7;
63
+
64
+  /* symbol arrays for all models */
65
+  struct qtmd_modelsym m0sym[64 + 1];
66
+  struct qtmd_modelsym m1sym[64 + 1];
67
+  struct qtmd_modelsym m2sym[64 + 1];
68
+  struct qtmd_modelsym m3sym[64 + 1];
69
+  struct qtmd_modelsym m4sym[24 + 1];
70
+  struct qtmd_modelsym m5sym[36 + 1];
71
+  struct qtmd_modelsym m6sym[42 + 1], m6lsym[27 + 1];
72
+  struct qtmd_modelsym m7sym[7 + 1];
73
+};
74
+
75
+/* allocates Quantum decompression state for decoding the given stream.
76
+ *
77
+ * - returns NULL if window_bits is outwith the range 10 to 21 (inclusive).
78
+ *
79
+ * - uses system->alloc() to allocate memory
80
+ *
81
+ * - returns NULL if not enough memory
82
+ *
83
+ * - window_bits is the size of the Quantum window, from 1Kb (10) to 2Mb (21).
84
+ *
85
+ * - input_buffer_size is the number of bytes to use to store bitstream data.
86
+ */
87
+extern struct qtmd_stream *qtmd_init(struct mspack_system *system,
88
+				     struct mspack_file *input,
89
+				     struct mspack_file *output,
90
+				     int window_bits,
91
+				     int input_buffer_size);
92
+
93
+/* decompresses, or decompresses more of, a Quantum stream.
94
+ *
95
+ * - out_bytes of data will be decompressed and the function will return
96
+ *   with an MSPACK_ERR_OK return code.
97
+ *
98
+ * - decompressing will stop as soon as out_bytes is reached. if the true
99
+ *   amount of bytes decoded spills over that amount, they will be kept for
100
+ *   a later invocation of qtmd_decompress().
101
+ *
102
+ * - the output bytes will be passed to the system->write() function given in
103
+ *   qtmd_init(), using the output file handle given in qtmd_init(). More
104
+ *   than one call may be made to system->write()
105
+ *
106
+ * - Quantum will read input bytes as necessary using the system->read()
107
+ *   function given in qtmd_init(), using the input file handle given in
108
+ *   qtmd_init(). This will continue until system->read() returns 0 bytes,
109
+ *   or an error.
110
+ */
111
+extern int qtmd_decompress(struct qtmd_stream *qtm, off_t out_bytes);
112
+
113
+/* frees all state associated with a Quantum data stream
114
+ *
115
+ * - calls system->free() using the system pointer given in qtmd_init()
116
+ */
117
+void qtmd_free(struct qtmd_stream *qtm);
118
+
119
+#endif
0 120
new file mode 100644
... ...
@@ -0,0 +1,488 @@
0
+/* This file is part of libmspack.
1
+ * (C) 2003-2004 Stuart Caie.
2
+ *
3
+ * The Quantum method was created by David Stafford, adapted by Microsoft
4
+ * Corporation.
5
+ *
6
+ * This decompressor is based on an implementation by Matthew Russotto, used
7
+ * with permission.
8
+ *
9
+ * libmspack is free software; you can redistribute it and/or modify it under
10
+ * the terms of the GNU Lesser General Public License (LGPL) version 2.1
11
+ *
12
+ * For further details, see the file COPYING.LIB distributed with libmspack
13
+ */
14
+
15
+/* Quantum decompression implementation */
16
+
17
+/* This decompressor was researched and implemented by Matthew Russotto. It
18
+ * has since been tidied up by Stuart Caie. More information can be found at
19
+ * http://www.speakeasy.org/~russotto/quantumcomp.html
20
+ */
21
+
22
+#if HAVE_CONFIG_H
23
+#include "clamav-config.h"
24
+#endif
25
+
26
+#include <mspack.h>
27
+#include <system.h>
28
+#include <qtm.h>
29
+
30
+/* Quantum decompressor bitstream reading macros
31
+ *
32
+ * STORE_BITS        stores bitstream state in qtmd_stream structure
33
+ * RESTORE_BITS      restores bitstream state from qtmd_stream structure
34
+ * READ_BITS(var,n)  takes N bits from the buffer and puts them in var
35
+ * FILL_BUFFER       if there is room for another 16 bits, reads another
36
+ *                   16 bits from the input stream.
37
+ * PEEK_BITS(n)      extracts without removing N bits from the bit buffer
38
+ * REMOVE_BITS(n)    removes N bits from the bit buffer
39
+ *
40
+ * These bit access routines work by using the area beyond the MSB and the
41
+ * LSB as a free source of zeroes. This avoids having to mask any bits.
42
+ * So we have to know the bit width of the bitbuffer variable.
43
+ */
44
+
45
+#ifdef HAVE_LIMITS_H
46
+# include <limits.h>
47
+#endif
48
+#ifndef CHAR_BIT
49
+# define CHAR_BIT (8)
50
+#endif
51
+#define BITBUF_WIDTH (sizeof(unsigned int) * CHAR_BIT)
52
+
53
+#define STORE_BITS do {                                                 \
54
+  qtm->i_ptr      = i_ptr;                                              \
55
+  qtm->i_end      = i_end;                                              \
56
+  qtm->bit_buffer = bit_buffer;                                         \
57
+  qtm->bits_left  = bits_left;                                          \
58
+} while (0)
59
+
60
+#define RESTORE_BITS do {                                               \
61
+  i_ptr      = qtm->i_ptr;                                              \
62
+  i_end      = qtm->i_end;                                              \
63
+  bit_buffer = qtm->bit_buffer;                                         \
64
+  bits_left  = qtm->bits_left;                                          \
65
+} while (0)
66
+
67
+/* adds 16 bits to bit buffer, if there's space for the new bits */
68
+#define FILL_BUFFER do {                                                \
69
+  if (bits_left <= (BITBUF_WIDTH - 16)) {                               \
70
+    if (i_ptr >= i_end) {                                               \
71
+      if (qtmd_read_input(qtm)) return qtm->error;                      \
72
+      i_ptr = qtm->i_ptr;                                               \
73
+      i_end = qtm->i_end;                                               \
74
+    }                                                                   \
75
+    bit_buffer |= ((i_ptr[0] << 8) | i_ptr[1])                          \
76
+                  << (BITBUF_WIDTH - 16 - bits_left);                   \
77
+    bits_left  += 16;                                                   \
78
+    i_ptr      += 2;                                                    \
79
+  }                                                                     \
80
+} while (0)
81
+
82
+#define PEEK_BITS(n)   (bit_buffer >> (BITBUF_WIDTH - (n)))
83
+#define REMOVE_BITS(n) ((bit_buffer <<= (n)), (bits_left -= (n)))
84
+
85
+#define READ_BITS(val, bits) do {                                       \
86
+  (val) = 0;                                                            \
87
+  for (bits_needed = (bits); bits_needed > 0; bits_needed -= bit_run) { \
88
+    FILL_BUFFER;                                                        \
89
+    bit_run = (bits_left < bits_needed) ? bits_left : bits_needed;      \
90
+    (val) = ((val) << bit_run) | PEEK_BITS(bit_run);                    \
91
+    REMOVE_BITS(bit_run);                                               \
92
+  }                                                                     \
93
+} while (0)
94
+
95
+static int qtmd_read_input(struct qtmd_stream *qtm) {
96
+  int read = qtm->sys->read(qtm->input, &qtm->inbuf[0], (int)qtm->inbuf_size);
97
+  if (read < 0) return qtm->error = MSPACK_ERR_READ;
98
+
99
+  qtm->i_ptr = &qtm->inbuf[0];
100
+  qtm->i_end = &qtm->inbuf[read];
101
+  return MSPACK_ERR_OK;
102
+}
103
+
104
+/* Quantum static data tables:
105
+ *
106
+ * Quantum uses 'position slots' to represent match offsets.  For every
107
+ * match, a small 'position slot' number and a small offset from that slot
108
+ * are encoded instead of one large offset.
109
+ *
110
+ * position_base[] is an index to the position slot bases
111
+ *
112
+ * extra_bits[] states how many bits of offset-from-base data is needed.
113
+ *
114
+ * length_base[] and length_extra[] are equivalent in function, but are
115
+ * used for encoding selector 6 (variable length match) match lengths,
116
+ * instead of match offsets.
117
+ */
118
+static unsigned int  position_base[42];
119
+static unsigned char extra_bits[42], length_base[27], length_extra[27];
120
+
121
+static void qtmd_static_init() {
122
+  unsigned int i, offset;
123
+
124
+  for (i = 0, offset = 0; i < 42; i++) {
125
+    position_base[i] = offset;
126
+    extra_bits[i] = ((i < 2) ? 0 : (i - 2)) >> 1;
127
+    offset += 1 << extra_bits[i];
128
+  }
129
+
130
+  for (i = 0, offset = 0; i < 26; i++) {
131
+    length_base[i] = offset;
132
+    length_extra[i] = (i < 2 ? 0 : i - 2) >> 2;
133
+    offset += 1 << length_extra[i];
134
+  }
135
+  length_base[26] = 254; length_extra[26] = 0;
136
+}
137
+
138
+
139
+/* Arithmetic decoder:
140
+ * 
141
+ * GET_SYMBOL(model, var) fetches the next symbol from the stated model
142
+ * and puts it in var.
143
+ *
144
+ * If necessary, qtmd_update_model() is called.
145
+ */
146
+#define GET_SYMBOL(model, var) do {                                     \
147
+  range = ((H - L) & 0xFFFF) + 1;                                       \
148
+  symf = ((((C - L + 1) * model.syms[0].cumfreq)-1) / range) & 0xFFFF;  \
149
+                                                                        \
150
+  for (i = 1; i < model.entries; i++) {                                 \
151
+    if (model.syms[i].cumfreq <= symf) break;                           \
152
+  }                                                                     \
153
+  (var) = model.syms[i-1].sym;                                          \
154
+                                                                        \
155
+  range = (H - L) + 1;                                                  \
156
+  symf = model.syms[0].cumfreq;                                         \
157
+  H = L + ((model.syms[i-1].cumfreq * range) / symf) - 1;               \
158
+  L = L + ((model.syms[i].cumfreq   * range) / symf);                   \
159
+                                                                        \
160
+  do { model.syms[--i].cumfreq += 8; } while (i > 0);                   \
161
+  if (model.syms[0].cumfreq > 3800) qtmd_update_model(&model);          \
162
+                                                                        \
163
+  while (1) {                                                           \
164
+    if ((L & 0x8000) != (H & 0x8000)) {                                 \
165
+      if ((L & 0x4000) && !(H & 0x4000)) {                              \
166
+        /* underflow case */                                            \
167
+        C ^= 0x4000; L &= 0x3FFF; H |= 0x4000;                          \
168
+      }                                                                 \
169
+      else break;                                                       \
170
+    }                                                                   \
171
+    L <<= 1; H = (H << 1) | 1;                                          \
172
+    FILL_BUFFER;                                                        \
173
+    C  = (C << 1) | PEEK_BITS(1);                                       \
174
+    REMOVE_BITS(1);                                                     \
175
+  }                                                                     \
176
+} while (0)
177
+
178
+static void qtmd_update_model(struct qtmd_model *model) {
179
+  struct qtmd_modelsym tmp;
180
+  int i, j;
181
+
182
+  if (--model->shiftsleft) {
183
+    for (i = model->entries - 1; i >= 0; i--) {
184
+      /* -1, not -2; the 0 entry saves this */
185
+      model->syms[i].cumfreq >>= 1;
186
+      if (model->syms[i].cumfreq <= model->syms[i+1].cumfreq) {
187
+	model->syms[i].cumfreq = model->syms[i+1].cumfreq + 1;
188
+      }
189
+    }
190
+  }
191
+  else {
192
+    model->shiftsleft = 50;
193
+    for (i = 0; i < model->entries; i++) {
194
+      /* no -1, want to include the 0 entry */
195
+      /* this converts cumfreqs into frequencies, then shifts right */
196
+      model->syms[i].cumfreq -= model->syms[i+1].cumfreq;
197
+      model->syms[i].cumfreq++; /* avoid losing things entirely */
198
+      model->syms[i].cumfreq >>= 1;
199
+    }
200
+
201
+    /* now sort by frequencies, decreasing order -- this must be an
202
+     * inplace selection sort, or a sort with the same (in)stability
203
+     * characteristics */
204
+    for (i = 0; i < model->entries - 1; i++) {
205
+      for (j = i + 1; j < model->entries; j++) {
206
+	if (model->syms[i].cumfreq < model->syms[j].cumfreq) {
207
+	  tmp = model->syms[i];
208
+	  model->syms[i] = model->syms[j];
209
+	  model->syms[j] = tmp;
210
+	}
211
+      }
212
+    }
213
+
214
+    /* then convert frequencies back to cumfreq */
215
+    for (i = model->entries - 1; i >= 0; i--) {
216
+      model->syms[i].cumfreq += model->syms[i+1].cumfreq;
217
+    }
218
+  }
219
+}
220
+
221
+/* Initialises a model to decode symbols from [start] to [start]+[len]-1 */
222
+static void qtmd_init_model(struct qtmd_model *model,
223
+			    struct qtmd_modelsym *syms, int start, int len)
224
+{
225
+  int i;
226
+
227
+  model->shiftsleft = 4;
228
+  model->entries    = len;
229
+  model->syms       = syms;
230
+
231
+  for (i = 0; i <= len; i++) {
232
+    syms[i].sym     = start + i; /* actual symbol */
233
+    syms[i].cumfreq = len - i;   /* current frequency of that symbol */
234
+  }
235
+}
236
+
237
+
238
+/*-------- main Quantum code --------*/
239
+
240
+struct qtmd_stream *qtmd_init(struct mspack_system *system,
241
+			      struct mspack_file *input,
242
+			      struct mspack_file *output,
243
+			      int window_bits, int input_buffer_size)
244
+{
245
+  unsigned int window_size = 1 << window_bits;
246
+  struct qtmd_stream *qtm;
247
+  int i;
248
+
249
+  if (!system) return NULL;
250
+
251
+  /* Quantum supports window sizes of 2^10 (1Kb) through 2^21 (2Mb) */
252
+  if (window_bits < 10 || window_bits > 21) return NULL;
253
+
254
+  input_buffer_size = (input_buffer_size + 1) & -2;
255
+  if (input_buffer_size < 2) return NULL;
256
+
257
+  /* initialise static data */
258
+  qtmd_static_init();
259
+
260
+  /* allocate decompression state */
261
+  if (!(qtm = system->alloc(system, sizeof(struct qtmd_stream)))) {
262
+    return NULL;
263
+  }
264
+
265
+  /* allocate decompression window and input buffer */
266
+  qtm->window = system->alloc(system, (size_t) window_size);
267
+  qtm->inbuf  = system->alloc(system, (size_t) input_buffer_size);
268
+  if (!qtm->window || !qtm->inbuf) {
269
+    system->free(qtm->window);
270
+    system->free(qtm->inbuf);
271
+    system->free(qtm);
272
+    return NULL;
273
+  }
274
+
275
+  /* initialise decompression state */
276
+  qtm->sys         = system;
277
+  qtm->input       = input;
278
+  qtm->output      = output;
279
+  qtm->inbuf_size  = input_buffer_size;
280
+  qtm->window_size = window_size;
281
+  qtm->window_posn = 0;
282
+  qtm->frame_start = 0;
283
+  qtm->header_read = 0;
284
+  qtm->error       = MSPACK_ERR_OK;
285
+
286
+  qtm->i_ptr = qtm->i_end = &qtm->inbuf[0];
287
+  qtm->o_ptr = qtm->o_end = &qtm->window[0];
288
+  qtm->bits_left = 0;
289
+  qtm->bit_buffer = 0;
290
+
291
+  /* initialise arithmetic coding models
292
+   * - model 4    depends on window size, ranges from 20 to 24
293
+   * - model 5    depends on window size, ranges from 20 to 36
294
+   * - model 6pos depends on window size, ranges from 20 to 42
295
+   */
296
+  i = window_bits * 2;
297
+  qtmd_init_model(&qtm->model0,    &qtm->m0sym[0],   0, 64);
298
+  qtmd_init_model(&qtm->model1,    &qtm->m1sym[0],  64, 64);
299
+  qtmd_init_model(&qtm->model2,    &qtm->m2sym[0], 128, 64);
300
+  qtmd_init_model(&qtm->model3,    &qtm->m3sym[0], 192, 64);
301
+  qtmd_init_model(&qtm->model4,    &qtm->m4sym[0],   0, (i > 24) ? 24 : i);
302
+  qtmd_init_model(&qtm->model5,    &qtm->m5sym[0],   0, (i > 36) ? 36 : i);
303
+  qtmd_init_model(&qtm->model6,    &qtm->m6sym[0],   0, i);
304
+  qtmd_init_model(&qtm->model6len, &qtm->m6lsym[0],  0, 27);
305
+  qtmd_init_model(&qtm->model7,    &qtm->m7sym[0],   0, 7);
306
+
307
+  /* all ok */
308
+  return qtm;
309
+}
310
+
311
+int qtmd_decompress(struct qtmd_stream *qtm, off_t out_bytes) {
312
+  unsigned int frame_start, frame_end, window_posn, match_offset, range;
313
+  unsigned char *window, *i_ptr, *i_end, *runsrc, *rundest;
314
+  int i, j, selector, extra, sym, match_length;
315
+  unsigned short H, L, C, symf;
316
+
317
+  register unsigned int bit_buffer;
318
+  register unsigned char bits_left;
319
+  unsigned char bits_needed, bit_run;
320
+
321
+  /* easy answers */
322
+  if (!qtm || (out_bytes < 0)) return MSPACK_ERR_ARGS;
323
+  if (qtm->error) return qtm->error;
324
+
325
+  /* flush out any stored-up bytes before we begin */
326
+  i = qtm->o_end - qtm->o_ptr;
327
+  if ((off_t) i > out_bytes) i = (int) out_bytes;
328
+  if (i) {
329
+    if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
330
+      return qtm->error = MSPACK_ERR_WRITE;
331
+    }
332
+    qtm->o_ptr  += i;
333
+    out_bytes   -= i;
334
+  }
335
+  if (out_bytes == 0) return MSPACK_ERR_OK;
336
+
337
+  /* restore local state */
338
+  RESTORE_BITS;
339
+  window = qtm->window;
340
+  window_posn = qtm->window_posn;
341
+  frame_start = qtm->frame_start;
342
+  H = qtm->H;
343
+  L = qtm->L;
344
+  C = qtm->C;
345
+
346
+  /* while we do not have enough decoded bytes in reserve: */
347
+  while ((qtm->o_end - qtm->o_ptr) < out_bytes) {
348
+
349
+    /* read header if necessary. Initialises H, L and C */
350
+    if (!qtm->header_read) {
351
+      H = 0xFFFF; L = 0; READ_BITS(C, 16);
352
+      qtm->header_read = 1;
353
+    }
354
+
355
+    /* decode more, at most up to to frame boundary */
356
+    frame_end = window_posn + (out_bytes - (qtm->o_end - qtm->o_ptr));
357
+    if ((frame_start + QTM_FRAME_SIZE) < frame_end) {
358
+      frame_end = frame_start + QTM_FRAME_SIZE;
359
+    }
360
+
361
+    while (window_posn < frame_end) {
362
+      GET_SYMBOL(qtm->model7, selector);
363
+      if (selector < 4) {
364
+	struct qtmd_model *mdl = (selector == 0) ? &qtm->model0 :
365
+	                        ((selector == 1) ? &qtm->model1 :
366
+				((selector == 2) ? &qtm->model2 :
367
+                                                   &qtm->model3));
368
+	GET_SYMBOL((*mdl), sym);
369
+	window[window_posn++] = sym;
370
+      }
371
+      else {
372
+	switch (selector) {
373
+	case 4: /* selector 4 = fixed length match (3 bytes) */
374
+	  GET_SYMBOL(qtm->model4, sym);
375
+	  READ_BITS(extra, extra_bits[sym]);
376
+	  match_offset = position_base[sym] + extra + 1;
377
+	  match_length = 3;
378
+	  break;
379
+
380
+	case 5: /* selector 5 = fixed length match (4 bytes) */
381
+	  GET_SYMBOL(qtm->model5, sym);
382
+	  READ_BITS(extra, extra_bits[sym]);
383
+	  match_offset = position_base[sym] + extra + 1;
384
+	  match_length = 4;
385
+	  break;
386
+
387
+	case 6: /* selector 6 = variable length match */
388
+	  GET_SYMBOL(qtm->model6len, sym);
389
+	  READ_BITS(extra, length_extra[sym]);
390
+	  match_length = length_base[sym] + extra + 5;
391
+
392
+	  GET_SYMBOL(qtm->model6, sym);
393
+	  READ_BITS(extra, extra_bits[sym]);
394
+	  match_offset = position_base[sym] + extra + 1;
395
+	  break;
396
+
397
+	default:
398
+	  /* should be impossible, model7 can only return 0-6 */
399
+	  return qtm->error = MSPACK_ERR_DECRUNCH;
400
+	}
401
+
402
+	rundest = &window[window_posn];
403
+	i = match_length;
404
+	/* does match offset wrap the window? */
405
+	if (match_offset > window_posn) {
406
+	  /* j = length from match offset to end of window */
407
+	  j = match_offset - window_posn;
408
+	  if (j > (int) qtm->window_size) {
409
+	    D(("match offset beyond window boundaries"))
410
+	    return qtm->error = MSPACK_ERR_DECRUNCH;
411
+	  }
412
+	  runsrc = &window[qtm->window_size - j];
413
+	  if (j < i) {
414
+	    /* if match goes over the window edge, do two copy runs */
415
+	    i -= j; while (j-- > 0) *rundest++ = *runsrc++;
416
+	    runsrc = window;
417
+	  }
418
+	  while (i-- > 0) *rundest++ = *runsrc++;
419
+	}
420
+	else {
421
+	  runsrc = rundest - match_offset;
422
+	  while (i-- > 0) *rundest++ = *runsrc++;
423
+	}
424
+	window_posn += match_length;
425
+      }
426
+    } /* while (window_posn < frame_end) */
427
+
428
+    qtm->o_end = &window[window_posn];
429
+
430
+    /* another frame completed? */
431
+    if ((window_posn - frame_start) >= QTM_FRAME_SIZE) {
432
+      if ((window_posn - frame_start) != QTM_FRAME_SIZE) {
433
+	D(("overshot frame alignment"))
434
+	return qtm->error = MSPACK_ERR_DECRUNCH;
435
+      }
436
+
437
+      /* re-align input */
438
+      if (bits_left & 7) REMOVE_BITS(bits_left & 7);
439
+      do { READ_BITS(i, 8); } while (i != 0xFF);
440
+      qtm->header_read = 0;
441
+
442
+      /* window wrap? */
443
+      if (window_posn == qtm->window_size) {
444
+	/* flush all currently stored data */
445
+	i = (qtm->o_end - qtm->o_ptr);
446
+	if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
447
+	  return qtm->error = MSPACK_ERR_WRITE;
448
+	}
449
+	out_bytes -= i;
450
+	qtm->o_ptr = &window[0];
451
+	qtm->o_end = &window[0];
452
+	window_posn = 0;
453
+      }
454
+
455
+      frame_start = window_posn;
456
+    }
457
+
458
+  } /* while (more bytes needed) */
459
+
460
+  if (out_bytes) {
461
+    i = (int) out_bytes;
462
+    if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
463
+      return qtm->error = MSPACK_ERR_WRITE;
464
+    }
465
+    qtm->o_ptr += i;
466
+  }
467
+
468
+  /* store local state */
469
+  STORE_BITS;
470
+  qtm->window_posn = window_posn;
471
+  qtm->frame_start = frame_start;
472
+  qtm->H = H;
473
+  qtm->L = L;
474
+  qtm->C = C;
475
+
476
+  return MSPACK_ERR_OK;
477
+}
478
+
479
+void qtmd_free(struct qtmd_stream *qtm) {
480
+  struct mspack_system *sys;
481
+  if (qtm) {
482
+    sys = qtm->sys;
483
+    sys->free(qtm->window);
484
+    sys->free(qtm->inbuf);
485
+    sys->free(qtm);
486
+  }
487
+}
0 488
new file mode 100644
... ...
@@ -0,0 +1,251 @@
0
+/* This file is part of libmspack.
1
+ * (C) 2003-2004 Stuart Caie.
2
+ *
3
+ * libmspack is free software; you can redistribute it and/or modify it under
4
+ * the terms of the GNU Lesser General Public License (LGPL) version 2.1
5
+ *
6
+ * For further details, see the file COPYING.LIB distributed with libmspack
7
+ */
8
+
9
+#if HAVE_CONFIG_H
10
+#include "clamav-config.h"
11
+#endif
12
+
13
+#include <mspack.h>
14
+#include "others.h"
15
+
16
+int mspack_version(int entity) {
17
+  switch (entity) {
18
+  case MSPACK_VER_LIBRARY:
19
+  case MSPACK_VER_SYSTEM:
20
+  case MSPACK_VER_MSCABD:
21
+  case MSPACK_VER_MSCHMD:
22
+    return 1;
23
+  case MSPACK_VER_MSCABC:
24
+  case MSPACK_VER_MSCHMC:
25
+  case MSPACK_VER_MSLITD:
26
+  case MSPACK_VER_MSLITC:
27
+  case MSPACK_VER_MSHLPD:
28
+  case MSPACK_VER_MSHLPC:
29
+  case MSPACK_VER_MSSZDDD:
30
+  case MSPACK_VER_MSSZDDC:
31
+  case MSPACK_VER_MSKWAJD:
32
+  case MSPACK_VER_MSKWAJC:
33
+    return 0;
34
+  }
35
+  return -1;
36
+}
37
+
38
+int mspack_sys_selftest_internal(int offt_size) {
39
+  return (sizeof(off_t) == offt_size) ? MSPACK_ERR_OK : MSPACK_ERR_SEEK;
40
+}
41
+
42
+/* validates a system structure */
43
+int mspack_valid_system(struct mspack_system *sys) {
44
+  return (sys != NULL) && (sys->open != NULL) && (sys->close != NULL) &&
45
+    (sys->read != NULL) && (sys->write != NULL) && (sys->seek != NULL) &&
46
+    (sys->tell != NULL) && (sys->message != NULL) && (sys->alloc != NULL) &&
47
+    (sys->free != NULL) && (sys->copy != NULL) && (sys->null_ptr == NULL);
48
+}
49
+
50
+/* returns the length of a file opened for reading */
51
+int mspack_sys_filelen(struct mspack_system *system,
52
+		       struct mspack_file *file, off_t *length)
53
+{
54
+  off_t current;
55
+
56
+  if (!system || !file || !length) return MSPACK_ERR_OPEN;
57
+
58
+  /* get current offset */
59
+  current = system->tell(file);
60
+
61
+  /* seek to end of file */
62
+  if (system->seek(file, (off_t) 0, MSPACK_SYS_SEEK_END)) {
63
+    return MSPACK_ERR_SEEK;
64
+  }
65
+
66
+  /* get offset of end of file */
67
+  *length = system->tell(file);
68
+
69
+  /* seek back to original offset */
70
+  if (system->seek(file, current, MSPACK_SYS_SEEK_START)) {
71
+    return MSPACK_ERR_SEEK;
72
+  }
73
+
74
+  return MSPACK_ERR_OK;
75
+}
76
+
77
+
78
+
79
+/* definition of mspack_default_system -- if the library is compiled with
80
+ * MSPACK_NO_DEFAULT_SYSTEM, no default system will be provided. Otherwise,
81
+ * an appropriate default system (e.g. the standard C library, or some native
82
+ * API calls)
83
+ */
84
+
85
+#ifdef MSPACK_NO_DEFAULT_SYSTEM
86
+struct mspack_system *mspack_default_system = NULL;
87
+#else
88
+
89
+/* implementation of mspack_default_system for standard C library */
90
+
91
+#include <stdio.h>
92
+#include <stdlib.h>
93
+#include <string.h>
94
+#include <stdarg.h>
95
+
96
+struct mspack_file_p {
97
+  FILE *fh;
98
+  char *name;
99
+  int desc;
100
+};
101
+
102
+static struct mspack_file *msp_open(struct mspack_system *this,
103
+				    char *filename, int mode)
104
+{
105
+  struct mspack_file_p *fh;
106
+  char *fmode;
107
+
108
+  switch (mode) {
109
+  case MSPACK_SYS_OPEN_READ:   fmode = "rb";  break;
110
+  case MSPACK_SYS_OPEN_WRITE:  fmode = "wb";  break;
111
+  case MSPACK_SYS_OPEN_UPDATE: fmode = "r+b"; break;
112
+  case MSPACK_SYS_OPEN_APPEND: fmode = "ab";  break;
113
+  default: return NULL;
114
+  }
115
+
116
+  if ((fh = malloc(sizeof(struct mspack_file_p)))) {
117
+    fh->name = filename;
118
+    fh->desc = 0;
119
+    if ((fh->fh = fopen(filename, fmode))) return (struct mspack_file *) fh;
120
+    free(fh);
121
+  }
122
+  return NULL;
123
+}
124
+
125
+static struct mspack_file *msp_dopen(struct mspack_system *this,
126
+				    int desc, int mode)
127
+{
128
+  struct mspack_file_p *fh;
129
+  char *fmode;
130
+
131
+  switch (mode) {
132
+  case MSPACK_SYS_OPEN_READ:   fmode = "rb";  break;
133
+  case MSPACK_SYS_OPEN_WRITE:  fmode = "wb";  break;
134
+  case MSPACK_SYS_OPEN_UPDATE: fmode = "r+b"; break;
135
+  case MSPACK_SYS_OPEN_APPEND: fmode = "ab";  break;
136
+  default: return NULL;
137
+  }
138
+
139
+  if ((fh = malloc(sizeof(struct mspack_file_p)))) {
140
+    fh->name = "descriptor";
141
+    fh->desc = desc;
142
+    if ((fh->fh = fdopen(desc, fmode))) return (struct mspack_file *) fh;
143
+    free(fh);
144
+  }
145
+  return NULL;
146
+}
147
+
148
+static void msp_close(struct mspack_file *file) {
149
+  struct mspack_file_p *this = (struct mspack_file_p *) file;
150
+  if (this) {
151
+    fclose(this->fh);
152
+    free(this);
153
+  }
154
+}
155
+
156
+static int msp_read(struct mspack_file *file, void *buffer, int bytes) {
157
+  struct mspack_file_p *this = (struct mspack_file_p *) file;
158
+  if (this) {
159
+    size_t count = fread(buffer, 1, (size_t) bytes, this->fh);
160
+    if (!ferror(this->fh)) return (int) count;
161
+  }
162
+  return -1;
163
+}
164
+
165
+static int msp_write(struct mspack_file *file, void *buffer, int bytes) {
166
+  struct mspack_file_p *this = (struct mspack_file_p *) file;
167
+  if (this) {
168
+    size_t count = fwrite(buffer, 1, (size_t) bytes, this->fh);
169
+    if (!ferror(this->fh)) return (int) count;
170
+  }
171
+  return -1;
172
+}
173
+
174
+static int msp_seek(struct mspack_file *file, off_t offset, int mode) {
175
+  struct mspack_file_p *this = (struct mspack_file_p *) file;
176
+  if (this) {
177
+    switch (mode) {
178
+    case MSPACK_SYS_SEEK_START: mode = SEEK_SET; break;
179
+    case MSPACK_SYS_SEEK_CUR:   mode = SEEK_CUR; break;
180
+    case MSPACK_SYS_SEEK_END:   mode = SEEK_END; break;
181
+    default: return -1;
182
+    }
183
+#ifdef HAVE_FSEEKO
184
+    return fseeko(this->fh, offset, mode);
185
+#else
186
+    return fseek(this->fh, offset, mode);
187
+#endif
188
+  }
189
+  return -1;
190
+}
191
+
192
+static off_t msp_tell(struct mspack_file *file) {
193
+  struct mspack_file_p *this = (struct mspack_file_p *) file;
194
+#ifdef HAVE_FSEEKO
195
+  return (this) ? (off_t) ftello(this->fh) : 0;
196
+#else
197
+  return (this) ? (off_t) ftell(this->fh) : 0;
198
+#endif
199
+}
200
+
201
+static void msp_msg(struct mspack_file *file, char *format, ...) {
202
+  va_list ap;
203
+  char buff[512];
204
+
205
+  va_start(ap, format);
206
+  vsnprintf(buff, 512, format, ap);
207
+  va_end(ap);
208
+  cli_dbgmsg("libmspack: %s\n", buff);
209
+}
210
+
211
+static void *msp_alloc(struct mspack_system *this, size_t bytes) {
212
+#ifdef DEBUG
213
+  /* make uninitialised data obvious */
214
+  char *buf = malloc(bytes + 8);
215
+  if (buf) memset(buf, 0xDC, bytes);
216
+  *((size_t *)buf) = bytes;
217
+  return &buf[8];
218
+#else
219
+  return malloc(bytes);
220
+#endif
221
+}
222
+
223
+static void msp_free(void *buffer) {
224
+#ifdef DEBUG
225
+  char *buf = buffer;
226
+  size_t bytes;
227
+  if (buf) {
228
+    buf -= 8;
229
+    bytes = *((size_t *)buf);
230
+    /* make freed data obvious */
231
+    memset(buf, 0xED, bytes);
232
+    free(buf);
233
+  }
234
+#else
235
+  free(buffer);
236
+#endif
237
+}
238
+
239
+static void msp_copy(void *src, void *dest, size_t bytes) {
240
+  memcpy(dest, src, bytes);
241
+}
242
+
243
+static struct mspack_system msp_system = {
244
+  &msp_open, &msp_dopen, &msp_close, &msp_read,  &msp_write, &msp_seek,
245
+  &msp_tell, &msp_msg, &msp_alloc, &msp_free, &msp_copy, NULL
246
+};
247
+
248
+struct mspack_system *mspack_default_system = &msp_system;
249
+
250
+#endif
0 251
new file mode 100644
... ...
@@ -0,0 +1,58 @@
0
+/* This file is part of libmspack.
1
+ * (C) 2003-2004 Stuart Caie.
2
+ *
3
+ * libmspack is free software; you can redistribute it and/or modify it under
4
+ * the terms of the GNU Lesser General Public License (LGPL) version 2.1
5
+ *
6
+ * For further details, see the file COPYING.LIB distributed with libmspack
7
+ */
8
+
9
+#ifndef MSPACK_SYSTEM_H
10
+#define MSPACK_SYSTEM_H 1
11
+
12
+#ifdef DEBUG
13
+# include <stdio.h>
14
+# define D(x) do { printf("%s:%d (%s) ",__FILE__, __LINE__, __FUNCTION__); \
15
+                   printf x ; fputc('\n', stdout); fflush(stdout);} while (0);
16
+#else
17
+# define D(x)
18
+#endif
19
+
20
+/* endian-neutral reading of little-endian data */
21
+#define __egi32(a,n) ( (((a)[n+3]) << 24) | (((a)[n+2]) << 16) | \
22
+		       (((a)[n+1]) <<  8) |  ((a)[n+0])        )
23
+#define EndGetI64(a) ((((unsigned long long int) __egi32(a,4)) << 32) | \
24
+		      ((unsigned int) __egi32(a,0)))
25
+#define EndGetI32(a) __egi32(a,0)
26
+#define EndGetI16(a) ((((a)[1])<<8)|((a)[0]))
27
+
28
+/* endian-neutral reading of big-endian data */
29
+#define EndGetM32(a) ((((a)[0])<<24)|(((a)[1])<<16)|(((a)[2])<<8)|((a)[3]))
30
+#define EndGetM16(a) ((((a)[0])<<8)|((a)[1]))
31
+
32
+extern struct mspack_system *mspack_default_system;
33
+
34
+/* returns the length of a file opened for reading */
35
+extern int mspack_sys_filelen(struct mspack_system *system,
36
+			      struct mspack_file *file, off_t *length);
37
+
38
+/* validates a system structure */
39
+extern int mspack_valid_system(struct mspack_system *sys);
40
+
41
+/* inline memcmp() */
42
+static inline int memcmp(const void *s1, const void *s2, size_t n) {
43
+  unsigned char *c1 = (unsigned char *) s1;
44
+  unsigned char *c2 = (unsigned char *) s2;
45
+  if (n == 0) return 0;
46
+  while (--n && (*c1 == *c2)) c1++, c2++;
47
+  return *c1 - *c2;
48
+}
49
+
50
+/* inline strlen() */
51
+static inline size_t strlen(const char *s) {
52
+  const char *e = s;
53
+  while (*e) e++;
54
+  return e - s;
55
+}
56
+
57
+#endif