protected void cancel() {
    if (!cancelled) {

      report("Torrent.create.progress.cancelled");

      cancelled = true;

      if (file_hasher != null) {

        file_hasher.cancel();
      }
    }
  }
  protected void processDir(TOTorrentFileHasher hasher, File dir, Vector encoded, String root)
      throws TOTorrentException {
    File[] dir_file_list = dir.listFiles();

    if (dir_file_list == null) {

      throw (new TOTorrentException(
          "TOTorrentCreate: directory '"
              + dir.getAbsolutePath()
              + "' returned error when listing files in it",
          TOTorrentException.RT_FILE_NOT_FOUND));
    }
    // sort contents so that multiple encodes of a dir always
    // generate same torrent

    List file_list = new ArrayList(Arrays.asList(dir_file_list));

    Collections.sort(file_list);

    long offset = 0;

    for (int i = 0; i < file_list.size(); i++) {

      File file = (File) file_list.get(i);

      String file_name = file.getName();

      if (!(file_name.equals(".") || file_name.equals(".."))) {

        if (file.isDirectory()) {

          if (root.length() > 0) {

            file_name = root + File.separator + file_name;
          }

          processDir(hasher, file, encoded, file_name);

        } else {

          if (!ignoreFile(file_name)) {

            if (root.length() > 0) {

              file_name = root + File.separator + file_name;
            }

            long length = hasher.add(file);

            TOTorrentFileImpl tf = new TOTorrentFileImpl(this, offset, length, file_name);

            offset += length;

            if (add_other_hashes) {

              byte[] ed2k_digest = hasher.getPerFileED2KDigest();
              byte[] sha1_digest = hasher.getPerFileSHA1Digest();

              // System.out.println( "file:ed2k = " + ByteFormatter.nicePrint( ed2k_digest, true ));
              // System.out.println( "file:sha1 = " + ByteFormatter.nicePrint( sha1_digest, true ));

              tf.setAdditionalProperty("sha1", sha1_digest);
              tf.setAdditionalProperty("ed2k", ed2k_digest);
            }

            encoded.addElement(tf);
          }
        }
      }
    }
  }
  protected void constructFixed(File _torrent_base, long _piece_length) throws TOTorrentException {

    setIgnoreList();

    setCreationDate(SystemTime.getCurrentTime() / 1000);

    setCreatedBy(Constants.AZUREUS_NAME + "/" + Constants.AZUREUS_VERSION);

    setPieceLength(_piece_length);

    report("Torrent.create.progress.piecelength", _piece_length);

    piece_count = calculateNumberOfPieces(_torrent_base, _piece_length);

    if (piece_count == 0) {

      throw (new TOTorrentException(
          "TOTorrentCreate: specified files have zero total length",
          TOTorrentException.RT_ZERO_LENGTH));
    }

    report("Torrent.create.progress.hashing");

    for (int i = 0; i < progress_listeners.size(); i++) {

      ((TOTorrentProgressListener) progress_listeners.get(i)).reportProgress(0);
    }

    boolean add_other_per_file_hashes = add_other_hashes && !getSimpleTorrent();

    file_hasher =
        new TOTorrentFileHasher(
            add_other_hashes,
            add_other_per_file_hashes,
            (int) _piece_length,
            progress_listeners.size() == 0 ? null : this);

    if (cancelled) {

      throw (new TOTorrentException(
          "TOTorrentCreate: operation cancelled", TOTorrentException.RT_CANCELLED));
    }

    if (getSimpleTorrent()) {

      long length = file_hasher.add(_torrent_base);

      setFiles(
          new TOTorrentFileImpl[] {
            new TOTorrentFileImpl(this, 0, length, new byte[][] {getName()})
          });

      setPieces(file_hasher.getPieces());

    } else {

      Vector encoded = new Vector();

      processDir(file_hasher, _torrent_base, encoded, "");

      TOTorrentFileImpl[] files = new TOTorrentFileImpl[encoded.size()];

      encoded.copyInto(files);

      setFiles(files);
    }

    setPieces(file_hasher.getPieces());

    if (add_other_hashes) {

      byte[] sha1_digest = file_hasher.getSHA1Digest();
      byte[] ed2k_digest = file_hasher.getED2KDigest();

      addAdditionalInfoProperty("sha1", sha1_digest);
      addAdditionalInfoProperty("ed2k", ed2k_digest);

      // System.out.println( "overall:sha1 = " + ByteFormatter.nicePrint( sha1_digest, true));
      // System.out.println( "overall:ed2k = " + ByteFormatter.nicePrint( ed2k_digest, true));
    }
  }