/*
* 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 );
}
}