/ source / tools / src / unpackssi.cpp
unpackssi.cpp
  1  /*
  2      .SSI File Unpacker
  3      Copyright (c) 2003 Jonathon Fowler
  4  
  5      This is a small program to extract the files from the .SSI package format
  6      which Sunstorm Interactive expansion packs for games like Duke Nukem 3D
  7      are distributed in. It is unsupported but should errors arise, bug reports
  8      are welcome.
  9  
 10      Update: 12 June 2003
 11  
 12      This updated version includes the ability to extract the SSI revision 2
 13      format as used in Duke Carribean.
 14  
 15  
 16      This program is distributed under the terms of the GNU General Public
 17      License Version 2 which can be found in the included GNU.txt file.
 18  
 19      This program is free software; you can redistribute it and/or modify
 20      it under the terms of the GNU General Public License as published by
 21      the Free Software Foundation; either version 2 of the License, or
 22      (at your option) any later version.
 23  
 24      This program is distributed in the hope that it will be useful,
 25      but WITHOUT ANY WARRANTY; without even the implied warranty of
 26      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 27      GNU General Public License for more details.
 28  
 29      You should have received a copy of the GNU General Public License
 30      along with this program; if not, write to the Free Software
 31      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 32  
 33  
 34      Jonathon Fowler
 35      jf@jonof.id.au
 36      http://www.jonof.id.au/
 37  */
 38  /*
 39      NOTE: This program does not fall under BUILDLIC.
 40  */
 41  
 42  #include "compat.h"
 43  
 44  int main(int argc, char **argv)
 45  {
 46      FILE *fp, *ofp;
 47      int32_t i,j=0;
 48      int32_t version;
 49      int32_t numfiles;
 50      unsigned char numchars;
 51      char title[33];
 52      char description[3][71];
 53      struct file {
 54          char name[13];
 55          int32_t length;
 56      } *filenames;
 57      char runfile[13] = "<unknown>";
 58      char buf[1024];
 59      int32_t mode=0, param;
 60  
 61      puts("unpackssi - .SSI File Unpacker\n"
 62           "Copyright (c) 2003 Jonathon Fowler\n"
 63           "This software is distributed under the terms of the GNU General Public License.");
 64  
 65      if (argc<2) {
 66          puts("\nUsage: unpackssi [-l] <ssifile.ssi> [ssifile2.ssi ...]");
 67          puts("  Unpacks the contents of an SSI file (like those which Sunstorm Interactive");
 68          puts("  expansion packs for Duke Nukem 3D are distributed in) to the current");
 69          puts("  directory. NOTE: Any files which already exist and have the same name as the");
 70          puts("  files contained in the SSI file will be overwritten when extracting.");
 71          puts("\nSwitches:");
 72          puts("  -l  List files (no extraction)\n");
 73          return -1;
 74      } else {
 75          param = 1;
 76          if (argv[1][0] == '-') {
 77              param++;
 78              switch (argv[1][1]) {
 79                  case 'l': mode = 1; break;
 80                  default: printf("Unrecognised switch: %c.\n", argv[1][1]); break;
 81              }
 82          }
 83      }
 84  
 85      while (param < argc) {
 86          puts("");
 87  
 88          fp = fopen(argv[param],"rb");
 89          if (!fp) return -2;
 90  
 91          fread(&version, 4, 1, fp);
 92          if (version != 1 && version != 2) {
 93              fclose(fp);
 94              puts("Error: Unrecognized SSI version.");
 95              return -1;
 96          }
 97  
 98          printf("File is SSI Version %i\n", version);
 99  
100          fread(&numfiles, 4, 1, fp);
101  
102          fread(&numchars, 1, 1, fp);
103          if (numchars > 32) numchars = 32;
104          fread(title, 32, 1, fp);
105          title[numchars] = 0;
106  
107          if (version == 2) {
108              fread(&numchars, 1, 1, fp);
109              if (numchars > 12) numchars = 12;
110              fread(runfile, 12, 1, fp);
111              runfile[numchars] = 0;
112          }
113  
114          for (i=0;i<3;i++) {
115              fread(&numchars, 1, 1, fp);
116              if (numchars > 70) numchars = 70;
117              fread(description[i], 70, 1, fp);
118              description[i][numchars] = 0;
119          }
120  
121          filenames = (struct file *)malloc(sizeof(struct file) * numfiles);
122          if (!filenames) {
123              fclose(fp);
124              puts("Error: Failed allocating memory for file index.");
125              return -2;
126          }
127  
128          for (i=0;i<numfiles;i++) {
129              fread(&numchars, 1, 1, fp);
130              if (numchars > 12) numchars = 12;
131              fread(filenames[i].name, 12, 1, fp);
132              filenames[i].name[numchars] = 0;
133  
134              fread(&filenames[i].length, 4, 1, fp);
135  
136              // seek past some stuff I can't seem to fully decipher at the moment
137              fseek(fp, 34+1+69, SEEK_CUR);
138          }
139  
140          printf("File:           %s\n"
141                 "Package Title:  %s\n"
142                 "Description:    %s\n"
143                 "                %s\n"
144                 "                %s\n"
145                 "Run Filename:   %s\n\n"
146                 , argv[param], title, description[0], description[1], description[2], runfile);
147  
148          if (mode == 1) {
149              j=0;
150              puts("File listing:");
151          }
152  
153          for (i=0;i<numfiles;i++) {
154              if (mode == 0) {
155                  ofp = fopen(filenames[i].name, "wb");
156                  if (!ofp) {
157                      printf("Error: Failed creating %s. Unpack operation cancelled.\n", filenames[i].name);
158                      break;
159                  }
160  
161                  printf("Unpacking %s (%i bytes)...", filenames[i].name, filenames[i].length);
162  
163                  for (j=filenames[i].length; j>1024; j-=1024) {
164                      fread(buf, 1024, 1, fp);
165                      fwrite(buf, 1024, 1, ofp);
166                  }
167                  if (j) {
168                      fread(buf, j, 1, fp);
169                      fwrite(buf, j, 1, ofp);
170                  }
171  
172                  fclose(ofp);
173                  puts("done");
174              } else if (mode == 1) {
175                  printf(" %-12s   %i bytes\n", filenames[i].name, filenames[i].length);
176                  j += filenames[i].length;
177              }
178          }
179  
180          if (mode == 1) {
181              puts("");
182              printf(" %i files, %i bytes\n", numfiles, j);
183          }
184  
185          fclose(fp);
186          free(filenames);
187  
188          param++;
189      }
190  
191      return 0;
192  }