/* * File : TorrentUtils.java * Created : 13-Oct-2003 * By : stuff * * 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.util; /** * @author parg * */ import java.io.*; import java.net.*; import java.util.*; //import com.aelitis.azureus.core.*; //import com.aelitis.azureus.core.util.CopyOnWriteList; import org.gudy.azureus2.core3.config.COConfigurationManager; import org.gudy.azureus2.core3.config.ParameterListener; //import org.gudy.azureus2.core3.internat.*; //import org.gudy.azureus2.core3.logging.LogRelation; import org.gudy.azureus2.core3.torrent.*; //import org.gudy.azureus2.core3.disk.*; //import org.gudy.azureus2.core3.download.*; public class TorrentUtils { // public static final int TORRENT_FLAG_LOW_NOISE = 0x00000001; // // private static final String TORRENT_AZ_PROP_DHT_BACKUP_ENABLE = "dht_backup_enable"; // private static final String TORRENT_AZ_PROP_DHT_BACKUP_REQUESTED = "dht_backup_requested"; // private static final String TORRENT_AZ_PROP_TORRENT_FLAGS = "torrent_flags"; // private static final String TORRENT_AZ_PROP_PLUGINS = "plugins"; // public static final String TORRENT_AZ_PROP_OBTAINED_FROM = "obtained_from"; // public static final String TORRENT_AZ_PROP_PEER_CACHE = "peer_cache"; // public static final String TORRENT_AZ_PROP_PEER_CACHE_VALID = "peer_cache_valid"; // private static final String MEM_ONLY_TORRENT_PATH = "?/\\!:mem_only:!\\/?"; // // private static final long PC_MARKER = RandomUtils.nextLong(); // private static final List created_torrents = new ArrayList(); // private static final Set created_torrents_set; // // private static ThreadLocal tls = // new ThreadLocal() // { // public Object // initialValue() // { // return( new HashMap()); // } // }; // // private static volatile Set ignore_set; // private static boolean bSaveTorrentBackup = true; // // private static CopyOnWriteList torrent_attribute_listeners = new CopyOnWriteList(); // // static { // 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())); // } // } public static TOTorrent readFromFile( File file, boolean create_delegate ) throws TOTorrentException { return( readFromFile( file, create_delegate, false )); } /** * 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 */ // public static ExtendedTorrent // readDelegateFromFile( // File file, // boolean force_initial_discard ) // // throws TOTorrentException // { // return((ExtendedTorrent)readFromFile( file, true, force_initial_discard )); // } public static TOTorrent readFromFile( File file, boolean create_delegate, boolean force_initial_discard ) throws TOTorrentException { 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 TOTorrent readFromBEncodedInputStream( InputStream is ) throws TOTorrentException { 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 URL getDecentralisedEmptyURL() { try{ return( new URL( "dht://" )); }catch( Throwable e ){ // Debug.printStackTrace(e); return( null ); } } public static void addCreatedTorrent( 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 void writeToFile( final TOTorrent torrent ) throws TOTorrentException { writeToFile( torrent, false ); } public static void writeToFile( TOTorrent torrent, boolean force_backup ) throws TOTorrentException { try{ torrent.getMonitor().enter(); 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; } // save first to temporary file as serialisation may require state to be re-read from // the existing file first and if we rename to .bak first then this aint good File torrent_file_tmp = new File(str + "._az"); torrent.serialiseToBEncodedFile( torrent_file_tmp ); // now backup if required 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 ); } } // now rename the temp file to required one if ( torrent_file.exists()){ torrent_file.delete(); } torrent_file_tmp.renameTo( torrent_file ); }finally{ torrent.getMonitor().exit(); } } public static void writeToFile( TOTorrent torrent, File file ) throws TOTorrentException { writeToFile( torrent, file, false ); } public static void writeToFile( TOTorrent torrent, File file, boolean force_backup ) throws TOTorrentException { torrent.setAdditionalStringProperty("torrent filename", file.toString()); writeToFile( torrent, force_backup ); } public static String getTorrentFileName( TOTorrent torrent ) throws TOTorrentException { 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 ); } /** * Copy a file to the Torrent Save Directory, taking into account all the * user config options related to that. * <p> * 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 */ public static File copyTorrentFileToSaveDir(File f, boolean persistent) 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 String getLocalisedName( TOTorrent torrent ) { try{ // LocaleUtilDecoder decoder = LocaleTorrentUtil.getTorrentEncodingIfAvailable( torrent ); String decoder = null; if ( decoder == null ){ return( new String(torrent.getName(),Constants.DEFAULT_ENCODING)); } // return( decoder.decodeString(torrent.getName())); return( new String(torrent.getName(),Constants.DEFAULT_ENCODING)); }catch( Throwable e ){ Debug.printStackTrace( e ); return( new String( torrent.getName())); } } public static void setObtainedFrom( File file, String str ) { try{ TOTorrent torrent = readFromFile( file, false, false ); setObtainedFrom( torrent, str ); writeToFile( torrent ); } catch (TOTorrentException e) { // ignore, file probably not torrent }catch( Throwable e ){ Debug.out( e ); } } public static void setObtainedFrom( TOTorrent torrent, String str ) { Map m = getAzureusPrivateProperties( torrent ); try{ m.put( TORRENT_AZ_PROP_OBTAINED_FROM, str.getBytes( "UTF-8" )); // fireAttributeListener( torrent, TORRENT_AZ_PROP_OBTAINED_FROM, str ); }catch( Throwable e ){ Debug.printStackTrace(e); } } private static Map getAzureusPrivateProperties( TOTorrent torrent ) { Map m = torrent.getAdditionalMapProperty( TOTorrent.AZUREUS_PRIVATE_PROPERTIES ); if ( m == null ){ m = new HashMap(); torrent.setAdditionalMapProperty( TOTorrent.AZUREUS_PRIVATE_PROPERTIES, m ); } return( m ); } }