1 #ifdef HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <sys/stat.h>
8 #include <mspack.h>
9 #include <system.h>
10 
11 #if HAVE_FSEEKO
12 # define fseek fseeko
13 #endif
14 
15 #define BUF_SIZE (1024*4096)
16 char buf[BUF_SIZE];
17 
rip(char * fname,off_t offset,unsigned int length)18 void rip(char *fname, off_t offset, unsigned int length) {
19     static unsigned int counter = 1;
20     struct stat st_buf;
21     char outname[13];
22     FILE *in = NULL, *out = NULL;
23 
24     /* find an unused output filename */
25     do {
26         snprintf(outname, 13, "%08u.cab", counter++);
27     } while (stat(outname, &st_buf) == 0);
28 
29     printf("ripping %s offset %" LD " length %u to %s\n",
30            fname, offset, length, outname);
31 
32     if (!(in = fopen(fname, "rb"))) {
33         perror(fname);
34         goto cleanup;
35     }
36     if (!(out = fopen(outname, "wb"))) {
37         perror(outname);
38         goto cleanup;
39     }
40     if (fseek(in, offset, SEEK_SET)) {
41         fprintf(stderr, "%s: can't seek to cab offset %"LD"\n", fname, offset);
42         goto cleanup;
43     }
44     while (length) {
45         size_t run = (length > BUF_SIZE) ? BUF_SIZE : length;
46         size_t actual = fread(&buf[0], 1, run, in);
47         if (actual < run) {
48             fprintf(stderr, "%s: file %u bytes shorter than expected\n",
49                     fname, length - (unsigned int)(run - actual));
50             length = run = actual;
51         }
52         if (fwrite(&buf[0], 1, run, out) != run) {
53             perror(outname);
54             break;
55         }
56         length -= run;
57     }
58 
59 cleanup:
60     if (in) fclose(in);
61     if (out) fclose(out);
62 }
63 
main(int argc,char * argv[])64 int main(int argc, char *argv[]) {
65     struct mscab_decompressor *cabd;
66     struct mscabd_cabinet *cab, *c;
67     int err;
68 
69     MSPACK_SYS_SELFTEST(err);
70     if (err) return 0;
71 
72     if ((cabd = mspack_create_cab_decompressor(NULL))) {
73         cabd->set_param(cabd, MSCABD_PARAM_SALVAGE, 1);
74         for (argv++; *argv; argv++) {
75             if ((cab = cabd->search(cabd, *argv))) {
76                 for (c = cab; c; c = c->next) {
77                     rip(*argv, c->base_offset, c->length);
78                 }
79                 cabd->close(cabd, cab);
80             }
81         }
82         mspack_destroy_cab_decompressor(cabd);
83     }
84     return 0;
85 }
86