home *** CD-ROM | disk | FTP | other *** search
/ Total Destruction / Total_Destruction.iso / util / Quake2Tool.exe / Unpack.java < prev   
Encoding:
Java Source  |  1998-01-14  |  11.2 KB  |  456 lines

  1.  
  2. /*
  3.  * Unpack -- a completely non-object oriented utility...
  4.  *
  5.  */
  6.  
  7. // TODO:
  8. //
  9. // Unpack files that are selected in the list
  10. //
  11. // MODIFICATIONS
  12. // AUHTOR: RD Bettens - richmal@ozemail.com.au
  13. // DATE: Jan 1998
  14. //
  15. // PURPOSE: to provide a GUI for Quake 2 Unpack utility
  16. // 
  17. // Problems:
  18. // Whatever you do.....DON'T PRESS THE CANCEL BUTTONS
  19. //     ........ bad things happen
  20. // This file is pretty crude. It only has minimal exception handling. This will be looked at
  21. // for the next release
  22. //
  23.  
  24. import java.awt.*;
  25. import java.io.*;
  26.  
  27. class Unpack extends Panel {
  28.  
  29.     // globals
  30.     int            ident;
  31.     int            dirofs;
  32.     int            dirlen;
  33.     int            numLumps;
  34.     byte[]        name = new byte[56];
  35.     String        nameString;
  36.     int            filepos;
  37.     int            filelen;
  38.     RandomAccessFile    readLump;
  39.     DataInputStream        directory;
  40.     String        pakName;
  41.     String        pattern;
  42.  
  43.     // awt components
  44.     FileDialog pakFileDialog;
  45.     FileDialog outputFileDialog;
  46.  
  47.     TextField patternText;
  48.     List pakList;
  49.     String[] pakListSelections;
  50.     Button unpackButton;
  51.     Button listButton;
  52.     boolean finished;
  53.  
  54.  
  55.     public boolean isFinished()
  56.     {
  57.         return finished;
  58.     }
  59.  
  60.     public boolean action(Event e, Object o)
  61.     {
  62.         if (e.target instanceof Button)
  63.         {
  64.             System.out.println("Object is: "+o.toString());
  65.             if (o.toString().equals("List") ) {
  66.                 pattern = GetPattern();
  67.                 System.out.println("The pattern is: "+pattern);
  68.                 UnpackFile( pattern );
  69.                 finished = false;
  70.             } else if (o.toString().equals("Unpack") ) {
  71.                 try {
  72.                     pakListSelections = pakList.getSelectedItems();
  73.                     WriteFiles(); // write selected files to output directory
  74.                     finished = true;
  75.                 } catch (Exception exc) {
  76.                     exc.printStackTrace();
  77.                     return false;
  78.                 }
  79.             }
  80.             return true;
  81.         }
  82.         return false;
  83.     }
  84.  
  85.     protected boolean Selected(String item)
  86.         // returns true if item is a seleced item
  87.     {
  88.         for (int i=0; i < pakListSelections.length; i++) {
  89.             if (pakListSelections[i].equals(item) ) {
  90.                 return true;
  91.             }
  92.         }
  93.         return false;
  94.     }
  95.  
  96.     protected void SetOutputDirectory() 
  97.     {
  98.         outputFileDialog.show();
  99.         System.out.println("The output directory is: "+outputFileDialog.getDirectory());
  100.     }
  101.  
  102.     protected String GetPattern()
  103.     {
  104.         return patternText.getText().trim();
  105.     }
  106.  
  107.  
  108.     protected void ReadPakFile() 
  109.     {
  110.         try    {
  111.             // one stream to read the directory
  112.             directory = new DataInputStream(new FileInputStream(pakName));
  113.  
  114.             // another to read lumps
  115.             readLump = new RandomAccessFile(pakName, "r");
  116.  
  117.             // read the header
  118.             ident = intSwap(directory.readInt()); // 4 bytes
  119.             dirofs = intSwap(directory.readInt());// 4 bytes
  120.             dirlen = intSwap(directory.readInt());// 4 bytes
  121.  
  122.             if (ident != IDPAKHEADER) {
  123.                 System.out.println ( pakName + " is not a pakfile.");
  124.                 System.exit (1);
  125.             }
  126.  
  127.             // read the directory
  128.             directory.skipBytes (dirofs - 12);
  129.             numLumps = dirlen / 64;
  130.  
  131.             // beginning of lumps
  132.             // int lumpStart = 4 + 4 + 4 + (dirofs - 12);
  133.  
  134.             // define the pak file selections list
  135.             pakListSelections = new String[numLumps];
  136.             System.out.println (numLumps + " lumps in " + pakName);
  137.         } catch
  138.             (IOException e) {
  139.                 System.out.println("Invalid IO operation");
  140.                 e.printStackTrace();
  141.         }
  142.     }
  143.  
  144.     protected void UnpackFile(String pattern)
  145.     {
  146.         try {
  147.             directory = new DataInputStream(new FileInputStream(pakName));
  148.             directory.skipBytes(4 + 4 + 4 + (dirofs - 12));
  149.             // this should be the start of the lumps
  150.  
  151.             pakList.clear(); // clear list box
  152.  
  153.             for (int i=0; i< numLumps; i++) {
  154.                 // read file name
  155.                 directory.readFully(name);
  156.                 // get file position
  157.                 filepos = intSwap(directory.readInt());
  158.                 // get file length
  159.                 filelen = intSwap(directory.readInt());
  160.  
  161.                 // get the name of the file
  162.                 nameString = new String (name, 0);
  163.                 // chop to the first 0 byte
  164.                 nameString = nameString.substring (0, nameString.indexOf(0));
  165.  
  166.                 if (patternMatch (pattern, nameString) ) {
  167.                     // listing mode
  168.                     pakList.addItem(nameString); // add file name to list box
  169.                 }
  170.             }
  171.  
  172.         } catch (IOException e) {
  173.             System.err.println("Unexpected Exception");
  174.             e.printStackTrace();
  175.         }
  176.     }
  177.  
  178.     public void WriteFiles()
  179.     // extract and write file from pak file
  180.     {
  181.         try    {
  182.             RandomAccessFile log;
  183.             String logName;
  184.                 
  185.             directory = new DataInputStream(new FileInputStream(pakName));
  186.             directory.skipBytes(4 + 4 + 4 + (dirofs - 12));
  187.             // this should be the start of the lumps
  188.  
  189.             if (outputFileDialog.getFile() == null) {
  190.                 logName = outputFileDialog.getDirectory()+"output.log";
  191.             } else {
  192.                 logName = outputFileDialog.getDirectory() + outputFileDialog.getFile();
  193.             }
  194.             log = new RandomAccessFile(logName,"rw");
  195.             log.writeBytes("FILES CREATED:\r\n");
  196.  
  197.  
  198.             for (int i = 0 ; i < numLumps ; i++) {
  199.                 directory.readFully(name);
  200.                 filepos = intSwap(directory.readInt());
  201.                 filelen = intSwap(directory.readInt());
  202.  
  203.                 nameString = new String (name, 0);
  204.                 // chop to the first 0 byte
  205.                 nameString = nameString.substring (0, nameString.indexOf(0));
  206.  
  207.                 //if (patternMatch (pattern, nameString) ) {
  208.                 if ( Selected(nameString) ) { // if selected item
  209.                     File                writeFile;
  210.                     DataOutputStream    writeLump;
  211.                     byte[]                buffer = new byte[filelen];
  212.                     StringBuffer        fixedString;
  213.                     String                finalName;
  214.                     int                    index;
  215.                     
  216.                     // set log file
  217.                     
  218.                     log.writeBytes(nameString+"\r\n");
  219.  
  220.                     System.out.println ("Unpaking " + nameString + " " + filelen 
  221.                         + " bytes");
  222.  
  223.                     // load the lump
  224.                     readLump.seek(filepos);
  225.                     readLump.readFully(buffer);
  226.  
  227.                     // quake uses forward slashes, but java requires
  228.                     // they only by the host's seperator, which
  229.                     // varies from win to unix
  230.                     fixedString = 
  231.                         new StringBuffer (outputFileDialog.getDirectory() + nameString);
  232.                     for (index = 0 ; index < fixedString.length() ; index++) {
  233.                         if (fixedString.charAt(index) == '/') {
  234.                             fixedString.setCharAt(index, File.separatorChar);
  235.                         }
  236.                     }
  237.                     finalName = fixedString.toString ();
  238.  
  239.                     index = finalName.lastIndexOf(File.separatorChar);
  240.                     if (index != -1) {
  241.                         String        finalPath;
  242.                         File        writePath;
  243.  
  244.                         finalPath = finalName.substring(0, index);
  245.                         writePath = new File (finalPath);
  246.                         writePath.mkdirs();
  247.                     }
  248.  
  249.                     writeFile = new File (finalName);
  250.                     writeLump = new DataOutputStream ( new FileOutputStream(writeFile) );
  251.                     writeLump.write(buffer);
  252.                     writeLump.close();
  253.                 }
  254.             }
  255.             log.close();
  256.         } catch (IOException e) {
  257.             System.out.println ( e.toString() );
  258.         }
  259.     }
  260.  
  261.     protected void CleanUp() 
  262.     {
  263.         pakFileDialog.dispose();
  264.         outputFileDialog.dispose();
  265.         try {
  266.             directory.close();
  267.             readLump.close();
  268.         } catch (IOException e) { e.printStackTrace(); }
  269.     }
  270.  
  271.  
  272.  
  273.     static final protected int IDPAKHEADER    = (('K'<<24)+('C'<<16)+('A'<<8)+'P');
  274.  
  275.     protected int intSwap(int i) {
  276.         int        a, b, c, d;
  277.  
  278.         a = i & 255;
  279.         b = (i >> 8) & 255;
  280.         c = (i >> 16) & 255;
  281.         d = (i >> 24) & 255;
  282.  
  283.         return (a << 24) + (b << 16) + (c << 8) + d;
  284.     }
  285.  
  286.     protected boolean    patternMatch (String pattern, String s) {
  287.         int        index;
  288.         int        remaining;
  289.  
  290.         if (pattern.equals(s)) {
  291.             return true;
  292.         }
  293.  
  294.         // fairly lame single wildcard matching
  295.         index = pattern.indexOf('*');
  296.         if (index == -1) {
  297.             return false;
  298.         }
  299.         if (!pattern.regionMatches(0, s, 0, index)) {
  300.             return false;
  301.         }
  302.  
  303.         index += 1;    // skip the *
  304.         remaining = pattern.length() - index;
  305.         if (s.length() < remaining) {
  306.             return false;
  307.         }
  308.  
  309.         if (!pattern.regionMatches(index, s, s.length()-remaining, remaining)) {
  310.             return false;
  311.         }
  312.  
  313.         return true;
  314.     }
  315.  
  316.     static void usage() {
  317.         System.out.println ("Usage: unpack <packfile> <match> <basedir>");
  318.         System.out.println ("   or: unpack -list <packfile>");
  319.         System.out.println ("<match> may contain a single * wildcard");
  320.         System.exit (1);
  321.     }
  322.  
  323.     public void GetPakFile()
  324.     {
  325.         pakFileDialog.show();
  326.         // need to check if a valid Quake2 pak file
  327.         pakName = pakFileDialog.getDirectory()+pakFileDialog.getFile();
  328.         // System.out.println("Pak File is "+pakName);
  329.         ReadPakFile();
  330.     }
  331.  
  332.     public Unpack(Frame parent)
  333.     {
  334.         super();
  335.  
  336.         finished = false;
  337.  
  338.         resize(200,200);
  339.  
  340.         // get pak filename
  341.         pakFileDialog = new FileDialog(parent,"Pak File");
  342.         pakFileDialog.setFile("*.pak");
  343.  
  344.         outputFileDialog = new FileDialog(parent, "Output File");
  345.         outputFileDialog.setFile("output.log");
  346.  
  347.         patternText = new TextField("*",20);
  348.  
  349.         this.setLayout(new FlowLayout());
  350.         
  351.  
  352.         // list component to display the list of files
  353.         // can also select multiple files for unpacking
  354.         pakList = new List(10,true);
  355.  
  356.         this.add(pakList);
  357.         this.add(new Label("Pattern:"));
  358.         this.add(patternText);
  359.  
  360.         listButton = new Button("Unpack");
  361.         unpackButton = new Button("List");
  362.  
  363.         this.add(unpackButton);
  364.         this.add(listButton);
  365.  
  366. /*
  367.         try    {
  368.             // one stream to read the directory
  369.             directory = new DataInputStream(new FileInputStream(pakName));
  370.  
  371.             // another to read lumps
  372.             readLump = new RandomAccessFile(pakName, "r");
  373.  
  374.             // read the header
  375.             ident = intSwap(directory.readInt());
  376.             dirofs = intSwap(directory.readInt());
  377.             dirlen = intSwap(directory.readInt());
  378.  
  379.             if (ident != IDPAKHEADER) {
  380.                 System.out.println ( pakName + " is not a pakfile.");
  381.                 System.exit (1);
  382.             }
  383.  
  384.             // read the directory
  385.             directory.skipBytes (dirofs - 12);
  386.             numLumps = dirlen / 64;
  387.  
  388.             System.out.println (numLumps + " lumps in " + pakName);
  389.  
  390.             for (int i = 0 ; i < numLumps ; i++) {
  391.                 directory.readFully(name);
  392.                 filepos = intSwap(directory.readInt());
  393.                 filelen = intSwap(directory.readInt());
  394.  
  395.                 nameString = new String (name, 0);
  396.                 // chop to the first 0 byte
  397.                 nameString = nameString.substring (0, nameString.indexOf(0));
  398.  
  399.                 if (pattern == null) {
  400.                     // listing mode
  401.                     System.out.println (nameString + " : " + filelen + "bytes");
  402.                 } else if (patternMatch (pattern, nameString) ) {
  403.                     File                writeFile;
  404.                     DataOutputStream    writeLump;
  405.                     byte[]                buffer = new byte[filelen];
  406.                     StringBuffer        fixedString;
  407.                     String                finalName;
  408.                     int                    index;
  409.  
  410.                     System.out.println ("Unpaking " + nameString + " " + filelen 
  411.                         + " bytes");
  412.  
  413.                     // load the lump
  414.                     readLump.seek(filepos);
  415.                     readLump.readFully(buffer);
  416.  
  417.                     // quake uses forward slashes, but java requires
  418.                     // they only by the host's seperator, which
  419.                     // varies from win to unix
  420.                     fixedString = new StringBuffer (args[2] + File.separator + nameString);
  421.                     for (index = 0 ; index < fixedString.length() ; index++) {
  422.                         if (fixedString.charAt(index) == '/') {
  423.                             fixedString.setCharAt(index, File.separatorChar);
  424.                         }
  425.                     }
  426.                     finalName = fixedString.toString ();
  427.  
  428.                     index = finalName.lastIndexOf(File.separatorChar);
  429.                     if (index != -1) {
  430.                         String        finalPath;
  431.                         File        writePath;
  432.  
  433.                         finalPath = finalName.substring(0, index);
  434.                         writePath = new File (finalPath);
  435.                         writePath.mkdirs();
  436.                     }
  437.  
  438.                     writeFile = new File (finalName);
  439.                     writeLump = new DataOutputStream ( new FileOutputStream(writeFile) );
  440.                     writeLump.write(buffer);
  441.                     writeLump.close();
  442.                     
  443.                 }
  444.             }
  445.  
  446.             readLump.close();
  447.             directory.close();
  448.  
  449.         } catch (IOException e) {
  450.             System.out.println ( e.toString() );
  451.         }
  452. */
  453.     }
  454.  
  455. }
  456.