/ source / tools / src / kextract.cpp
kextract.cpp
  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  
 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  
 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      engineCreateAllocator();
 59  
 60      if ((fil = Bopen(argv[1],BO_BINARY|BO_RDONLY,BS_IREAD)) == -1)
 61      {
 62          Bprintf("Error: %s could not be opened\n",argv[1]);
 63          return(0);
 64      }
 65  
 66      Bread(fil,buf,16);
 67      if ((buf[0] != 'K') || (buf[1] != 'e') || (buf[2] != 'n') ||
 68           (buf[3] != 'S') || (buf[4] != 'i') || (buf[5] != 'l') ||
 69           (buf[6] != 'v') || (buf[7] != 'e') || (buf[8] != 'r') ||
 70           (buf[9] != 'm') || (buf[10] != 'a') || (buf[11] != 'n'))
 71      {
 72          Bclose(fil);
 73          Bprintf("Error: %s not a valid group file\n",argv[1]);
 74          return(0);
 75      }
 76      numfiles = *((int*)&buf[12]); numfiles = B_LITTLE32(numfiles);
 77  
 78      Bread(fil,filelist,numfiles<<4);
 79  
 80      j = 0;
 81      for(i=0;i<numfiles;i++)
 82      {
 83          k = *((int*)&filelist[i][12]); k = B_LITTLE32(k);
 84          filelist[i][12] = 0;
 85          fileoffs[i] = j;
 86          j += k;
 87      }
 88      fileoffs[numfiles] = j;
 89  
 90      if (onlylist)
 91      {
 92          for (i=0; i<numfiles; i++)
 93              Bprintf("%s\t\t%d\n", filelist[i], fileoffs[i+1]-fileoffs[i]);
 94  
 95          return 0;
 96      }
 97  
 98      for(i=0;i<numfiles;i++) marked4extraction[i] = 0;
 99  
100      anyfiles4extraction = 0;
101      for(i=argc-1;i>1;i--)
102      {
103          if (argv[i][0] == '@')
104          {
105              if ((fil2 = Bopen(&argv[i][1],BO_BINARY|BO_RDONLY,BS_IREAD)) != -1)
106              {
107                  l = Bread(fil2,buf,65536);
108                  j = 0;
109                  while ((j < l) && (buf[j] <= 32)) j++;
110                  while (j < l)
111                  {
112                      k = j;
113                      while ((k < l) && (buf[k] > 32)) k++;
114  
115                      buf[k] = 0;
116                      findfiles(&buf[j]);
117                      j = k+1;
118  
119                      while ((j < l) && (buf[j] <= 32)) j++;
120                  }
121                  Bclose(fil2);
122              }
123          }
124          else
125              findfiles(argv[i]);
126      }
127  
128      if (anyfiles4extraction == 0)
129      {
130          Bclose(fil);
131          Bprintf("No files found in group file with those names\n");
132          return(0);
133      }
134  
135      if (Bfstat(fil, &stbuf) == -1)
136          stbuf.st_mtime = 0;
137  
138      for(i=0;i<numfiles;i++)
139      {
140          if (marked4extraction[i] == 0) continue;
141  
142          fileleng[i] = fileoffs[i+1]-fileoffs[i];
143  
144          if ((fil2 = Bopen(filelist[i],BO_BINARY|BO_TRUNC|BO_CREAT|BO_WRONLY,BS_IREAD|BS_IWRITE)) == -1)
145          {
146              Bprintf("Error: Could not write to %s\n",filelist[i]);
147              continue;
148          }
149          Bprintf("Extracting %s...\n",filelist[i]);
150          Blseek(fil,fileoffs[i]+((numfiles+1)<<4),SEEK_SET);
151          for(j=0;j<fileleng[i];j+=65536)
152          {
153              k = min(fileleng[i]-j,65536);
154              Bread(fil,buf,k);
155              if (Bwrite(fil2,buf,k) < k)
156              {
157                  Bprintf("Write error (drive full?)\n");
158                  Bclose(fil2);
159                  Bclose(fil);
160                  return(0);
161              }
162          }
163          Bclose(fil2);
164  
165          if (stbuf.st_mtime != 0)
166          {
167              struct utimbuf times;
168  
169              times.modtime = stbuf.st_mtime;
170              times.actime = Btime();
171  
172              Butime(filelist[i],&times);
173          }
174      }
175      Bclose(fil);
176  
177      return 0;
178  }
179