/* * File : TOTorrentCreateImpl.java * Created : 5 Oct. 2003 * By : Parg * * Azureus - a Java Bittorrent client * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details ( see the LICENSE file ). * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.gudy.azureus2.core3.torrent.impl; import java.io.*; import java.net.*; import java.util.*; //import org.gudy.azureus2.core3.internat.MessageText; import org.gudy.azureus2.core3.torrent.*; import org.gudy.azureus2.core3.util.*; public class TOTorrentCreateImpl extends TOTorrentImpl implements TOTorrentFileHasherListener { protected File torrent_base; protected long piece_length; protected TOTorrentFileHasher file_hasher; protected long total_file_size = -1; protected long total_file_count = 0; protected long piece_count; protected boolean add_other_hashes; protected List progress_listeners = new ArrayList(); protected int reported_progress; protected Set ignore_set = new HashSet(); protected boolean cancelled; public static TOTorrentCreator create( File _torrent_base, URL _announce_url, boolean _add_other_hashes, long _piece_length ) throws TOTorrentException { TOTorrentCreateImpl t = new TOTorrentCreateImpl( _torrent_base, _announce_url, _add_other_hashes, _piece_length ); // return( new TOTorrentCreatorImpl( t )); return null; } public static TOTorrentCreator create( File _torrent_base, URL _announce_url, boolean _add_other_hashes, long _piece_min_size, long _piece_max_size, long _piece_num_lower, long _piece_num_upper ) throws TOTorrentException { TOTorrentCreateImpl t = new TOTorrentCreateImpl( _torrent_base, _announce_url, _add_other_hashes, _piece_min_size, _piece_max_size, _piece_num_lower, _piece_num_upper ); //return( new TOTorrentCreatorImpl( t )); return null; } protected TOTorrentCreateImpl( File _torrent_base, URL _announce_url, boolean _add_other_hashes, long _piece_length ) throws TOTorrentException { super( _torrent_base.getName(), _announce_url, _torrent_base.isFile()); torrent_base = _torrent_base; piece_length = _piece_length; add_other_hashes = _add_other_hashes; } protected TOTorrentCreateImpl( File _torrent_base, URL _announce_url, boolean _add_other_hashes, long _piece_min_size, long _piece_max_size, long _piece_num_lower, long _piece_num_upper ) throws TOTorrentException { super( _torrent_base.getName(), _announce_url, _torrent_base.isFile()); torrent_base = _torrent_base; add_other_hashes = _add_other_hashes; long total_size = calculateTotalFileSize( _torrent_base ); piece_length = getComputedPieceSize( total_size, _piece_min_size, _piece_max_size, _piece_num_lower, _piece_num_upper ); } protected void create() throws TOTorrentException { constructFixed( torrent_base, piece_length ); } 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)); } } 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 ); } } } } } public void pieceHashed( int piece_number ) { for (int i=0;i<progress_listeners.size();i++){ int this_progress = (int)((piece_number*100)/piece_count ); if ( this_progress != reported_progress ){ reported_progress = this_progress; ((TOTorrentProgressListener)progress_listeners.get(i)).reportProgress( reported_progress ); } } } protected long calculateNumberOfPieces( File _file, long _piece_length ) throws TOTorrentException { long res = getPieceCount(calculateTotalFileSize( _file ), _piece_length ); report( "Torrent.create.progress.piececount", ""+res ); return( res ); } protected long calculateTotalFileSize( File file ) throws TOTorrentException { if ( total_file_size == -1 ){ total_file_size = getTotalFileSize( file ); } return( total_file_size ); } protected long getTotalFileSize( File file ) throws TOTorrentException { report( "Torrent.create.progress.parsingfiles" ); long res = getTotalFileSizeSupport( file ); report( "Torrent.create.progress.totalfilesize", res ); report( "Torrent.create.progress.totalfilecount", ""+total_file_count ); return( res ); } protected long getTotalFileSizeSupport( File file ) throws TOTorrentException { String name = file.getName(); if ( name.equals( "." ) || name.equals( ".." )){ return( 0 ); } if ( !file.exists()){ throw( new TOTorrentException( "TOTorrentCreate: file '" + file.getName() + "' doesn't exist", TOTorrentException.RT_FILE_NOT_FOUND )); } if ( file.isFile()){ if ( !ignoreFile( name )){ total_file_count++; return( file.length()); }else{ return( 0 ); } }else{ File[] dir_files = file.listFiles(); if ( dir_files == null ){ throw( new TOTorrentException( "TOTorrentCreate: directory '" + file.getAbsolutePath() + "' returned error when listing files in it", TOTorrentException.RT_FILE_NOT_FOUND )); } long length = 0; for (int i=0;i<dir_files.length;i++){ length += getTotalFileSizeSupport( dir_files[i] ); } return( length ); } } protected void report( String resource_key ) { report( resource_key, null ); } protected void report( String resource_key, long bytes ) { if ( progress_listeners.size() > 0 ){ // report( resource_key, DisplayFormatters.formatByteCountToKiBEtc( bytes )); } } protected void report( String resource_key, String additional_text ) { if ( progress_listeners.size() > 0 ){ // String prefix = MessageText.getString(resource_key); // // for (int i=0;i<progress_listeners.size();i++){ // // ((TOTorrentProgressListener)progress_listeners.get(i)).reportCurrentTask( prefix + (additional_text==null?"":additional_text )); // } } } protected static long getTorrentDataSizeFromFileOrDirSupport( File file ) { String name = file.getName(); if ( name.equals( "." ) || name.equals( ".." )){ return( 0 ); } if ( !file.exists()){ return(0); } if ( file.isFile()){ return( file.length()); }else{ File[] dir_files = file.listFiles(); long length = 0; for (int i=0;i<dir_files.length;i++){ length += getTorrentDataSizeFromFileOrDirSupport( dir_files[i] ); } return( length ); } } public static long getTorrentDataSizeFromFileOrDir( File file_or_dir ) { return( getTorrentDataSizeFromFileOrDirSupport( file_or_dir )); } public static long getComputedPieceSize( long total_size, long _piece_min_size, long _piece_max_size, long _piece_num_lower, long _piece_num_upper ) { long piece_length = -1; long current_piece_size = _piece_min_size; while( current_piece_size <= _piece_max_size ){ long pieces = total_size / current_piece_size; if ( pieces <= _piece_num_upper ){ piece_length = current_piece_size; break; } current_piece_size = current_piece_size << 1; } // if we haven't set a piece length here then there are too many pieces even // at maximum piece size. Go for largest piece size if ( piece_length == -1 ){ // just go for the maximum piece size piece_length = _piece_max_size; } return( piece_length ); } public static long getPieceCount( long total_size, long piece_size ) { return( (total_size + (piece_size-1))/piece_size ); } protected void setIgnoreList() { try{ // ignore_set = TorrentUtils.getIgnoreSet(); }catch( NoClassDefFoundError e ){ return; } } protected boolean ignoreFile( String file ) { if ( ignore_set.contains(file.toLowerCase())){ report( "Torrent.create.progress.ignoringfile", " '" + file + "'" ); return( true ); } return( false ); } protected void cancel() { if ( !cancelled ){ report( "Torrent.create.progress.cancelled"); cancelled = true; if ( file_hasher != null ){ file_hasher.cancel(); } } } protected void addListener( TOTorrentProgressListener listener ) { progress_listeners.add( listener ); } protected void removeListener( TOTorrentProgressListener listener ) { progress_listeners.remove( listener ); } }