476 lines
14 KiB
Java
476 lines
14 KiB
Java
package com.frostwire.jlibtorrent;
|
|
|
|
import com.frostwire.jlibtorrent.swig.byte_vector;
|
|
import com.frostwire.jlibtorrent.swig.file_flags_t;
|
|
import com.frostwire.jlibtorrent.swig.file_slice_vector;
|
|
import com.frostwire.jlibtorrent.swig.file_storage;
|
|
import com.frostwire.jlibtorrent.swig.string_vector;
|
|
import com.frostwire.jlibtorrent.swig.torrent_info;
|
|
|
|
import java.io.File;
|
|
import java.util.ArrayList;
|
|
|
|
/**
|
|
* This class represents a file list and the piece
|
|
* size. Everything necessary to interpret a regular bittorrent storage
|
|
* file structure.
|
|
*
|
|
* @author gubatron
|
|
* @author aldenml
|
|
*/
|
|
public final class FileStorage {
|
|
|
|
private final file_storage fs;
|
|
private final torrent_info ti;
|
|
|
|
/**
|
|
* @param fs the native object
|
|
*/
|
|
public FileStorage(file_storage fs) {
|
|
this(fs, null);
|
|
}
|
|
|
|
/**
|
|
* Used to keep the torrent info reference around.
|
|
*
|
|
* @param fs the native object
|
|
* @param ti the torrent info to pin
|
|
*/
|
|
FileStorage(file_storage fs, torrent_info ti) {
|
|
this.fs = fs;
|
|
this.ti = ti;
|
|
}
|
|
|
|
/**
|
|
* @return the native object
|
|
*/
|
|
public file_storage swig() {
|
|
return fs;
|
|
}
|
|
|
|
/**
|
|
* This methods returns the internal torrent info or null
|
|
* if it was constructed without one.
|
|
* <p>
|
|
* This also prevent premature garbage collection in case
|
|
* the storage was created from a torrent info.
|
|
*
|
|
* @return the pinned torrent info
|
|
*/
|
|
public torrent_info ti() {
|
|
return ti;
|
|
}
|
|
|
|
/**
|
|
* Returns true if the piece length has been initialized
|
|
* on the file_storage. This is typically taken as a proxy
|
|
* of whether the file_storage as a whole is initialized or
|
|
* not.
|
|
*
|
|
* @return true if valid
|
|
*/
|
|
public boolean isValid() {
|
|
return fs.is_valid();
|
|
}
|
|
|
|
/**
|
|
* Allocates space for {@code numFiles} in the internal file list. This can
|
|
* be used to avoid reallocating the internal file list when the number
|
|
* of files to be added is known up-front.
|
|
*
|
|
* @param numFiles the number of files
|
|
*/
|
|
public void reserve(int numFiles) {
|
|
fs.reserve(numFiles);
|
|
}
|
|
|
|
/**
|
|
* Adds a file to the file storage. The {@code flags} argument sets attributes on the file.
|
|
* The file attributes is an extension and may not work in all bittorrent clients.
|
|
* <p>
|
|
* If more files than one are added, certain restrictions to their paths apply.
|
|
* In a multi-file file storage (torrent), all files must share the same root directory.
|
|
* <p>
|
|
* That is, the first path element of all files must be the same.
|
|
* This shared path element is also set to the name of the torrent. It
|
|
* can be changed by calling {@link #name(String)}.
|
|
* <p>
|
|
* The built in functions to traverse a directory to add files will
|
|
* make sure this requirement is fulfilled.
|
|
*
|
|
* @param path the path
|
|
* @param size the file size
|
|
* @param flags the file flags
|
|
* @param mtime the time
|
|
* @param symlink the symlink
|
|
*/
|
|
public void addFile(String path, long size, file_flags_t flags, int mtime, String symlink) {
|
|
fs.add_file(path, size, flags, mtime, symlink);
|
|
}
|
|
|
|
/**
|
|
* Adds a file to the file storage. The {@code flags} argument sets attributes on the file.
|
|
* The file attributes is an extension and may not work in all bittorrent clients.
|
|
* <p>
|
|
* If more files than one are added, certain restrictions to their paths apply.
|
|
* In a multi-file file storage (torrent), all files must share the same root directory.
|
|
* <p>
|
|
* That is, the first path element of all files must be the same.
|
|
* This shared path element is also set to the name of the torrent. It
|
|
* can be changed by calling {@link #name(String)}.
|
|
* <p>
|
|
* The built in functions to traverse a directory to add files will
|
|
* make sure this requirement is fulfilled.
|
|
*
|
|
* @param path the path
|
|
* @param size the file size
|
|
* @param flags the file flags
|
|
* @param mtime the time
|
|
*/
|
|
public void addFile(String path, long size, file_flags_t flags, int mtime) {
|
|
fs.add_file(path, size, flags, mtime);
|
|
}
|
|
|
|
/**
|
|
* Adds a file to the file storage. The {@code flags} argument sets attributes on the file.
|
|
* The file attributes is an extension and may not work in all bittorrent clients.
|
|
* <p>
|
|
* If more files than one are added, certain restrictions to their paths apply.
|
|
* In a multi-file file storage (torrent), all files must share the same root directory.
|
|
* <p>
|
|
* That is, the first path element of all files must be the same.
|
|
* This shared path element is also set to the name of the torrent. It
|
|
* can be changed by calling {@link #name(String)}.
|
|
* <p>
|
|
* The built in functions to traverse a directory to add files will
|
|
* make sure this requirement is fulfilled.
|
|
*
|
|
* @param path the path
|
|
* @param size the file size
|
|
* @param flags the file flags
|
|
*/
|
|
public void addFile(String path, long size, file_flags_t flags) {
|
|
fs.add_file(path, size, flags);
|
|
}
|
|
|
|
/**
|
|
* Adds a file to the file storage.
|
|
* <p>
|
|
* If more files than one are added, certain restrictions to their paths apply.
|
|
* In a multi-file file storage (torrent), all files must share the same root directory.
|
|
* <p>
|
|
* That is, the first path element of all files must be the same.
|
|
* This shared path element is also set to the name of the torrent. It
|
|
* can be changed by calling {@link #name(String)}.
|
|
* <p>
|
|
* The built in functions to traverse a directory to add files will
|
|
* make sure this requirement is fulfilled.
|
|
*
|
|
* @param p
|
|
* @param size
|
|
*/
|
|
public void addFile(String p, long size) {
|
|
fs.add_file(p, size);
|
|
}
|
|
|
|
/**
|
|
* Renames the file at {@code index} to {@code newFilename}. Keep in mind
|
|
* that filenames are expected to be UTF-8 encoded.
|
|
*
|
|
* @param index
|
|
* @param newFilename
|
|
*/
|
|
public void renameFile(int index, String newFilename) {
|
|
fs.rename_file(index, newFilename);
|
|
}
|
|
|
|
/**
|
|
* Returns a list of {@link com.frostwire.jlibtorrent.FileSlice} objects representing the portions of
|
|
* files the specified piece index, byte offset and size range overlaps.
|
|
* <p>
|
|
* This is the inverse mapping of {@link #mapFile(int, long, int)}.
|
|
*
|
|
* @param piece
|
|
* @param offset
|
|
* @param size
|
|
* @return
|
|
*/
|
|
public ArrayList<FileSlice> mapBlock(int piece, long offset, int size) {
|
|
return mapBlock(fs.map_block(piece, offset, size));
|
|
}
|
|
|
|
/**
|
|
* Returns a {@link com.frostwire.jlibtorrent.PeerRequest} representing the
|
|
* piece index, byte offset and size the specified file range overlaps.
|
|
* This is the inverse mapping of {@link #mapBlock(int, long, int)}.
|
|
* <p>
|
|
* Note that the {@link PeerRequest} return type
|
|
* is meant to hold bittorrent block requests, which may not be larger
|
|
* than 16 kiB. Mapping a range larger than that may return an overflown
|
|
* integer.
|
|
*
|
|
* @param file
|
|
* @param offset
|
|
* @param size
|
|
* @return
|
|
*/
|
|
public PeerRequest mapFile(int file, long offset, int size) {
|
|
return new PeerRequest(fs.map_file(file, offset, size));
|
|
}
|
|
|
|
/**
|
|
* Returns the number of files in the file_storage.
|
|
*
|
|
* @return
|
|
*/
|
|
public int numFiles() {
|
|
return fs.num_files();
|
|
}
|
|
|
|
/**
|
|
* Returns the total number of bytes all the files in this torrent spans.
|
|
*
|
|
* @return
|
|
*/
|
|
public long totalSize() {
|
|
return fs.total_size();
|
|
}
|
|
|
|
/**
|
|
* Returns the number of pieces in the torrent.
|
|
*
|
|
* @return the number of pieces in the torrent
|
|
*/
|
|
public int numPieces() {
|
|
return fs.num_pieces();
|
|
}
|
|
|
|
/**
|
|
* Set the number of pieces in the torrent.
|
|
*
|
|
* @param n
|
|
*/
|
|
public void numPieces(int n) {
|
|
fs.set_num_pieces(n);
|
|
}
|
|
|
|
/**
|
|
* Get the size of each piece in this torrent. This size is typically an even power
|
|
* of 2. It doesn't have to be though. It should be divisible by 16kiB however.
|
|
*
|
|
* @return
|
|
*/
|
|
public int pieceLength() {
|
|
return fs.piece_length();
|
|
}
|
|
|
|
/**
|
|
* Set the size of each piece in this torrent. This size is typically an even power
|
|
* of 2. It doesn't have to be though. It should be divisible by 16kiB however.
|
|
*
|
|
* @param l
|
|
*/
|
|
public void pieceLength(int l) {
|
|
fs.set_piece_length(l);
|
|
}
|
|
|
|
/**
|
|
* Returns the piece size of {@code index}. This will be the same as {@link #pieceLength()},
|
|
* except for the last piece, which may be shorter.
|
|
*
|
|
* @param index
|
|
* @return
|
|
*/
|
|
public int pieceSize(int index) {
|
|
return fs.piece_size(index);
|
|
}
|
|
|
|
/**
|
|
* Get the name of this torrent. For multi-file torrents, this is also
|
|
* the name of the root directory all the files are stored in.
|
|
*
|
|
* @return
|
|
*/
|
|
public String name() {
|
|
return fs.name();
|
|
}
|
|
|
|
/**
|
|
* Set the name of this torrent. For multi-file torrents, this is also
|
|
* the name of the root directory all the files are stored in.
|
|
*
|
|
* @param name
|
|
*/
|
|
public void name(String name) {
|
|
fs.set_name(name);
|
|
}
|
|
|
|
/**
|
|
* Is a sha-1 hash of the file, or 0 if none was
|
|
* provided in the torrent file. This can potentially be used to
|
|
* join a bittorrent network with other file sharing networks.
|
|
*
|
|
* @param index
|
|
* @return
|
|
*/
|
|
public Sha1Hash hash(int index) {
|
|
return new Sha1Hash(fs.hash(index));
|
|
}
|
|
|
|
/**
|
|
* returns the full path to a file.
|
|
*
|
|
* @param index
|
|
* @param savePath
|
|
* @return
|
|
*/
|
|
public String filePath(int index, String savePath) {
|
|
// not calling the corresponding swig function because internally,
|
|
// the use of the function GetStringUTFChars does not consider the case of
|
|
// a copy not made
|
|
return savePath + File.separator + fs.file_path(index);
|
|
}
|
|
|
|
/**
|
|
* Returns the full path to a file.
|
|
*
|
|
* @param index the file index
|
|
* @return the full path
|
|
*/
|
|
public String filePath(int index) {
|
|
return fs.file_path(index);
|
|
}
|
|
|
|
/**
|
|
* Returns only the name of the file, whereas
|
|
* {@link #filePath(int)} returns the path (inside the torrent file) with
|
|
* the filename appended.
|
|
*
|
|
* @param index the file index
|
|
* @return the file name
|
|
*/
|
|
public String fileName(int index) {
|
|
byte_vector v = fs.file_name(index).to_bytes();
|
|
return Vectors.byte_vector2utf8(v);
|
|
}
|
|
|
|
/**
|
|
* returns the size of a file.
|
|
*
|
|
* @param index
|
|
* @return
|
|
*/
|
|
public long fileSize(int index) {
|
|
return fs.file_size(index);
|
|
}
|
|
|
|
/**
|
|
* returns true if the file at the given
|
|
* index is a pad-file.
|
|
*
|
|
* @param index
|
|
* @return
|
|
*/
|
|
public boolean padFileAt(int index) {
|
|
return fs.pad_file_at(index);
|
|
}
|
|
|
|
/**
|
|
* returns the byte offset within the torrent file
|
|
* where this file starts. It can be used to map the file to a piece
|
|
* index (given the piece size).
|
|
*
|
|
* @param index
|
|
* @return
|
|
*/
|
|
public long fileOffset(int index) {
|
|
return fs.file_offset(index);
|
|
}
|
|
|
|
/**
|
|
* @return
|
|
*/
|
|
public ArrayList<String> paths() {
|
|
string_vector v = fs.paths();
|
|
int size = (int) v.size();
|
|
ArrayList<String> l = new ArrayList<>(size);
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
l.add(v.get(i));
|
|
}
|
|
|
|
return l;
|
|
}
|
|
|
|
/**
|
|
* This file is a pad file. The creator of the
|
|
* torrent promises the file is entirely filled with
|
|
* zeroes and does not need to be downloaded. The
|
|
* purpose is just to align the next file to either
|
|
* a block or piece boundary.
|
|
*/
|
|
public static final file_flags_t FLAG_PAD_FILE = file_storage.flag_pad_file;
|
|
|
|
/**
|
|
* This file is hidden (sets the hidden attribute
|
|
* on windows).
|
|
*/
|
|
public static final file_flags_t FLAG_HIDDEN = file_storage.flag_hidden;
|
|
|
|
/**
|
|
* This file is executable (sets the executable bit
|
|
* on posix like systems).
|
|
*/
|
|
public static final file_flags_t FLAG_EXECUTABLE = file_storage.flag_executable;
|
|
|
|
/**
|
|
* This file is a symlink. The symlink target is
|
|
* specified in a separate field
|
|
*/
|
|
public static final file_flags_t FLAG_SYMLINK = file_storage.flag_symlink;
|
|
|
|
/**
|
|
* Returns a bitmask of flags from {@link file_flags_t} that apply
|
|
* to file at {@code index}.
|
|
*
|
|
* @param index
|
|
* @return the flags
|
|
*/
|
|
public file_flags_t fileFlags(int index) {
|
|
return fs.file_flags(index);
|
|
}
|
|
|
|
/**
|
|
* Returns true if the file at the specified index has been renamed to
|
|
* have an absolute path, i.e. is not anchored in the save path of the
|
|
* torrent.
|
|
*
|
|
* @param index
|
|
* @return
|
|
*/
|
|
public boolean fileAbsolutePath(int index) {
|
|
return fs.file_absolute_path(index);
|
|
}
|
|
|
|
/**
|
|
* Returns the index of the file at the given offset in the torrent.
|
|
*
|
|
* @param offset
|
|
* @return
|
|
*/
|
|
public int fileIndexAtOffset(long offset) {
|
|
return fs.file_index_at_offset(offset);
|
|
}
|
|
|
|
static ArrayList<FileSlice> mapBlock(file_slice_vector v) {
|
|
int size = (int) v.size();
|
|
|
|
ArrayList<FileSlice> l = new ArrayList<>(size);
|
|
for (int i = 0; i < size; i++) {
|
|
l.add(new FileSlice(v.get(i)));
|
|
}
|
|
|
|
return l;
|
|
}
|
|
}
|