📄 totorrentimpl.java
字号:
/*
* File : TOTorrentImpl.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.logging.LogRelation;
import org.gudy.azureus2.core3.torrent.*;
import org.gudy.azureus2.core3.util.*;
import com.aelitis.azureus.core.AzureusCoreFactory;
public class
TOTorrentImpl
extends LogRelation
implements TOTorrent
{
protected static final String TK_ANNOUNCE = "announce";
protected static final String TK_ANNOUNCE_LIST = "announce-list";
protected static final String TK_COMMENT = "comment";
protected static final String TK_CREATION_DATE = "creation date";
protected static final String TK_CREATED_BY = "created by";
protected static final String TK_INFO = "info";
protected static final String TK_NAME = "name";
protected static final String TK_LENGTH = "length";
protected static final String TK_PATH = "path";
protected static final String TK_FILES = "files";
protected static final String TK_PIECE_LENGTH = "piece length";
protected static final String TK_PIECES = "pieces";
protected static final String TK_PRIVATE = "private";
protected static final String TK_NAME_UTF8 = "name.utf-8";
protected static final String TK_PATH_UTF8 = "path.utf-8";
protected static final String TK_COMMENT_UTF8 = "comment.utf-8";
protected static final List TK_ADDITIONAL_OK_ATTRS =
Arrays.asList(new String[]{TK_COMMENT_UTF8, AZUREUS_PROPERTIES });
private byte[] torrent_name;
private byte[] torrent_name_utf8;
private byte[] comment;
private URL announce_url;
private TOTorrentAnnounceURLGroupImpl announce_group = new TOTorrentAnnounceURLGroupImpl(this);
private long piece_length;
private byte[][] pieces;
private int number_of_pieces;
private byte[] torrent_hash;
private HashWrapper torrent_hash_wrapper;
private boolean simple_torrent;
private TOTorrentFileImpl[] files;
private long creation_date;
private byte[] created_by;
private Map additional_properties = new HashMap();
private Map additional_info_properties = new HashMap();
private boolean created;
private boolean serialising;
protected AEMonitor this_mon = new AEMonitor( "TOTorrent" );
/**
* Constructor for deserialisation
*/
protected
TOTorrentImpl()
{
}
/**
* Constructor for creation
*/
protected
TOTorrentImpl(
String _torrent_name,
URL _announce_url,
boolean _simple_torrent )
throws TOTorrentException
{
created = true;
try{
torrent_name = _torrent_name.getBytes( Constants.DEFAULT_ENCODING );
torrent_name_utf8 = torrent_name;
setAnnounceURL( _announce_url );
simple_torrent = _simple_torrent;
}catch( UnsupportedEncodingException e ){
throw( new TOTorrentException( "Unsupported encoding for '" + _torrent_name + "'",
TOTorrentException.RT_UNSUPPORTED_ENCODING));
}
}
public void
serialiseToBEncodedFile(
final File output_file )
throws TOTorrentException
{
// we have to defer marking as created until some kind of persisting occurs as we don't know that the info-hash is "permanent" until#
// this point (external code can set info-hash internal properties between create + complete )
if ( created ){
TorrentUtils.addCreatedTorrent( this );
}
byte[] res = serialiseToByteArray();
BufferedOutputStream bos = null;
try{
File parent = output_file.getParentFile();
if (parent == null) {
throw new TOTorrentException( "Path '" + output_file + "' is invalid", TOTorrentException.RT_WRITE_FAILS);
}
// We would expect this to be normally true most of the time.
if (!parent.isDirectory()) {
// Try to create a directory.
boolean dir_created = FileUtil.mkdirs(parent);
// Something strange going on...
if (!dir_created) {
// Does it exist already?
if (parent.exists()) {
// And it really isn't a directory?
if (!parent.isDirectory()) {
// How strange.
throw new TOTorrentException( "Path '" + output_file + "' is invalid", TOTorrentException.RT_WRITE_FAILS);
}
// It is a directory which does exist. But we tested for that earlier. Perhaps it has been created in the
// meantime.
else {
/* do nothing */
}
}
// It doesn't exist, and we couldn't create it.
else {
throw new TOTorrentException( "Failed to create directory '" + parent + "'", TOTorrentException.RT_WRITE_FAILS );
}
} // end if (!dir_created)
} // end if (!parent.isDirectory)
File temp = new File( parent, output_file.getName() + ".saving");
if ( temp.exists()){
if ( !temp.delete()){
throw( new TOTorrentException( "Insufficient permissions to delete '" + temp + "'", TOTorrentException.RT_WRITE_FAILS ));
}
}else{
boolean ok = false;
try{
ok = temp.createNewFile();
}catch( Throwable e ){
}
if ( !ok ){
throw( new TOTorrentException( "Insufficient permissions to write '" + temp + "'", TOTorrentException.RT_WRITE_FAILS ));
}
}
FileOutputStream fos = new FileOutputStream( temp, false );
bos = new BufferedOutputStream( fos, 8192 );
bos.write( res );
bos.flush();
fos.getFD().sync();
bos.close();
bos = null;
//only use newly saved file if it got this far, i.e. it was written successfully
if ( temp.length() > 1L ) {
output_file.delete(); // Will fail silently if it doesn't exist.
temp.renameTo( output_file );
}
}catch( TOTorrentException e ){
throw( e );
}catch( Throwable e){
throw( new TOTorrentException( "Failed to serialise torrent: " + Debug.getNestedExceptionMessage(e),
TOTorrentException.RT_WRITE_FAILS ));
}finally{
if ( bos != null ){
try{
bos.close();
}catch( IOException e ){
Debug.printStackTrace( e );
}
}
}
}
protected byte[]
serialiseToByteArray()
throws TOTorrentException
{
if ( created ){
TorrentUtils.addCreatedTorrent( this );
}
Map root = serialiseToMap();
try{
return( BEncoder.encode( root ));
}catch( IOException e ){
throw( new TOTorrentException(
"Failed to serialise torrent: " + Debug.getNestedExceptionMessage(e),
TOTorrentException.RT_WRITE_FAILS ));
}
}
public Map
serialiseToMap()
throws TOTorrentException
{
// protect against recursion when getting the hash
if ( created && !serialising ){
try{
serialising = true; // not thread safe but we can live without the hassle of using TLS or whatever
TorrentUtils.addCreatedTorrent( this );
}finally{
serialising = false;
}
}
Map root = new HashMap();
writeStringToMetaData( root, TK_ANNOUNCE, announce_url.toString());
TOTorrentAnnounceURLSet[] sets = announce_group.getAnnounceURLSets();
if (sets.length > 0 ){
List announce_list = new ArrayList();
for (int i=0;i<sets.length;i++){
TOTorrentAnnounceURLSet set = sets[i];
URL[] urls = set.getAnnounceURLs();
if ( urls.length == 0 ){
continue;
}
List sub_list = new ArrayList();
announce_list.add( sub_list );
for (int j=0;j<urls.length;j++){
sub_list.add( writeStringToMetaData( urls[j].toString()));
}
}
if ( announce_list.size() > 0 ){
root.put( TK_ANNOUNCE_LIST, announce_list );
}
}
if ( comment != null ){
root.put( TK_COMMENT, comment );
}
if ( creation_date != 0 ){
root.put( TK_CREATION_DATE, new Long( creation_date ));
}
if ( created_by != null ){
root.put( TK_CREATED_BY, created_by );
}
Map info = new HashMap();
root.put( TK_INFO, info );
info.put( TK_PIECE_LENGTH, new Long( piece_length ));
if ( pieces == null ){
throw( new TOTorrentException( "Pieces is null", TOTorrentException.RT_WRITE_FAILS ));
}
byte[] flat_pieces = new byte[pieces.length*20];
for (int i=0;i<pieces.length;i++){
System.arraycopy( pieces[i], 0, flat_pieces, i*20, 20 );
}
info.put( TK_PIECES, flat_pieces );
info.put( TK_NAME, torrent_name );
if ( torrent_name_utf8 != null ){
info.put( TK_NAME_UTF8, torrent_name_utf8 );
}
if ( simple_torrent ){
TOTorrentFile file = files[0];
info.put( TK_LENGTH, new Long( file.getLength()));
}else{
List meta_files = new ArrayList();
info.put( TK_FILES, meta_files );
for (int i=0;i<files.length;i++){
TOTorrentFileImpl file = files[i];
Map file_map = new HashMap();
meta_files.add( file_map );
file_map.put( TK_LENGTH, new Long( file.getLength()));
List path = new ArrayList();
file_map.put( TK_PATH, path );
byte[][] path_comps = file.getPathComponents();
for (int j=0;j<path_comps.length;j++){
path.add( path_comps[j]);
}
if ( file.isUTF8()){
List utf8_path = new ArrayList();
file_map.put( TK_PATH_UTF8, utf8_path );
for (int j=0;j<path_comps.length;j++){
utf8_path.add( path_comps[j]);
}
}
Map file_additional_properties = file.getAdditionalProperties();
Iterator prop_it = file_additional_properties.keySet().iterator();
while( prop_it.hasNext()){
String key = (String)prop_it.next();
file_map.put( key, file_additional_properties.get( key ));
}
}
}
Iterator info_it = additional_info_properties.keySet().iterator();
while( info_it.hasNext()){
String key = (String)info_it.next();
info.put( key, additional_info_properties.get( key ));
}
Iterator it = additional_properties.keySet().iterator();
while( it.hasNext()){
String key = (String)it.next();
Object value = additional_properties.get( key );
if ( value != null ){
root.put( key, value );
}
}
return( root );
}
public void
serialiseToXMLFile(
File file )
throws TOTorrentException
{
if ( created ){
TorrentUtils.addCreatedTorrent( this );
}
TOTorrentXMLSerialiser serialiser = new TOTorrentXMLSerialiser( this );
serialiser.serialiseToFile( file );
}
public byte[]
getName()
{
return( torrent_name );
}
protected void
setName(
byte[] _name )
{
torrent_name = _name;
}
public boolean
isSimpleTorrent()
{
return( simple_torrent );
}
public byte[]
getComment()
{
return( comment );
}
protected void
setComment(
byte[] _comment )
{
comment = _comment;
}
public void
setComment(
String _comment )
{
try{
byte[] utf8_comment = _comment.getBytes( Constants.DEFAULT_ENCODING );
setComment( utf8_comment );
setAdditionalByteArrayProperty( TK_COMMENT_UTF8, utf8_comment );
}catch( UnsupportedEncodingException e ){
Debug.printStackTrace( e );
comment = null;
}
}
public URL
getAnnounceURL()
{
return( announce_url );
}
public boolean
setAnnounceURL(
URL url )
{
URL newURL = anonymityTransform( url );
String s0 = (newURL == null) ? "" : newURL.toString();
String s1 = (announce_url == null) ? "" : announce_url.toString();
if (s0.equals(s1))
return false;
announce_url = newURL;
return true;
}
public long
getCreationDate()
{
return( creation_date );
}
public void
setCreationDate(
long _creation_date )
{
creation_date = _creation_date;
}
protected void
setCreatedBy(
byte[] _created_by )
{
created_by = _created_by;
}
protected void
setCreatedBy(
String _created_by )
{
try{
setCreatedBy( _created_by.getBytes( Constants.DEFAULT_ENCODING ));
}catch( UnsupportedEncodingException e ){
Debug.printStackTrace( e );
created_by = null;
}
}
public byte[]
getCreatedBy()
{
return( created_by );
}
public boolean
isCreated()
{
return( created );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -