expack.cc

Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) 2000-2001  The Exult Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 #ifdef HAVE_CONFIG_H
00020 #  include <config.h>
00021 #endif
00022 
00023 #ifndef ALPHA_LINUX_CXX
00024 #  include <unistd.h>
00025 #  include <fstream>
00026 #  include <cstdio>
00027 #  include <cstdlib>
00028 #  include <cstring>
00029 #endif
00030 #include <iostream>
00031 #include <iomanip>
00032 #include <vector>
00033 #include <string>
00034 #include "U7file.h"
00035 #include "Flex.h"
00036 #include "utils.h"
00037 #include "databuf.h"
00038 #include "crc.h"
00039 #include "exceptions.h"
00040 
00041 using std::atoi;
00042 using std::cerr;
00043 using std::cout;
00044 using std::endl;
00045 using std::exit;
00046 using std::FILE;
00047 using std::ifstream;
00048 using std::ofstream;
00049 using std::size_t;
00050 using std::strrchr;
00051 using std::strncpy;
00052 using std::strncat;
00053 using std::strlen;
00054 using std::vector;
00055 using std::string;
00056 
00057 enum Arch_mode { NONE, LIST, EXTRACT, CREATE, ADD, RESPONSE };
00058 
00059 bool is_text_file(const char *fname)
00060 {
00061   int len = strlen(fname);
00062 
00063   // only if the filename is greater than 4 chars
00064   if (len > 4 && fname[len-4] == '.' &&
00065     (fname[len-3] == 't' || fname[len-3] == 'T') &&
00066     (fname[len-2] == 'x' || fname[len-2] == 'X') &&
00067     (fname[len-1] == 't' || fname[len-1] == 'T'))
00068   {
00069     return true;
00070   }
00071 
00072   return false;
00073 }
00074 
00075 bool is_null_entry(const char *fname)
00076 {
00077   int len = strlen(fname);
00078 
00079   if (len >= 4 && fname[len-4] == 'N' && fname[len-3] == 'U' &&
00080           fname[len-2] == 'L' && fname[len-1] == 'L')
00081     return true;
00082 
00083   return false;
00084 
00085 }
00086 
00087 void set_mode(Arch_mode &mode, Arch_mode new_mode)
00088 {
00089   if(mode!=NONE) {
00090     cerr << "Error: cannot specify multiple modes" << endl;
00091     exit(1);
00092   } else
00093     mode = new_mode;
00094 }
00095 
00096 // Converts all .'s to _'s
00097 void make_header_name(char *filename)
00098 {
00099   int i = strlen (filename);
00100 
00101   while (i--) if (filename[i] == '.') filename[i] = '_';
00102     else if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':') break;
00103 }
00104 
00105 // Makes a name uppercase
00106 void make_uppercase (char *name)
00107 {
00108   int i = strlen (name);
00109 
00110   while (i--) if (name[i] >= 'a' && name[i] <= 'z') name[i] -= 'a' - 'A';
00111 }
00112 
00113 // strips a path from a filename
00114 void strip_path (char *filename)
00115 {
00116   int i = strlen (filename);
00117 
00118   while (i--)
00119   {
00120     if (filename[i] == '\\' || filename[i] == '/' || filename[i] == ':')
00121       break;
00122   }
00123 
00124   // Has a path
00125   if (i >= 0)
00126   {
00127     int j = 0;
00128 
00129     for (i++, j = 0; filename[j+i]; j++)
00130       filename[j] = filename[j+i];
00131 
00132     filename[j] = 0;
00133   }
00134 }
00135 
00136 long get_file_size(const char *fname)
00137 {
00138   if (is_null_entry(fname)) 
00139     return 0; // an empty entry
00140 
00141   const char *mode = "rb";
00142   bool text = is_text_file(fname);
00143   if (text)
00144     mode = "r";
00145 
00146   FILE *fp;
00147   try {
00148     fp = U7open (fname, mode);
00149   } catch (const file_open_exception& e) {
00150     cerr << e.what() << endl;
00151     exit(1);
00152   }
00153 
00154   long len = 0;
00155   if (!text)
00156   {
00157     fseek(fp, 0, SEEK_END);
00158     len = ftell(fp);
00159   }
00160   else while (fgetc(fp) != EOF)
00161     len++;
00162 
00163   fclose(fp);
00164   return len;
00165 }
00166 
00167 
00168 // This getline() accepts any kind of endline on any platform
00169 // (So it will accept windows linefeeds in linux, and vice versa)
00170 void getline(ifstream& file, char* buf, int size)
00171 {
00172   int i = 0;
00173   char c;
00174   file.get(c);
00175 
00176   while (i < size-1 && (c>=' ' || c=='\t') && file.good()) {
00177     buf[i++] = c;
00178     file.get(c);
00179   }
00180   buf[i] = '\0'; // terminator
00181 
00182   while (!(file.peek()>=' ' || file.peek()=='\t') && file.good())
00183     file.get(c);
00184 }
00185 
00186 
00187 #ifdef MACOS
00188 
00189 int mac_main(int argc, char **argv);
00190 
00191 int main()
00192 {
00193   const int mac_argc = 3;
00194   char  *mac_argv[mac_argc] =
00195     {
00196       "expack",
00197       "-i",
00198       "flx.in"
00199     };
00200     
00201   mac_main( mac_argc, mac_argv );
00202 
00203   char  *mac_argv2[mac_argc] =
00204     {
00205       "expack",
00206       "-i",
00207       "bg/flx.in"
00208     };
00209     
00210   mac_main( mac_argc, mac_argv2 );
00211 
00212   char  *mac_argv3[mac_argc] =
00213     {
00214       "expack",
00215       "-i",
00216       "si/flx.in"
00217     };
00218     
00219   mac_main( mac_argc, mac_argv3 );
00220 }
00221 
00222 
00223 int mac_main(int argc, char **argv)
00224 #else
00225 int main(int argc, char **argv)
00226 #endif
00227 {
00228   Arch_mode mode = NONE;
00229   char fname[1024];
00230   char hname[1024];
00231   char hprefix[1024];
00232   char ext[] = "u7o";
00233   int index;
00234   vector<string>  file_names;
00235     hname[0] = 0;
00236 
00237   if(argc>2) {
00238     strncpy(fname, argv[2], 1024);
00239     if((argv[1][0]=='-')&&(strlen(argv[1])==2)) {
00240       switch(argv[1][1]) {
00241       case 'i':
00242         {
00243           char temp[1024];
00244           char path_prefix[1024];
00245           
00246           ifstream respfile;
00247           char *slash = strrchr(fname, '/');
00248           if(slash) {
00249             int len = slash-fname+1;
00250             strncpy(path_prefix, fname, len);
00251             path_prefix[len] = 0;
00252           } else
00253             path_prefix[0] = 0;
00254 
00255           set_mode(mode,RESPONSE);
00256           try {
00257             U7open(respfile, fname, true);
00258           } catch (const file_open_exception& e) {
00259             cerr << e.what() << endl;
00260             exit(1);
00261           }
00262           
00263           // Read the output file name
00264           getline(respfile, temp, 1024);
00265           strncpy(fname, path_prefix, 1024);
00266           strncat(fname, temp, 1024);
00267 
00268           // Header file name
00269           strncpy (hprefix, temp, 1024);
00270           make_header_name(hprefix);
00271           strncpy (hname, path_prefix, 1024);
00272           strncat (hname, hprefix, 1024);
00273           strncat (hname, ".h", 1024);
00274           strip_path (hprefix);
00275           make_uppercase (hprefix);
00276 
00277           while(respfile.good()) {
00278             getline(respfile, temp, 1024);
00279             if(strlen(temp)>0) {
00280               char temp2[1024];
00281               strncpy(temp2, path_prefix,1024);
00282               strncat(temp2, temp, 1024);
00283               file_names.push_back(temp2);
00284             }
00285           }
00286           respfile.close();
00287         }
00288         break;
00289       case 'l':
00290         set_mode(mode,LIST);
00291         break;
00292       case 'x':
00293         set_mode(mode,EXTRACT);
00294         break;
00295       case 'c':
00296         {
00297         for(int i=0;i<argc-3;i++) {
00298           file_names.push_back(argv[i+3]);
00299         }
00300         set_mode(mode,CREATE);
00301         break;
00302         }
00303       case 'a':
00304         set_mode(mode,ADD);
00305         break;
00306       default:
00307         mode = NONE;
00308         break;
00309             }
00310     }
00311   }
00312   
00313   switch(mode) {
00314   case LIST:
00315     {
00316       if(argc!=3)
00317         break;
00318       U7FileManager fm;
00319       U7file *f = fm.get_file_object(fname);
00320       int count = f->number_of_objects();
00321       cout << "Archive: " << fname << endl;
00322       cout << "Type: " << f->get_archive_type() << endl;
00323       cout << "Size: " << count << endl;
00324       cout << "-------------------------" << endl;
00325       for(int i=0; i<count; i++) {
00326         char *buf;
00327         size_t len;
00328     
00329         buf = f->retrieve(i, len);
00330         cout << i << "\t" << len << endl;
00331         delete [] buf;
00332       }
00333     }
00334         break;
00335     case EXTRACT:
00336     {
00337       if(argc==4) {
00338         U7object f(fname,atoi(argv[3]));
00339         int nobjs = f.number_of_objects();
00340         int n = atoi(argv[3]);
00341         if (n >= nobjs) {
00342           cerr << "Obj. #(" << n <<
00343             ") is too large.  ";
00344           cerr << "Flex size is " << 
00345             nobjs << '.' << endl;
00346           exit(1);
00347         }
00348         char outfile[32];
00349         snprintf(outfile,32,"%d.%s", n, ext);
00350         f.retrieve(outfile);  // may throw!
00351       } else {
00352         U7FileManager fm;
00353         U7file *f = fm.get_file_object(fname);
00354         int count = f->number_of_objects();
00355         for(index=0; index<count; index++) {
00356           U7object o(fname,index);
00357           char outfile[32];
00358           snprintf(outfile,32,"%d.%s",index,ext);
00359           o.retrieve(outfile);
00360         }
00361         delete f;
00362       }
00363     }
00364     break;
00365   case RESPONSE:
00366   case CREATE:
00367     {
00368       ofstream flex;
00369       try {
00370         U7open(flex, fname);
00371       } catch (const file_open_exception& e) {
00372         cerr << e.what() << endl;
00373         exit(1);
00374       }
00375 
00376       char hline[1024];
00377       ofstream header;
00378       if (!hname[0]) {  // Need header name.
00379         strncpy (hprefix, fname, 1024);
00380         make_header_name(hprefix);
00381         strncat (hname, hprefix, 1024);
00382         strncat (hname, ".h", 1024);
00383       }   
00384       try {
00385         U7open(header, hname, true);
00386       } catch (const file_open_exception& e) {
00387         cerr << e.what() << endl;
00388         exit(1);
00389       }
00390 
00391       // The FLEX title
00392       Flex_writer writer(flex, "Exult Archive", file_names.size());
00393 
00394       // The beginning of the header
00395       header << "// Header for \"" << fname << "\" Created by expack" << std::endl << std::endl;
00396       header << "// DO NOT MODIFY" << std::endl << std::endl;
00397       header << "#ifndef " << hprefix << "_INCLUDED" << std::endl;
00398       header << "#define " << hprefix << "_INCLUDED" << std::endl << std::endl;
00399 
00400       // The files
00401         {
00402         for(int i=0; i<file_names.size(); i++) {
00403           int fsize = get_file_size(file_names[i].c_str());
00404           if(fsize) {
00405             ifstream infile;
00406             try {
00407               U7open(infile, file_names[i].c_str(), is_text_file(file_names[i].c_str()));
00408             } catch (const file_open_exception& e) {
00409               cerr << e.what() << endl;
00410               exit(1);
00411             }
00412             StreamDataSource ifs(&infile);
00413             char *buf = new char[fsize];
00414             ifs.read(buf, fsize);
00415             flex.write(buf, fsize);
00416             delete [] buf;
00417             infile.close();
00418 
00419             strncpy (hline, file_names[i].c_str(), 1024);
00420             strip_path(hline);
00421             make_header_name(hline);
00422             make_uppercase(hline);
00423             header << "#define\t" << hprefix << "_" << hline << "\t\t" << i << std::endl;
00424           }
00425         writer.mark_section_done();
00426         }
00427       }
00428       if (!writer.close())
00429         cerr << "Error writing " << fname << endl;
00430 
00431       uint32 crc32val = crc32_syspath(fname);
00432       header << std::endl << "#define\t" << hprefix << "_CRC32\t0x";
00433       header << std::hex << crc32val << std::dec << "U" << std::endl;
00434 
00435       header << std::endl << "#endif" << std::endl << std::endl;
00436       header.close();
00437       
00438     }
00439     break;
00440   default:
00441     cout << "Usage:" << endl
00442        << argv[0] << " -[l|x|c] file [index]" << endl
00443        << argv[0] << " -i indexfile" << endl;
00444     break;
00445   }
00446   return 0;
00447 }
00448 

Generated on Mon Jul 9 14:42:50 2007 for ExultEngine by  doxygen 1.5.1