FileDocCategorySizeDatePackage
TorrentUtils.javaAPI DocAzureus 3.0.3.445063Thu Sep 13 13:43:38 BST 2007org.gudy.azureus2.core3.util

TorrentUtils

public class TorrentUtils extends Object
author
parg

Fields Summary
public static final int
TORRENT_FLAG_LOW_NOISE
private static final String
TORRENT_AZ_PROP_DHT_BACKUP_ENABLE
private static final String
TORRENT_AZ_PROP_DHT_BACKUP_REQUESTED
private static final String
TORRENT_AZ_PROP_TORRENT_FLAGS
private static final String
TORRENT_AZ_PROP_PLUGINS
private static final String
MEM_ONLY_TORRENT_PATH
private static final List
created_torrents
private static final Set
created_torrents_set
private static ThreadLocal
tls
private static volatile Set
ignore_set
private static boolean
bSaveTorrentBackup
private static final int
PIECE_HASH_TIMEOUT
private static Map
torrent_delegates
private static String
torrent_map_fluff
private static Map
discarded_map
Constructors Summary
Methods Summary
public static voidaddCreatedTorrent(TOTorrent torrent)

		synchronized( created_torrents ){
			
			try{
				byte[]	hash = torrent.getHash();
				
				//System.out.println( "addCreated:" + new String(torrent.getName()) + "/" + ByteFormatter.encodeString( hash ));
				
				if ( created_torrents.size() == 0 ){
					
					COConfigurationManager.setParameter( "my.created.torrents", created_torrents );
				}
				
				HashWrapper	hw = new HashWrapper( hash );
				
				if ( !created_torrents_set.contains( hw )){
					
					created_torrents.add( hash );
				
					created_torrents_set.add( hw );
				
					COConfigurationManager.setDirty();
				}
			}catch( TOTorrentException e ){
				
			}
		}
	
public static booleanannounceGroupsContainsURL(TOTorrent torrent, java.lang.String url)

		List	groups = announceGroupsToList( torrent );
		
		for (int i=0;i<groups.size();i++){
			
			List	set = (List)groups.get(i);
			
			for (int j=0;j<set.size();j++){
		
				if ( url.equals(set.get(j))){
			
					return( true );
				}
			}
		}
		
		return( false );
	
public static voidannounceGroupsInsertFirst(TOTorrent torrent, java.lang.String first_url)

		try{
			
			announceGroupsInsertFirst( torrent, new URL( first_url ));
			
		}catch( MalformedURLException e ){
			
			Debug.printStackTrace( e );
		}
	
public static voidannounceGroupsInsertFirst(TOTorrent torrent, java.net.URL first_url)

		announceGroupsInsertFirst( torrent, new URL[]{ first_url });
	
public static voidannounceGroupsInsertFirst(TOTorrent torrent, java.net.URL[] first_urls)

		TOTorrentAnnounceURLGroup group = torrent.getAnnounceURLGroup();
		
		TOTorrentAnnounceURLSet[] sets = group.getAnnounceURLSets();

		TOTorrentAnnounceURLSet set1 = group.createAnnounceURLSet( first_urls );
		
		
		if ( sets.length > 0 ){
			
			TOTorrentAnnounceURLSet[]	new_sets = new TOTorrentAnnounceURLSet[sets.length+1];
			
			new_sets[0] = set1;
			
			System.arraycopy( sets, 0, new_sets, 1, sets.length );
			
			group.setAnnounceURLSets( new_sets );
					
		}else{
			
			TOTorrentAnnounceURLSet set2 = group.createAnnounceURLSet(new URL[]{torrent.getAnnounceURL()});
			
			group.setAnnounceURLSets(
				new  TOTorrentAnnounceURLSet[]{ set1, set2 });
		}
	
public static voidannounceGroupsInsertLast(TOTorrent torrent, java.net.URL[] first_urls)

		TOTorrentAnnounceURLGroup group = torrent.getAnnounceURLGroup();
		
		TOTorrentAnnounceURLSet[] sets = group.getAnnounceURLSets();

		TOTorrentAnnounceURLSet set1 = group.createAnnounceURLSet( first_urls );
		
		
		if ( sets.length > 0 ){
			
			TOTorrentAnnounceURLSet[]	new_sets = new TOTorrentAnnounceURLSet[sets.length+1];
			
			new_sets[sets.length] = set1;
			
			System.arraycopy( sets, 0, new_sets, 0, sets.length );
			
			group.setAnnounceURLSets( new_sets );
					
		}else{
			
			TOTorrentAnnounceURLSet set2 = group.createAnnounceURLSet(new URL[]{torrent.getAnnounceURL()});
			
			group.setAnnounceURLSets(
				new  TOTorrentAnnounceURLSet[]{ set2, set1 });
		}
	
public static voidannounceGroupsSetFirst(TOTorrent torrent, java.lang.String first_url)

		List	groups = announceGroupsToList( torrent );
		
		boolean	found = false;
	
		outer:
		for (int i=0;i<groups.size();i++){
			
			List	set = (List)groups.get(i);
			
			for (int j=0;j<set.size();j++){
		
				if ( first_url.equals(set.get(j))){
			
					set.remove(j);
					
					set.add(0, first_url);
					
					groups.remove(set);
					
					groups.add(0,set);
	
					found = true;
					
					break outer;
				}
			}
		}
		
		if ( !found ){
			
			System.out.println( "TorrentUtils::announceGroupsSetFirst - failed to find '" + first_url + "'" );
		}
		
		listToAnnounceGroups( groups, torrent );
	
public static java.util.ListannounceGroupsToList(TOTorrent torrent)

		List	groups = new ArrayList();
		
		TOTorrentAnnounceURLGroup group = torrent.getAnnounceURLGroup();
		
		TOTorrentAnnounceURLSet[]	sets = group.getAnnounceURLSets();
		
		if ( sets.length == 0 ){
		
			List	s = new ArrayList();
			
			s.add( torrent.getAnnounceURL().toString());
			
			groups.add(s);
		}else{
			
			for (int i=0;i<sets.length;i++){
			
				List	s = new ArrayList();
								
				TOTorrentAnnounceURLSet	set = sets[i];
				
				URL[]	urls = set.getAnnounceURLs();
				
				for (int j=0;j<urls.length;j++){
				
					s.add( urls[j].toString());
				}
				
				if ( s.size() > 0 ){
					
					groups.add(s);
				}
			}
		}
		
		return( groups );
	
public static voidcopyToFile(TOTorrent torrent, java.io.File file)

	   	torrent.serialiseToBEncodedFile(file);
	
public static java.io.FilecopyTorrentFileToSaveDir(java.io.File f, boolean persistent)
Copy a file to the Torrent Save Directory, taking into account all the user config options related to that.

Also makes the directory if it doesn't exist.

param
f File to copy
param
persistent Whether the torrent is persistent
return
File after it's been copied (may be the same as f)
throws
IOException

		File torrentDir;
		boolean saveTorrents = persistent
				&& COConfigurationManager.getBooleanParameter("Save Torrent Files");
		if (saveTorrents)
			torrentDir = new File(COConfigurationManager
					.getDirectoryParameter("General_sDefaultTorrent_Directory"));
		else
			torrentDir = new File(f.getParent());

		//if the torrent is already in the completed files dir, use this
		//torrent instead of creating a new one in the default dir
		boolean moveWhenDone = COConfigurationManager.getBooleanParameter("Move Completed When Done");
		String completedDir = COConfigurationManager.getStringParameter(
				"Completed Files Directory", "");
		if (moveWhenDone && completedDir.length() > 0) {
			File cFile = new File(completedDir, f.getName());
			if (cFile.exists()) {
				//set the torrentDir to the completedDir
				torrentDir = new File(completedDir);
			}
		}

		FileUtil.mkdirs(torrentDir);

		File fDest = new File(torrentDir, f.getName().replaceAll("%20", "."));
		if (fDest.equals(f)) {
			return f;
		}

		while (fDest.exists()) {
			fDest = new File(torrentDir, "_" + fDest.getName());
		}

		fDest.createNewFile();

		if (!FileUtil.copyFile(f, fDest)) {
			throw new IOException("File copy failed");
		}

		return fDest;
	
public static voiddelete(TOTorrent torrent)

	   try{
	   		torrent.getMonitor().enter();
	    	
	    	String str = torrent.getAdditionalStringProperty("torrent filename");
	    	
	    	if ( str == null ){
	    		
	    		throw( new TOTorrentException("TorrentUtils::delete: no 'torrent filename' attribute defined", TOTorrentException.RT_FILE_NOT_FOUND));
	    	}
	    	
	    	if ( str.equals( MEM_ONLY_TORRENT_PATH )){
	    		
	    		return;
	    	}
	    	
	    	if ( !new File(str).delete()){
	    		
	    		throw( new TOTorrentException("TorrentUtils::delete: failed to delete '" + str + "'", TOTorrentException.RT_WRITE_FAILS));
	    	}
		
	    	new File( str + ".bak" ).delete();
	    	
	    }finally{
	    	
	    	torrent.getMonitor().exit();
	    }
	
public static voiddelete(java.io.File torrent_file)

		if ( !FileUtil.deleteWithRecycle( torrent_file )){
			
    		Debug.out( "TorrentUtils::delete: failed to delete '" + torrent_file + "'" );
    	}
	
    	new File( torrent_file.toString() + ".bak" ).delete();
	
public static java.lang.StringexceptionToText(TOTorrentException e)

		String	errorDetail;
		
		int	reason = e.getReason();
  					
		if ( reason == TOTorrentException.RT_FILE_NOT_FOUND ){
 	     	        		 		
			errorDetail = MessageText.getString("DownloadManager.error.filenotfound" );
	        				
		}else if ( reason == TOTorrentException.RT_ZERO_LENGTH ){
	     
			errorDetail = MessageText.getString("DownloadManager.error.fileempty");
	        			
		}else if ( reason == TOTorrentException.RT_TOO_BIG ){
	 	     		
			errorDetail = MessageText.getString("DownloadManager.error.filetoobig");
			        
		}else if ( reason == TOTorrentException.RT_DECODE_FAILS ){
	 
			errorDetail = MessageText.getString("DownloadManager.error.filewithouttorrentinfo" );
	 		  			
		}else if ( reason == TOTorrentException.RT_UNSUPPORTED_ENCODING ){
	 	     		
			errorDetail = MessageText.getString("DownloadManager.error.unsupportedencoding");
							
		}else if ( reason == TOTorrentException.RT_READ_FAILS ){
	
			errorDetail = MessageText.getString("DownloadManager.error.ioerror");
					
		}else if ( reason == TOTorrentException.RT_HASH_FAILS ){
			
			errorDetail = MessageText.getString("DownloadManager.error.sha1");
					
		}else if ( reason == TOTorrentException.RT_CANCELLED ){
			
			errorDetail = MessageText.getString("DownloadManager.error.operationcancancelled");
						
		}else{
	 	     
			errorDetail = Debug.getNestedExceptionMessage(e);
		}
					
		String	msg = Debug.getNestedExceptionMessage(e);
				
		if ( errorDetail.indexOf( msg ) == -1){
				
			errorDetail += " (" + msg + ")";
		}
		
		return( errorDetail );
	
private static java.util.MapgetAzureusProperties(TOTorrent torrent)

		Map	m = torrent.getAdditionalMapProperty( TOTorrent.AZUREUS_PROPERTIES );
		
		if ( m == null ){
			
			m = new HashMap();
			
			torrent.setAdditionalMapProperty( TOTorrent.AZUREUS_PROPERTIES, m );
		}
		
		return( m );
	
public static booleangetDHTBackupEnabled(TOTorrent torrent)

			// missing -> true
		
		Map	m = getAzureusProperties( torrent );
		
		Object	obj = m.get( TORRENT_AZ_PROP_DHT_BACKUP_ENABLE );
		
		if ( obj instanceof Long ){
		
			return( ((Long)obj).longValue() == 1 );
		}
		
		return( true );
	
public static booleangetDHTTrackerEnabled()

		PluginInterface dht_pi = 
			AzureusCoreFactory.getSingleton().getPluginManager().getPluginInterfaceByClass(
						DHTPlugin.class );
				
		if ( dht_pi == null ){
			
			return( false );
			
		}else{
			
			DHTPlugin dht = (DHTPlugin)dht_pi.getPlugin();		
			
			return( dht.peekEnabled());
		}
	
public static java.net.URLgetDecentralisedEmptyURL()

		try{
			return( new URL( "dht://" ));
			
		}catch( Throwable e ){
			
			Debug.printStackTrace(e);
			
			return( null );
		}
	
public static DownloadManagergetDownloadManager(HashWrapper hash)
Get the DownloadManager related to a torrent's hashBytes

param
hashBytes
return

		try {
			return AzureusCoreFactory.getSingleton().getGlobalManager()
					.getDownloadManager(hash);
		} catch (Exception e) {
			return null;
		}
	
public static booleangetFlag(TOTorrent torrent, int flag)

		Map	m = getAzureusProperties( torrent );
		
		Long	flags = (Long)m.get( TORRENT_AZ_PROP_TORRENT_FLAGS );
		
		if ( flags == null ){
			
			return( false );
		}

		return(( flags.intValue() & flag ) != 0 );
	
public static java.util.SetgetIgnoreSet()

		return(getIgnoreSetSupport(false));
	
public static synchronized java.util.SetgetIgnoreSetSupport(boolean force)

		if ( ignore_set == null || force ){
			
			Set		new_ignore_set	= new HashSet();
		    
			String	ignore_list = COConfigurationManager.getStringParameter( "File.Torrent.IgnoreFiles", TOTorrent.DEFAULT_IGNORE_FILES );
			
			if ( ignore_set == null ){
				
					// first time - add the listener
				
				COConfigurationManager.addParameterListener(
					"File.Torrent.IgnoreFiles",
					new ParameterListener()
					{
						public void 
						parameterChanged(
							String parameterName)
						{
							getIgnoreSetSupport( true );
						}
					});
			}
			
			int	pos = 0;
			
			while(true){
				
				int	p1 = ignore_list.indexOf( ";", pos );
				
				String	bit;
				
				if ( p1 == -1 ){
					
					bit = ignore_list.substring(pos);
					
				}else{
					
					bit	= ignore_list.substring( pos, p1 );
					
					pos	= p1+1;
				}
				
				new_ignore_set.add(bit.trim().toLowerCase());
				
				if ( p1 == -1 ){
					
					break;
				}
			}
			
			ignore_set = new_ignore_set;
		}
		
		return( ignore_set );
	
public static java.lang.StringgetLocalisedName(TOTorrent torrent)

		try{
			
			LocaleUtilDecoder decoder = LocaleTorrentUtil.getTorrentEncodingIfAvailable( torrent );
			
			if ( decoder == null ){
				
				return( new String(torrent.getName(),Constants.DEFAULT_ENCODING));
			}
			
			return( decoder.decodeString(torrent.getName()));
			
		}catch( Throwable e ){
			
			Debug.printStackTrace( e );
			
			return( new String( torrent.getName()));
		}
	
public static java.util.MapgetPluginMapProperty(TOTorrent torrent, java.lang.String name)

		Map	m = getAzureusProperties( torrent );
		
		Object	obj = m.get( TORRENT_AZ_PROP_PLUGINS );
		
		if ( obj instanceof Map ){
		
			Map p = (Map)obj;
			
			obj = p.get( name );
			
			if ( obj instanceof Map ){
		
				return((Map)obj);
			}
		}
		
		return( null );
	
public static java.lang.StringgetPluginStringProperty(TOTorrent torrent, java.lang.String name)

		Map	m = getAzureusProperties( torrent );
		
		Object	obj = m.get( TORRENT_AZ_PROP_PLUGINS );
		
		if ( obj instanceof Map ){
		
			Map p = (Map)obj;
			
			obj = p.get( name );
			
			if ( obj instanceof byte[]){
			
				return( new String((byte[])obj));
			}
		}
		
		return( null );
	
public static booleangetPrivate(TOTorrent torrent)

		if ( torrent == null ){
			
			return( false );
		}	
			
		return( torrent.getPrivate());
	
public static TOTorrentgetTLSTorrent()

		HashWrapper	hash = (HashWrapper)((Map)tls.get()).get("hash");
		
		if ( hash != null ){
			
			try{
				AzureusCore	core = AzureusCoreFactory.getSingleton();
				
				DownloadManager dm = core.getGlobalManager().getDownloadManager( hash );
				
				if ( dm != null ){
							
					return( dm.getTorrent());
				}
			}catch( Throwable e ){
				
				Debug.printStackTrace(e);
			}
		}
		
		return( null );
	
public static java.lang.StringgetTorrentFileName(TOTorrent torrent)

    	String str = torrent.getAdditionalStringProperty("torrent filename");
    	
    	if ( str == null ){
    		
    		throw( new TOTorrentException("TorrentUtils::getTorrentFileName: no 'torrent filename' attribute defined", TOTorrentException.RT_FILE_NOT_FOUND));
    	}

    	if ( str.equals( MEM_ONLY_TORRENT_PATH )){
    		
    		return( null );
    	}
    	
		return( str );
	
public static booleanisCreatedTorrent(TOTorrent torrent)

		synchronized( created_torrents ){

			try{
				HashWrapper	hw = torrent.getHashWrapper();
				
				boolean	res = created_torrents_set.contains( hw );
				
					// if we don't have a persistent record of creation, check the non-persisted version
				
				if ( !res ){
					
					res = torrent.isCreated();
				}
				
				// System.out.println( "isCreated:" + new String(torrent.getName()) + "/" + ByteFormatter.encodeString( hw.getBytes()) + " -> " + res );

				return( res );
				
			}catch( TOTorrentException e ){
				
				Debug.printStackTrace(e);
				
				return( false );
				
			}
		}
	
public static booleanisDHTBackupRequested(TOTorrent torrent)

			// missing -> false
		
		Map	m = getAzureusProperties( torrent );
		
		Object obj = m.get( TORRENT_AZ_PROP_DHT_BACKUP_REQUESTED );
		
		if ( obj instanceof Long ){
		
			return( ((Long)obj).longValue() == 1 );
		}
		
		return( false );
	
public static booleanisDecentralised(TOTorrent torrent)

		if ( torrent == null ){
			
			return( false );
		}
		
		return( isDecentralised( torrent.getAnnounceURL()));
	
public static booleanisDecentralised(java.net.URL url)

		if ( url == null ){
			
			return( false );
		}
		
		return( url.getProtocol().equalsIgnoreCase( "dht" ));
	
public static booleanisTorrentFile(java.lang.String filename)
Runs a file through a series of test to verify if it is a torrent.

param
filename File to test
return
true - file is a valid torrent file
throws
FileNotFoundException
throws
IOException

	  File check = new File(filename);
	  if (!check.exists())
	    throw new FileNotFoundException("File "+filename+" not found.");
	  if (!check.canRead())
	    throw new IOException("File "+filename+" cannot be read.");
	  if (check.isDirectory())
	    throw new FileIsADirectoryException("File "+filename+" is a directory.");
	  try {
	    TOTorrentFactory.deserialiseFromBEncodedFile(check);
	    return true;
	  } catch (Throwable e) {
	    return false;
	  }
	
public static voidlistToAnnounceGroups(java.util.List groups, TOTorrent torrent)

		try{
			TOTorrentAnnounceURLGroup tg = torrent.getAnnounceURLGroup();
			
			if ( groups.size() == 1 ){
				
				List	set = (List)groups.get(0);
				
				if ( set.size() == 1 ){
					
					torrent.setAnnounceURL( new URL((String)set.get(0)));
					
					tg.setAnnounceURLSets( new TOTorrentAnnounceURLSet[0]);
					
					return;
				}
			}
			
			
			Vector	g = new Vector();
			
			for (int i=0;i<groups.size();i++){
				
				List	set = (List)groups.get(i);
				
				URL[]	urls = new URL[set.size()];
				
				for (int j=0;j<set.size();j++){
				
					urls[j] = new URL((String)set.get(j));
				}
				
				if ( urls.length > 0 ){
					
					g.add( tg.createAnnounceURLSet( urls ));
				}
			}
			
			TOTorrentAnnounceURLSet[]	sets = new TOTorrentAnnounceURLSet[g.size()];
			
			g.copyInto( sets );
			
			tg.setAnnounceURLSets( sets );
			
			if ( sets.length == 0 ){
			
					// hmm, no valid urls at all
				
				torrent.setAnnounceURL( new URL( "http://no.valid.urls.defined/announce"));
			}
			
		}catch( MalformedURLException e ){
			
			Debug.printStackTrace( e );
		}
	
public static booleanmergeAnnounceURLs(TOTorrent new_torrent, TOTorrent dest_torrent)

		if ( new_torrent == null || dest_torrent == null ){
			
			return( false);
		}
		
		List	new_groups 	= announceGroupsToList( new_torrent );
		List 	dest_groups = announceGroupsToList( dest_torrent );
		
		List	groups_to_add = new ArrayList();
		
		for (int i=0;i<new_groups.size();i++){
			
			List new_set = (List)new_groups.get(i);
			
			boolean	match = false;
			
			for (int j=0;j<dest_groups.size();j++){
				
				List dest_set = (List)dest_groups.get(j);
				
				boolean same = new_set.size() == dest_set.size();
				
				if ( same ){
					
					for (int k=0;k<new_set.size();k++){
						
						String new_url = (String)new_set.get(k);
						
						if ( !dest_set.contains(new_url)){
							
							same = false;
							
							break;
						}
					}
				}
				
				if ( same ){
					
					match = true;
					
					break;
				}
			}
			
			if ( !match ){
		
				groups_to_add.add( new_set );
			}
		}
		
		if ( groups_to_add.size() == 0 ){
			
			return( false );
		}
		
		for (int i=0;i<groups_to_add.size();i++){
			
			dest_groups.add(i,groups_to_add.get(i));
		}
		
		listToAnnounceGroups( dest_groups, dest_torrent );
		
		return( true );
	
public static booleanmove(java.io.File from_torrent, java.io.File to_torrent)

		if ( !FileUtil.renameFile(from_torrent, to_torrent )){
			
			return( false );
		}
		
		if ( new File( from_torrent.toString() + ".bak").exists()){
			
			FileUtil.renameFile( 
				new File( from_torrent.toString() + ".bak"),
				new File( to_torrent.toString() + ".bak"));
		}
		
		return( true );
	
public static java.lang.StringnicePrintTorrentHash(TOTorrent torrent)
A nice string of a Torrent's hash

param
torrent Torrent to fromat hash of
return
Hash string in a nice format

		return nicePrintTorrentHash(torrent, false);
	
public static java.lang.StringnicePrintTorrentHash(TOTorrent torrent, boolean tight)
A nice string of a Torrent's hash

param
torrent Torrent to fromat hash of
param
tight No spaces between groups of numbers
return
Hash string in a nice format

		byte[] hash;

		if (torrent == null) {

			hash = new byte[20];
		} else {
			try {
				hash = torrent.getHash();

			} catch (TOTorrentException e) {

				Debug.printStackTrace(e);

				hash = new byte[20];
			}
		}

		return (ByteFormatter.nicePrint(hash, tight));
	
public static org.gudy.azureus2.core3.util.TorrentUtils$ExtendedTorrentreadDelegateFromFile(java.io.File file, boolean force_initial_discard)
If you set "create_delegate" to true then you must understand that this results is piece hashes being discarded and then re-read from the torrent file if needed Therefore, if you delete the original torrent file you're going to get errors if you access the pieces after this (and they've been discarded)

param
file
param
create_delegate
param
force_initial_discard - use to get rid of pieces immediately
return
throws
TOTorrentException

		return((ExtendedTorrent)readFromFile( file, true, force_initial_discard ));
	
public static TOTorrentreadFromBEncodedInputStream(java.io.InputStream is)

		TOTorrent	torrent = TOTorrentFactory.deserialiseFromBEncodedInputStream( is );
		
			// as we've just imported this torrent we want to clear out any possible attributes that we
			// don't want such as "torrent filename"
		
		torrent.removeAdditionalProperties();
		
		return( torrent );
	
public static TOTorrentreadFromFile(java.io.File file, boolean create_delegate)

	
	 
		COConfigurationManager.addAndFireParameterListener("Save Torrent Backup",
				new ParameterListener() {
					public void parameterChanged(String parameterName) {
						bSaveTorrentBackup = COConfigurationManager.getBooleanParameter(parameterName);
					}
				});
		
		created_torrents = COConfigurationManager.getListParameter( "my.created.torrents", new ArrayList());
		
		created_torrents_set	= new HashSet();
		
		Iterator	it = created_torrents.iterator();
		
		while( it.hasNext()){
			
			created_torrents_set.add( new HashWrapper((byte[])it.next()));
		}
	
		return( readFromFile( file, create_delegate, false ));
	
public static TOTorrentreadFromFile(java.io.File file, boolean create_delegate, boolean force_initial_discard)

		TOTorrent torrent;
   
		try{
			torrent = TOTorrentFactory.deserialiseFromBEncodedFile(file);
			
				// make an immediate backup if requested and one doesn't exist 
			
	    	if (bSaveTorrentBackup) {
	    		
	    		File torrent_file_bak = new File(file.getParent(), file.getName() + ".bak");

	    		if ( !torrent_file_bak.exists()){
	    			
	    			try{
	    				torrent.serialiseToBEncodedFile(torrent_file_bak);
	    				
	    			}catch( Throwable e ){
	    				
	    				Debug.printStackTrace(e);
	    			}
	    		}
	    	}
	    	
		}catch (TOTorrentException e){
      
			Debug.outNoStack( e.getMessage() );
			
			File torrentBackup = new File(file.getParent(), file.getName() + ".bak");
			
			if( torrentBackup.exists()){
				
				torrent = TOTorrentFactory.deserialiseFromBEncodedFile(torrentBackup);
				
					// use the original torrent's file name so that when this gets saved
					// it writes back to the original and backups are made as required
					// - set below
			}else{
				
				throw e;
			}
		}
				
		torrent.setAdditionalStringProperty("torrent filename", file.toString());
		
		if ( create_delegate ){
			
			torrentDelegate	res = new torrentDelegate( torrent, file );
			
			if ( force_initial_discard ){
				
				res.discardPieces( SystemTime.getCurrentTime(), true );
			}
			
			return( res );
			
		}else{
			
			return( torrent );
		}
	
public static voidrecursiveEmptyDirDelete(java.io.File f)
Deletes the given dir and all dirs underneath if empty. Don't delete default save path or completed files directory, however, allow deletion of their empty subdirectories Files defined to be ignored for the sake of torrent creation are automatically deleted For example, by default this includes thumbs.db

		TorrentUtils.recursiveEmptyDirDelete(f, true);
	
public static voidrecursiveEmptyDirDelete(java.io.File f, boolean log_warnings)
Same as #recursiveEmptyDirDelete(File), except allows disabling of logging of any warnings

param
f Dir to delete
param
log_warnings Whether to log warning

		Set ignore_map = getIgnoreSet();

		FileUtil.recursiveEmptyDirDelete(f, ignore_map, log_warnings);
	
public static voidregisterMapFluff(java.lang.String _fluff)

	
	  
	
				 
	
		synchronized( TorrentUtils.class ){
			
				// lazyness - currently only one fluff item 
			
			if ( torrent_map_fluff != null ){
				
				Debug.out( "Excessive fluff detected" );
				
			}else{
				
				torrent_map_fluff = _fluff;
			}
		}
	
public static voidremoveCreatedTorrent(TOTorrent torrent)

		synchronized( created_torrents ){

			try{
				HashWrapper	hw = torrent.getHashWrapper();
				
				byte[]		hash	= hw.getBytes();
				
				//System.out.println( "removeCreated:" + new String(torrent.getName()) + "/" + ByteFormatter.encodeString( hash ));

				Iterator	it = created_torrents.iterator();
				
				while( it.hasNext()){
					
					byte[]	h = (byte[])it.next();
					
					if ( Arrays.equals( hash, h )){
						
						it.remove();
					}
				}
				
				COConfigurationManager.setDirty();

				created_torrents_set.remove( hw );
				
			}catch( TOTorrentException e ){
				
			}
		}
	
public static booleanreplaceAnnounceURL(TOTorrent torrent, java.net.URL old_url, java.net.URL new_url)

		boolean	found = false;
		
		String	old_str = old_url.toString();
		String	new_str = new_url.toString();
		
		List	l = announceGroupsToList( torrent );
		
		for (int i=0;i<l.size();i++){
			
			List	set = (List)l.get(i);
			
			for (int j=0;j<set.size();j++){
		
				if (((String)set.get(j)).equals(old_str)){
					
					found	= true;
					
					set.set( j, new_str );
				}
			}
		}
		
		if ( found ){
			
			listToAnnounceGroups( l, torrent );
		}
		
		if ( torrent.getAnnounceURL().toString().equals( old_str )){
			
			torrent.setAnnounceURL( new_url );
			
			found	= true;
		}
		
		if ( found ){
			
			try{
				writeToFile( torrent );
				
			}catch( Throwable e ){
				
				Debug.printStackTrace(e);
				
				return( false );
			}
		}
		
		return( found );
	
public static voidsetDHTBackupEnabled(TOTorrent torrent, boolean enabled)

		Map	m = getAzureusProperties( torrent );
		
		m.put( TORRENT_AZ_PROP_DHT_BACKUP_ENABLE, new Long(enabled?1:0));
	
public static voidsetDHTBackupRequested(TOTorrent torrent, boolean requested)

		Map	m = getAzureusProperties( torrent );
		
		m.put( TORRENT_AZ_PROP_DHT_BACKUP_REQUESTED, new Long(requested?1:0));
	
public static voidsetDecentralised(TOTorrent torrent)

	   	try{
	   		byte[]	hash = torrent.getHash();
	     		
	   		torrent.setAnnounceURL( new URL( "dht://" + ByteFormatter.encodeString( hash ) + ".dht/announce" ));
			
		}catch( Throwable e ){
			
			Debug.printStackTrace( e );
		}
	
public static voidsetFlag(TOTorrent torrent, int flag, boolean value)

		Map	m = getAzureusProperties( torrent );
		
		Long	flags = (Long)m.get( TORRENT_AZ_PROP_TORRENT_FLAGS );
		
		if ( flags == null ){
			
			flags = new Long(0);
		}		
		
		m.put( TORRENT_AZ_PROP_TORRENT_FLAGS, new Long(flags.intValue() | flag ));
	
public static voidsetMemoryOnly(TOTorrent torrent, boolean mem_only)

		if ( mem_only ){
			
			torrent.setAdditionalStringProperty("torrent filename", MEM_ONLY_TORRENT_PATH );
			
		}else{
			
			String s = torrent.getAdditionalStringProperty("torrent filename");
			
			if ( s != null && s.equals( MEM_ONLY_TORRENT_PATH )){
				
				torrent.removeAdditionalProperty( "torrent filename" );
			}
		}
	
public static voidsetPluginMapProperty(TOTorrent torrent, java.lang.String name, java.util.Map value)

		Map	m = getAzureusProperties( torrent );
		
		Object obj = m.get( TORRENT_AZ_PROP_PLUGINS );
		
		Map	p;
		
		if ( obj instanceof Map ){
			
			p = (Map)obj;
			
		}else{
			
			p = new HashMap();
			
			m.put( TORRENT_AZ_PROP_PLUGINS, p );
		}
		
		if ( value == null ){
			
			p.remove( name );
			
		}else{
			
			p.put( name, value );
		}
	
public static voidsetPluginStringProperty(TOTorrent torrent, java.lang.String name, java.lang.String value)

		Map	m = getAzureusProperties( torrent );
		
		Object obj = m.get( TORRENT_AZ_PROP_PLUGINS );
		
		Map	p;
		
		if ( obj instanceof Map ){
			
			p = (Map)obj;
			
		}else{
			
			p = new HashMap();
			
			m.put( TORRENT_AZ_PROP_PLUGINS, p );
		}
		
		if ( value == null ){
			
			p.remove( name );
			
		}else{
			
			p.put( name, value.getBytes());
		}
	
public static voidsetPrivate(TOTorrent torrent, boolean _private)

		if ( torrent == null ){
			
			return;
		}
		
		try{
			torrent.setPrivate( _private );
			
		}catch( Throwable e ){
			
			Debug.printStackTrace(e);
		}
	
public static voidsetResumeDataCompletelyValid(DownloadManagerState download_manager_state)

		DiskManagerFactory.setResumeDataCompletelyValid( download_manager_state );
	
public static voidsetTLSTorrentHash(HashWrapper hash)

		((Map)tls.get()).put( "hash", hash );
	
public static voidwriteToFile(TOTorrent torrent)

		writeToFile( torrent, false );
	
public static voidwriteToFile(TOTorrent torrent, boolean force_backup)

	   try{
	   		torrent.getMonitor().enter();
	    	
	   			// we've got to re-obtain the pieces etc. here in case they've been thrown
	   			// away to save memory *before* we rename the torrent file!
	   		   		
	   		torrent.getPieces();
	   		
	   			// restore fluff too
	   		
	   		if  ( torrent_map_fluff != null ){
	   			
	   			torrent.getAdditionalMapProperty( torrent_map_fluff );
	   		}
	   		
	    	String str = torrent.getAdditionalStringProperty("torrent filename");
	    	
	    	if (str == null){
	    		
	    		throw (new TOTorrentException("TorrentUtils::writeToFile: no 'torrent filename' attribute defined", TOTorrentException.RT_FILE_NOT_FOUND));
	    	}
	    	
	    	if ( str.equals( MEM_ONLY_TORRENT_PATH )){
	    		
	    		return;
	    	}
	    	
	    	File torrent_file = new File(str);
	    	
	    	if ( 	( force_backup ||COConfigurationManager.getBooleanParameter("Save Torrent Backup")) &&
	    			torrent_file.exists()) {
	    		
	    		File torrent_file_bak = new File(str + ".bak");
	    		
	    		try{
	    			
	    			// Will return false if it cannot be deleted (including if the file doesn't exist). 
	    			torrent_file_bak.delete();
	    			torrent_file.renameTo(torrent_file_bak);
	    			
	    		}catch( SecurityException e){
	    			
	    			Debug.printStackTrace( e );
	    		}
	    	}
	      
	    	torrent.serialiseToBEncodedFile(torrent_file);
			
	   	}finally{
	   		
	   		torrent.getMonitor().exit();
	   	}
	
public static voidwriteToFile(TOTorrent torrent, java.io.File file)

		writeToFile( torrent, file, false );
	
public static voidwriteToFile(TOTorrent torrent, java.io.File file, boolean force_backup)

		
		torrent.setAdditionalStringProperty("torrent filename", file.toString());
		
		writeToFile( torrent, force_backup );