/*
* File : TOTorrentFileImpl.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 com.frostwire.torrent;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;
final class TOTorrentFileImpl implements TOTorrentFile {
private final TOTorrent torrent;
private final long file_length;
private final byte[][] path_components;
private final byte[][] path_components_utf8;
private final int first_piece_number;
private final int last_piece_number;
private final Map<String, Object> additional_properties = new HashMap<String, Object>(1);
private final boolean is_utf8;
protected TOTorrentFileImpl(TOTorrent _torrent, long _torrent_offset, long _len, String _path)
throws TOTorrentException {
torrent = _torrent;
file_length = _len;
first_piece_number = (int) (_torrent_offset / torrent.getPieceLength());
last_piece_number = (int) ((_torrent_offset + file_length - 1) / torrent.getPieceLength());
is_utf8 = true;
try {
Vector<byte[]> temp = new Vector<byte[]>();
int pos = 0;
while (true) {
int p1 = _path.indexOf(File.separator, pos);
if (p1 == -1) {
temp.add(_path.substring(pos).getBytes(Constants.DEFAULT_ENCODING));
break;
}
temp.add(_path.substring(pos, p1).getBytes(Constants.DEFAULT_ENCODING));
pos = p1 + 1;
}
path_components = new byte[temp.size()][];
temp.copyInto(path_components);
path_components_utf8 = new byte[temp.size()][];
temp.copyInto(path_components_utf8);
checkComponents();
} catch (UnsupportedEncodingException e) {
throw (new TOTorrentException("Unsupported encoding for '" + _path + "'", TOTorrentException.RT_UNSUPPORTED_ENCODING));
}
}
protected TOTorrentFileImpl(TOTorrent _torrent, long _torrent_offset, long _len, byte[][] _path_components)
throws TOTorrentException {
torrent = _torrent;
file_length = _len;
path_components = _path_components;
path_components_utf8 = null;
first_piece_number = (int) (_torrent_offset / torrent.getPieceLength());
last_piece_number = (int) ((_torrent_offset + file_length - 1) / torrent.getPieceLength());
is_utf8 = false;
checkComponents();
}
protected TOTorrentFileImpl(TOTorrent _torrent, long _torrent_offset, long _len, byte[][] _path_components, byte[][] _path_components_utf8)
throws TOTorrentException {
torrent = _torrent;
file_length = _len;
path_components = _path_components;
path_components_utf8 = _path_components_utf8;
first_piece_number = (int) (_torrent_offset / torrent.getPieceLength());
last_piece_number = (int) ((_torrent_offset + file_length - 1) / torrent.getPieceLength());
is_utf8 = false;
checkComponents();
}
protected void checkComponents()
throws TOTorrentException {
byte[][][] to_do = { path_components, path_components_utf8 };
for (byte[][] pc : to_do) {
if (pc == null) {
continue;
}
for (int i = 0; i < pc.length; i++) {
byte[] comp = pc[i];
if (comp.length == 2 && comp[0] == (byte) '.' && comp[1] == (byte) '.')
throw (new TOTorrentException("Torrent file contains illegal '..' component", TOTorrentException.RT_DECODE_FAILS));
// intern directories as they're likely to repeat
// if(i < (pc.length - 1)){
// //pc[i] = StringInterner.internBytes(pc[i]);
// }
}
}
}
public TOTorrent getTorrent() {
return (torrent);
}
public long getLength() {
return (file_length);
}
public byte[][] getPathComponentsBasic() {
return (path_components);
}
public byte[][] getPathComponents() {
return path_components_utf8 == null ? path_components : path_components_utf8;
}
public byte[][] getPathComponentsUTF8() {
return (path_components_utf8);
}
protected boolean isUTF8() {
return (is_utf8);
}
protected void setAdditionalProperty(String name, Object value) {
additional_properties.put(name, value);
}
protected Map<String, Object> getAdditionalProperties() {
return (additional_properties);
}
public int getFirstPieceNumber() {
return (first_piece_number);
}
public int getLastPieceNumber() {
return (last_piece_number);
}
public int getNumberOfPieces() {
return (getLastPieceNumber() - getFirstPieceNumber() + 1);
}
public String getRelativePath() {
if (torrent == null) {
return "";
}
String sRelativePath = "";
byte[][] pathComponentsUTF8 = getPathComponentsUTF8();
if (pathComponentsUTF8 != null) {
for (int j = 0; j < pathComponentsUTF8.length; j++) {
try {
String comp;
try {
comp = new String(pathComponentsUTF8[j], "utf8");
} catch (UnsupportedEncodingException e) {
System.out.println("file - unsupported encoding!!!!");
comp = "UnsupportedEncoding";
}
comp = convertOSSpecificChars(comp, j != pathComponentsUTF8.length - 1);
sRelativePath += (j == 0 ? "" : File.separator) + comp;
} catch (Exception ex) {
Debug.out(ex);
}
}
return sRelativePath;
}
LocaleUtilDecoder decoder = null;
try {
decoder = LocaleTorrentUtil.getTorrentEncodingIfAvailable(torrent);
if (decoder == null) {
LocaleUtil localeUtil = LocaleUtil.getSingleton();
decoder = localeUtil.getSystemDecoder();
}
} catch (Exception e) {
// Do Nothing
}
if (decoder != null) {
byte[][] components = getPathComponents();
for (int j = 0; j < components.length; j++) {
try {
String comp;
try {
comp = decoder.decodeString(components[j]);
} catch (UnsupportedEncodingException e) {
System.out.println("file - unsupported encoding!!!!");
try {
comp = new String(components[j]);
} catch (Exception e2) {
comp = "UnsupportedEncoding";
}
}
comp = convertOSSpecificChars(comp, j != components.length - 1);
sRelativePath += (j == 0 ? "" : File.separator) + comp;
} catch (Exception ex) {
Debug.out(ex);
}
}
}
return sRelativePath;
}
/**
* @return
*
* @since 4.1.0.5
*/
public Map<String, Object> serializeToMap() {
Map<String, Object> file_map = new HashMap<String, Object>();
file_map.put(TOTorrentImpl.TK_LENGTH, new Long(getLength()));
List<byte[]> path = new ArrayList<byte[]>();
file_map.put(TOTorrentImpl.TK_PATH, path);
byte[][] path_comps = getPathComponentsBasic();
if (path_comps != null) {
for (int j = 0; j < path_comps.length; j++) {
path.add(path_comps[j]);
}
}
if (path_comps != null && isUTF8()) {
List<byte[]> utf8_path = new ArrayList<byte[]>();
file_map.put(TOTorrentImpl.TK_PATH_UTF8, utf8_path);
for (int j = 0; j < path_comps.length; j++) {
utf8_path.add(path_comps[j]);
}
} else {
byte[][] utf8_path_comps = getPathComponentsUTF8();
if (utf8_path_comps != null) {
List<byte[]> utf8_path = new ArrayList<byte[]>();
file_map.put(TOTorrentImpl.TK_PATH_UTF8, utf8_path);
for (int j = 0; j < utf8_path_comps.length; j++) {
utf8_path.add(utf8_path_comps[j]);
}
}
}
Map<String, Object> file_additional_properties = getAdditionalProperties();
Iterator<String> 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));
}
return file_map;
}
private static String convertOSSpecificChars(String file_name_in, boolean is_folder) {
// this rule originally from DiskManager
char[] chars = file_name_in.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (chars[i] == '"') {
chars[i] = '\'';
}
}
if (!Constants.isOSX) {
if (Constants.isWindows) {
// this rule originally from DiskManager
// The definitive list of characters permitted for Windows is defined here:
// http://support.microsoft.com/kb/q120138/
String not_allowed = "\\/:?*<>|";
for (int i = 0; i < chars.length; i++) {
if (not_allowed.indexOf(chars[i]) != -1) {
chars[i] = '_';
}
}
// windows doesn't like trailing dots and whitespaces in folders, replace them
if (is_folder) {
for (int i = chars.length - 1; i >= 0 && (chars[i] == '.' || chars[i] == ' '); chars[i] = '_', i--)
;
}
}
// '/' is valid in mac file names, replace with space
// so it seems are cr/lf
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
if (c == '/' || c == '\r' || c == '\n') {
chars[i] = ' ';
}
}
}
String file_name_out = new String(chars);
try {
// mac file names can end in space - fix this up by getting
// the canonical form which removes this on Windows
// however, for soem reason getCanonicalFile can generate high CPU usage on some user's systems
// in java.io.Win32FileSystem.canonicalize
// so changing this to only be used on non-windows
if (Constants.isWindows) {
while (file_name_out.endsWith(" ")) {
file_name_out = file_name_out.substring(0, file_name_out.length() - 1);
}
} else {
String str = new File(file_name_out).getCanonicalFile().toString();
int p = str.lastIndexOf(File.separator);
file_name_out = str.substring(p + 1);
}
} catch (Throwable e) {
// ho hum, carry on, it'll fail later
//e.printStackTrace();
}
//System.out.println( "convertOSSpecificChars: " + file_name_in + " ->" + file_name_out );
return (file_name_out);
}
}