1 // "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
2 // Ken Silverman's official web site: "http://www.advsys.net/ken"
3 // See the included license file "BUILDLIC.TXT" for license info.
4 //
5 // This file has been modified from Ken Silverman's original release
6 // by Jonathon Fowler (jf@jonof.id.au)
7 
8 #include "compat.h"
9 #include "kplib.h"
10 
11 #include <utime.h>
12 
13 #define MAXFILES 4096
14 
15 static char buf[65536];
16 
17 static int numfiles, anyfiles4extraction;
18 static char marked4extraction[MAXFILES];
19 static char filelist[MAXFILES][16];
20 static int fileoffs[MAXFILES+1], fileleng[MAXFILES];
21 
findfiles(const char * dafilespec)22 void findfiles(const char *dafilespec)
23 {
24     char t[13];
25     int i;
26 
27     for(i=numfiles-1;i>=0;i--)
28     {
29         memcpy(t,filelist[i],12);
30         t[12] = 0;
31 
32         if (Bwildmatch(t,dafilespec)) {
33             marked4extraction[i] = 1;
34             anyfiles4extraction = 1;
35         }
36     }
37 }
38 
main(int argc,char ** argv)39 int main(int argc, char **argv)
40 {
41     int i, j, k, l, fil, fil2;
42     struct Bstat stbuf;
43 
44     int onlylist = (argc==2);
45 
46     if (argc < 2)
47     {
48         Bprintf("KEXTRACT <groupfile.grp> [@file or filespec...]           by Kenneth Silverman\n");
49         Bprintf("   This program extracts files from a previously grouped group file.\n");
50         Bprintf("   You can extract files using the ? and * wildcards.\n");
51         Bprintf("   Ex: kextract stuff.dat tiles000.art nukeland.map palette.dat\n");
52         Bprintf("         (stuff.dat is the group file, the rest are the files to extract)\n");
53         Bprintf("       kextract stuff.grp\n");
54         Bprintf("         (simply lists the contents of stuff.grp)\n");
55         return(0);
56     }
57 
58     if ((fil = Bopen(argv[1],BO_BINARY|BO_RDONLY,BS_IREAD)) == -1)
59     {
60         Bprintf("Error: %s could not be opened\n",argv[1]);
61         return(0);
62     }
63 
64     Bread(fil,buf,16);
65     if ((buf[0] != 'K') || (buf[1] != 'e') || (buf[2] != 'n') ||
66          (buf[3] != 'S') || (buf[4] != 'i') || (buf[5] != 'l') ||
67          (buf[6] != 'v') || (buf[7] != 'e') || (buf[8] != 'r') ||
68          (buf[9] != 'm') || (buf[10] != 'a') || (buf[11] != 'n'))
69     {
70         Bclose(fil);
71         Bprintf("Error: %s not a valid group file\n",argv[1]);
72         return(0);
73     }
74     numfiles = *((int*)&buf[12]); numfiles = B_LITTLE32(numfiles);
75 
76     Bread(fil,filelist,numfiles<<4);
77 
78     j = 0;
79     for(i=0;i<numfiles;i++)
80     {
81         k = *((int*)&filelist[i][12]); k = B_LITTLE32(k);
82         filelist[i][12] = 0;
83         fileoffs[i] = j;
84         j += k;
85     }
86     fileoffs[numfiles] = j;
87 
88     if (onlylist)
89     {
90         for (i=0; i<numfiles; i++)
91             Bprintf("%s\t\t%d\n", filelist[i], fileoffs[i+1]-fileoffs[i]);
92 
93         return 0;
94     }
95 
96     for(i=0;i<numfiles;i++) marked4extraction[i] = 0;
97 
98     anyfiles4extraction = 0;
99     for(i=argc-1;i>1;i--)
100     {
101         if (argv[i][0] == '@')
102         {
103             if ((fil2 = Bopen(&argv[i][1],BO_BINARY|BO_RDONLY,BS_IREAD)) != -1)
104             {
105                 l = Bread(fil2,buf,65536);
106                 j = 0;
107                 while ((j < l) && (buf[j] <= 32)) j++;
108                 while (j < l)
109                 {
110                     k = j;
111                     while ((k < l) && (buf[k] > 32)) k++;
112 
113                     buf[k] = 0;
114                     findfiles(&buf[j]);
115                     j = k+1;
116 
117                     while ((j < l) && (buf[j] <= 32)) j++;
118                 }
119                 Bclose(fil2);
120             }
121         }
122         else
123             findfiles(argv[i]);
124     }
125 
126     if (anyfiles4extraction == 0)
127     {
128         Bclose(fil);
129         Bprintf("No files found in group file with those names\n");
130         return(0);
131     }
132 
133     if (Bfstat(fil, &stbuf) == -1)
134         stbuf.st_mtime = 0;
135 
136     for(i=0;i<numfiles;i++)
137     {
138         if (marked4extraction[i] == 0) continue;
139 
140         fileleng[i] = fileoffs[i+1]-fileoffs[i];
141 
142         if ((fil2 = Bopen(filelist[i],BO_BINARY|BO_TRUNC|BO_CREAT|BO_WRONLY,BS_IREAD|BS_IWRITE)) == -1)
143         {
144             Bprintf("Error: Could not write to %s\n",filelist[i]);
145             continue;
146         }
147         Bprintf("Extracting %s...\n",filelist[i]);
148         Blseek(fil,fileoffs[i]+((numfiles+1)<<4),SEEK_SET);
149         for(j=0;j<fileleng[i];j+=65536)
150         {
151             k = min(fileleng[i]-j,65536);
152             Bread(fil,buf,k);
153             if (Bwrite(fil2,buf,k) < k)
154             {
155                 Bprintf("Write error (drive full?)\n");
156                 Bclose(fil2);
157                 Bclose(fil);
158                 return(0);
159             }
160         }
161         Bclose(fil2);
162 
163         if (stbuf.st_mtime != 0)
164         {
165             struct utimbuf times;
166 
167             times.modtime = stbuf.st_mtime;
168             times.actime = Btime();
169 
170             Butime(filelist[i],&times);
171         }
172     }
173     Bclose(fil);
174 
175     return 0;
176 }
177 
178