gt:                     String fpath2 = fpath.substring(baseDir.length());
context: /*
   * Copyright 2008-present, David Karnok & Contributors
   * The file is part of the Open Imperium Galactica project.
   *
   * The code should be distributed under the LGPL license.
   * See http://www.gnu.org/licenses/lgpl.html for details.
   */
  
  package hu.openig.tools;
  
  import hu.openig.launcher.Launcher;
  import hu.openig.model.Configuration;
  import hu.openig.utils.Exceptions;
  import hu.openig.utils.IOUtils;
  import hu.openig.utils.XElement;
  
  import java.awt.Font;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.io.BufferedOutputStream;
  import java.io.File;
  import java.io.FileFilter;
  import java.io.FileInputStream;
  import java.io.FileOutputStream;
  import java.io.FilenameFilter;
  import java.io.IOException;
  import java.security.DigestInputStream;
  import java.security.MessageDigest;
  import java.security.NoSuchAlgorithmException;
  import java.text.SimpleDateFormat;
  import java.util.Date;
  import java.util.Locale;
  import java.util.Map;
  import java.util.concurrent.ConcurrentHashMap;
  import java.util.concurrent.ConcurrentMap;
  import java.util.concurrent.ExecutorService;
  import java.util.concurrent.Executors;
  import java.util.concurrent.TimeUnit;
  import java.util.zip.ZipEntry;
  import java.util.zip.ZipOutputStream;
  
  import javax.swing.BoxLayout;
  import javax.swing.JButton;
  import javax.swing.JCheckBox;
  import javax.swing.JFrame;
  import javax.swing.JPanel;
  import javax.swing.JScrollPane;
  import javax.swing.JTextArea;
  import javax.swing.SwingUtilities;
  import javax.swing.SwingWorker;
  import javax.xml.stream.XMLStreamException;
  
  /**
   * Utility program to package the executable JAR file and upgrade packs for image+data.
   * @author akarnokd
   */
  public final class PackageStuff {
      /** Utility class. */
      private PackageStuff() {
  
      }
      /** The separator. */
      static String sep = File.separator;
      /**
       * Build the graphics/data patch file.
       * @param version the version number in the file
       * @return the digest
       */
      static String buildImages(String version) {
          String result = "";
          String fileName = "install/open-ig-images-" + version + ".zip";
          try (ZipOutputStream zout = new ZipOutputStream(
                      new BufferedOutputStream(
                              new FileOutputStream(fileName), 1024 * 1024))) {
              zout.setLevel(9);
              processDirectory("." + sep + "images" + sep + "", "." + sep + "images", zout, null);
          } catch (IOException ex) {
              Exceptions.add(ex);
          }
          try {
              result += computeDigest(fileName);
          } catch (IOException ex) {
              Exceptions.add(ex);
          }
          return result;
      }
      /**
       * Build the graphics/data patch file.
       * @param version the version number in the file
       * @return the digest
       */
      static String buildData(String version) {
          String result = "";
          String fileName = "install/open-ig-upgrade-" + version + "2.zip";
          try (ZipOutputStream zout = new ZipOutputStream(
                      new BufferedOutputStream(
                              new FileOutputStream(fileName), 1024 * 1024))) {
              zout.setLevel(9);
              processDirectory("." + sep + "data" + sep + "", "." + sep + "data", zout, null);
          } catch (IOException ex) {
              Exceptions.add(ex);
          }
          try {
              result += computeDigest(fileName);
          } catch (IOException ex) {
              Exceptions.add(ex);
          }
          return result;
      }
      /**
       * Build the game's runnable jar.
       * @param version the target version
       * @return the digest
       */
      static String buildGame(String version) {
          String fileName = "install/open-ig-" + version + ".jar";
          try (ZipOutputStream zout = new ZipOutputStream(
                  new BufferedOutputStream(
                          new FileOutputStream(fileName), 1024 * 1024))) {
              zout.setLevel(9);
              processDirectory("." + sep + "bin" + sep + "", "." + sep + "bin", zout, new FilenameFilter() {
  
                  @Override
                  public boolean accept(File dir, String name) {
                      name = name.toLowerCase(Locale.ENGLISH);
                      String d = dir.toString().replace('\\', '/');
                      if (!d.endsWith("/")) {
                          d += "/";
                      }
                      d += name;
                      return !name.contains("splash_medium")
                              && !name.contains("launcher_background")
                              && !d.contains("/launcher");
                  }
              });
              addFile("META-INF/MANIFEST.MF", "META-INF/MANIFEST.MF", zout);
          } catch (IOException ex) {
              Exceptions.add(ex);
          }
          try {
              return computeDigest(fileName);
          } catch (IOException ex) {
              Exceptions.add(ex);
          }
          return "";
      }
      /**
       * Compute the SHA1 digest of the given file.
       * @param fileName the filename
       * @return the digest string + the filename
       * @throws IOException on error
       */
      static String computeDigest(String fileName) throws IOException {
          try (FileInputStream fis = new FileInputStream(fileName);
              DigestInputStream din = new DigestInputStream(fis, MessageDigest.getInstance("SHA1"))) {
              byte[] buffer = new byte[8192];
              while (true) {
                  if (din.read(buffer) < 0) {
                      break;
                  }
              }
              byte[] digest = din.getMessageDigest().digest();
              StringBuilder sb = new StringBuilder();
              for (byte b : digest) {
                  sb.append(String.format("%02X", b & 0xFF));
              }
              sb.append(" ").append(fileName).append("\r\n");
              return sb.toString();
          } catch (NoSuchAlgorithmException ex) {
              Exceptions.add(ex);
          }
          return "";
      }
      /**
       * Build the launcher file.
       * @return the digest
       */
      static String buildLauncher() {
          String fileName = "open-ig-launcher.jar";
          try (ZipOutputStream zout = new ZipOutputStream(
                  new BufferedOutputStream(
                          new FileOutputStream(fileName), 1024 * 1024))) {
              zout.setLevel(9);
              processDirectory("." + sep + "bin" + sep + "", "." + sep + "bin", zout, new FilenameFilter() {
                  @Override
                  public boolean accept(File dir, String name) {
                      String d = dir.toString().replace('\\', '/');
                      if (!d.endsWith("/")) {
                          d += "/";
                      }
                      d += name;
                      return d.contains("hu/openig/launcher")
  
                              || d.contains("hu/openig/utils/Exceptions")
                              || d.contains("hu/openig/utils/XElement")
                              || d.contains("hu/openig/utils/IOUtils")
                              || d.contains("hu/openig/utils/Parallels")
                              || d.contains("hu/openig/utils/ImageUtils")
                              || d.contains("hu/openig/utils/ConsoleWatcher")
                              || d.contains("hu/openig/gfx/checkmark_grayscale.png")
                              || d.contains("hu/openig/gfx/checkmark.png")
                              || d.contains("hu/openig/gfx/button_medium.png")
                              || d.contains("hu/openig/gfx/button_medium_pressed.png")
                              || d.contains("hu/openig/gfx/launcher_background.png")
                              || d.contains("hu/openig/gfx/hungarian.png")
                              || d.contains("hu/openig/gfx/english.png")
                              || d.contains("hu/openig/gfx/german.png")
                              || d.contains("hu/openig/gfx/french.png")
                              || d.contains("hu/openig/gfx/spanish.png")
                              || d.contains("hu/openig/gfx/russian.png")
                              || d.contains("hu/openig/gfx/loading.gif")
                              || d.contains("hu/openig/gfx/down.png")
                              || d.contains("hu/openig/ui/IGButton")
                              || d.contains("hu/openig/ui/IGCheckBox")
                              || d.contains("hu/openig/render/RenderTools")
                              || d.contains("hu/openig/render/GenericMediumButton")
                              || d.contains("hu/openig/render/GenericButtonRenderer")
                              || d.contains("hu/openig/core/Func0");
                  }
              });
              addFile("META-INF/MANIFEST.MF", "META-INF/MANIFEST.MF.launcher", zout);
          } catch (IOException ex) {
              Exceptions.add(ex);
          }
          try {
              return computeDigest(fileName);
          } catch (IOException ex) {
              Exceptions.add(ex);
          }
          return "";
      }
      /**
       * Add the given fileName to the zip stream with the given entry name.
       * @param entryName the entry name
       * @param fileName the file name and path
       * @param zout the output stream
       * @throws IOException on error
       */
      static void addFile(String entryName, String fileName, ZipOutputStream zout)
      throws IOException {
          ZipEntry mf = new ZipEntry(entryName);
          File mfm = new File(fileName);
          if (mfm.canRead()) {
              mf.setSize(mfm.length());
              mf.setTime(mfm.lastModified());
              zout.putNextEntry(mf);
              zout.write(IOUtils.load(mfm));
          } else {
              throw new RuntimeException("File not found: " + mfm.toString());
          }
      }
      /**
       * Process the contents of the given directory.
       * @param baseDir the base directory
       * @param currentDir the current directory
       * @param zout the output stream
       * @param filter the optional file filter
       * @throws IOException on error
       */
      static void processDirectory(String baseDir, String currentDir, ZipOutputStream zout,
              FilenameFilter filter) throws IOException {
          File[] files = new File(currentDir).listFiles(new FileFilter() {
              @Override
              public boolean accept(File pathname) {
                  return !pathname.isHidden();
              }
          });
          if (files != null) {
              for (File f : files) {
                  if (f.isDirectory()) {
                      if (!f.getName().equals(".svn")) {
                          processDirectory(baseDir, f.getPath(), zout, filter);
                      }
                  } else {
                      String fpath = f.getPath();
  