/** Load the cached index file into memory */
  private void loadCachedIndex() throws InstallException {
    // We need a sword book driver so the installer can use the driver
    // name to use in deciding where to put the index.
    BookDriver fake = SwordBookDriver.instance();

    entries.clear();

    URI cache = getCachedIndexFile();
    if (!NetUtil.isFile(cache)) {
      reloadBookList();
    }

    InputStream in = null;
    GZIPInputStream gin = null;
    TarInputStream tin = null;
    try {
      ConfigEntry.resetStatistics();

      in = NetUtil.getInputStream(cache);
      gin = new GZIPInputStream(in);
      tin = new TarInputStream(gin);
      while (true) {
        TarEntry entry = tin.getNextEntry();
        if (entry == null) {
          break;
        }

        String internal = entry.getName();
        if (!entry.isDirectory()) {
          try {
            int size = (int) entry.getSize();

            // Every now and then an empty entry sneaks in
            if (size == 0) {
              log.error("Empty entry: " + internal);
              continue;
            }

            byte[] buffer = new byte[size];
            if (tin.read(buffer) != size) {
              // This should not happen, but if it does then skip
              // it.
              log.error("Did not read all that was expected " + internal);
              continue;
            }

            if (internal.endsWith(SwordConstants.EXTENSION_CONF)) {
              internal = internal.substring(0, internal.length() - 5);
            } else {
              log.error("Not a SWORD config file: " + internal);
              continue;
            }

            if (internal.startsWith(SwordConstants.DIR_CONF + '/')) {
              internal = internal.substring(7);
            }

            SwordBookMetaData sbmd = new SwordBookMetaData(buffer, internal);
            sbmd.setDriver(fake);
            Book book = new SwordBook(sbmd, null);
            entries.put(book.getName(), book);
          } catch (IOException ex) {
            log.error("Failed to load config for entry: " + internal, ex);
          }
        }
      }

      loaded = true;

      ConfigEntry.dumpStatistics();
    } catch (IOException ex) {
      throw new InstallException(JSOtherMsg.lookupText("Error loading from cache"), ex);
    } finally {
      IOUtil.close(tin);
      IOUtil.close(gin);
      IOUtil.close(in);
    }
  }
  protected void process() {
    if (!checkWriteAccess()) {
      return;
    }

    String filePath = getParameter("filePath");

    if (!checkAccess(filePath)) {
      return;
    }

    output.println("<html>");
    output.println("<head>");

    output.println(
        "<link rel=\"stylesheet\" type=\"text/css\" href=\"/webfilesys/styles/common.css\">");
    output.println(
        "<link rel=\"stylesheet\" type=\"text/css\" href=\"/webfilesys/styles/skins/"
            + userMgr.getCSS(uid)
            + ".css\">");

    output.println("</head>");
    output.println("<body>");

    headLine(getResource("label.untarhead", "Extract from TAR archive"));

    output.println("<br/>");

    output.println("<form accept-charset=\"utf-8\" name=\"form1\">");

    output.println("<table class=\"dataForm\" width=\"100%\">");

    output.println("<tr>");
    output.println("<td colspan=\"2\" class=\"formParm1\">");
    output.println(getResource("label.extractfrom", "extracting from") + ":");
    output.println("</td>");
    output.println("</tr>");
    output.println("<tr>");
    output.println("<td colspan=\"2\" class=\"formParm2\">");
    output.println(this.getHeadlinePath(filePath));
    output.println("</td>");
    output.println("</tr>");

    output.println("<tr>");
    output.println("<td colspan=\"2\" class=\"formParm1\">");
    output.println(getResource("label.currentzip", "current file") + ":");
    output.println("</td>");
    output.println("</tr>");

    output.println("<tr>");
    output.println("<td colspan=\"2\" class=\"formParm2\">");
    output.println("<div id=\"currentFile\" />");
    output.println("</td>");
    output.println("</tr>");

    output.println("<tr>");
    output.println("<td colspan=\"2\" class=\"formParm1\">");
    output.println(getResource("label.untarResult", "files extracted") + ":");
    output.println("</td>");
    output.println("</tr>");

    output.println("<tr>");
    output.println("<td colspan=\"2\" class=\"formParm2\">");
    output.println("<div id=\"extractCount\" />");
    output.println("</td>");
    output.println("</tr>");

    boolean untarOkay = true;

    int untarNum = 0;

    boolean dirCreated = false;

    try {
      TarInputStream tarFile = new TarInputStream(new FileInputStream(filePath));

      TarEntry tarEntry = null;

      byte buff[] = new byte[4096];

      while ((tarEntry = tarFile.getNextEntry()) != null) {

        output.println("<script language=\"javascript\">");
        output.println(
            "document.getElementById('currentFile').innerHTML='"
                + CommonUtils.shortName(tarEntry.getName(), 45)
                + " ("
                + tarEntry.getSize()
                + " bytes)';");
        output.println("document.getElementById('extractCount').innerHTML='" + untarNum + "';");
        output.println("</script>");
        output.flush();

        File untarOutFile = createUntarFile(tarEntry.getName());

        if (!(untarOutFile.isDirectory())) {
          FileOutputStream destination = null;
          try {
            destination = new FileOutputStream(untarOutFile);

            boolean done = false;
            while (!done) {
              int bytesRead = tarFile.read(buff);

              if (bytesRead == -1) {
                done = true;
              } else {
                destination.write(buff, 0, bytesRead);
              }
            }

            destination.close();
          } catch (IOException ioex) {
            Logger.getLogger(getClass()).error("untar error in file " + untarOutFile, ioex);

            output.println("<font class=\"error\">");
            output.println(
                getResource("label.untarError", "Failed to extract from TAR archive")
                    + ": "
                    + untarOutFile);
            output.println("</font><br><br>");
            untarOkay = false;

            try {
              if (destination != null) {
                destination.close();
              }
              untarOutFile.delete();
            } catch (Exception ex) {
            }
          }

          untarNum++;
        } else {
          dirCreated = true;
        }
      }

      tarFile.close();
    } catch (IOException ioex) {
      Logger.getLogger(getClass()).error("failed to extract from tar archive", ioex);

      output.println("<font class=\"error\">");
      output.println(getResource("label.untarError", "Failed to extract from TAR archive"));
      output.println("</font><br><br>");
      untarOkay = false;
    }

    if (dirCreated) {
      TestSubDirThread subDirThread = new TestSubDirThread(getCwd());

      subDirThread.start();
    }

    String filenameWithoutPath = filePath.substring(filePath.lastIndexOf(File.separator) + 1);

    output.println("<script language=\"javascript\">");
    output.println("document.getElementById('extractCount').innerHTML='" + untarNum + "';");
    output.println("</script>");
    output.flush();

    String returnUrl = null;

    if (!untarOkay) {
      output.println("<tr>");
      output.println("<td colspan=\"2\" class=\"formButton\">");
      returnUrl = "/webfilesys/servlet?command=listFiles";
      output.println(
          "<input type=\"button\" value=\""
              + getResource("button.return", "Return")
              + "\" onclick=\"window.location.href='"
              + returnUrl
              + "'\">");
      output.println("</td>");
      output.println("</tr>");
    } else {
      output.println("<tr>");
      output.println("<td class=\"formButton\">");

      String mobile = (String) session.getAttribute("mobile");

      if (mobile != null) {
        returnUrl = "/webfilesys/servlet?command=mobile&cmd=folderFileList&keepListStatus=true";
      } else {
        returnUrl = "/webfilesys/servlet?command=listFiles&keepListStatus=true";
      }
      output.print(
          "<input type=\"button\" value=\""
              + getResource("button.keepTarArchive", "keep TAR archive")
              + "\" onclick=\"");

      if ((mobile == null) && (dirCreated)) {
        output.print(
            "window.parent.frames[1].location.href='/webfilesys/servlet?command=refresh&path="
                + UTF8URLEncoder.encode(getCwd())
                + "';");
      }
      output.println("window.location.href='" + returnUrl + "'\">");

      output.println("</td>");

      output.println("<td class=\"formButton\" style=\"text-align:right\">");

      returnUrl =
          "/webfilesys/servlet?command=fmdelete&fileName="
              + UTF8URLEncoder.encode(filenameWithoutPath)
              + "&deleteRO=no";
      output.print(
          "<input type=\"button\" value=\""
              + getResource("button.delTarArchive", "delete TAR archive")
              + "\" onclick=\"");

      if ((mobile == null) && (dirCreated)) {
        output.print(
            "window.parent.frames[1].location.href='/webfilesys/servlet?command=refresh&path="
                + UTF8URLEncoder.encode(getCwd())
                + "';");
      }

      output.println("window.location.href='" + returnUrl + "'\">");

      output.println("</td>");
      output.println("</tr>");

      if (WebFileSys.getInstance().isAutoCreateThumbs()) {
        if (dirCreated) {
          AutoThumbnailCreator.getInstance().queuePath(getCwd(), AutoThumbnailCreator.SCOPE_TREE);
        } else {
          AutoThumbnailCreator.getInstance().queuePath(getCwd(), AutoThumbnailCreator.SCOPE_DIR);
        }
      }
    }

    output.println("</table>");

    output.println("</form>");

    output.print("</body>");
    output.println("</html>");
    output.flush();
  }