1 /* 2 * Created on 02-Aug-2004 3 * Created by Paul Gardner 4 * Copyright (C) Azureus Software, Inc, All Rights Reserved. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 * 18 */ 19 20 package org.gudy.azureus2.core3.disk.impl.piecemapper.impl; 21 22 import java.io.*; 23 import java.util.ArrayList; 24 import java.util.List; 25 26 import org.gudy.azureus2.core3.disk.impl.DiskManagerFileInfoImpl; 27 import org.gudy.azureus2.core3.disk.impl.piecemapper.DMPieceList; 28 import org.gudy.azureus2.core3.disk.impl.piecemapper.DMPieceMap; 29 import org.gudy.azureus2.core3.disk.impl.piecemapper.DMPieceMapper; 30 import org.gudy.azureus2.core3.disk.impl.piecemapper.DMPieceMapperFile; 31 32 import org.gudy.azureus2.core3.internat.LocaleUtilDecoder; 33 import org.gudy.azureus2.core3.torrent.*; 34 import org.gudy.azureus2.core3.util.FileUtil; 35 import org.gudy.azureus2.core3.util.StringInterner; 36 37 /** 38 * @author parg 39 * 40 */ 41 42 43 public class 44 PieceMapperImpl 45 implements DMPieceMapper 46 { 47 private TOTorrent torrent; 48 49 private int last_piece_length; 50 51 protected ArrayList<fileInfo> btFileList = new ArrayList<fileInfo>(); 52 53 54 public PieceMapperImpl( TOTorrent _torrent )55 PieceMapperImpl( 56 TOTorrent _torrent ) 57 { 58 torrent = _torrent; 59 60 int piece_length = (int)torrent.getPieceLength(); 61 62 int piece_count = torrent.getNumberOfPieces(); 63 64 long total_length = torrent.getSize(); 65 66 last_piece_length = (int) (total_length - ((long) (piece_count - 1) * (long)piece_length)); 67 } 68 69 public void construct( LocaleUtilDecoder _locale_decoder, String _save_name )70 construct( 71 LocaleUtilDecoder _locale_decoder, 72 String _save_name ) 73 74 throws UnsupportedEncodingException 75 { 76 //build something to hold the filenames/sizes 77 78 TOTorrentFile[] torrent_files = torrent.getFiles(); 79 80 if ( torrent.isSimpleTorrent()){ 81 82 buildFileLookupTables( torrent_files[0], _save_name ); 83 84 }else{ 85 86 buildFileLookupTables( torrent_files, _locale_decoder ); 87 } 88 } 89 90 // method for simple torrents 91 92 private void buildFileLookupTables( TOTorrentFile torrent_file, String fileName )93 buildFileLookupTables( 94 TOTorrentFile torrent_file, 95 String fileName ) 96 { 97 // not needed as fileName already normalised 98 // fileName = FileUtil.convertOSSpecificChars( fileName, false ); 99 100 btFileList.add(new PieceMapperImpl.fileInfo(torrent_file,"", fileName )); 101 } 102 103 private void buildFileLookupTables( TOTorrentFile[] torrent_files, LocaleUtilDecoder locale_decoder )104 buildFileLookupTables( 105 TOTorrentFile[] torrent_files, 106 LocaleUtilDecoder locale_decoder ) 107 108 throws UnsupportedEncodingException 109 { 110 char separator = File.separatorChar; 111 112 //for each file 113 114 for (int i = 0; i < torrent_files.length; i++) { 115 116 buildFileLookupTable(torrent_files[i], locale_decoder, separator); 117 } 118 } 119 120 /** 121 * Builds the path stored in fileDictionay, saving it in btFileList 122 * @param fileDictionay 123 * @param btFileList 124 * @param localeUtil 125 * @param separator 126 * @return the length of the file as stored in fileDictionay 127 */ 128 // refactored out of initialize() - Moti 129 // code further refactored for readibility 130 131 private void buildFileLookupTable( TOTorrentFile torrent_file, LocaleUtilDecoder locale_decoder, final char separator)132 buildFileLookupTable( 133 TOTorrentFile torrent_file, 134 LocaleUtilDecoder locale_decoder, 135 final char separator) 136 137 throws UnsupportedEncodingException 138 { 139 //build the path 140 141 byte[][] path_components = torrent_file.getPathComponents(); 142 143 /* replaced the following two calls: 144 StringBuffer pathBuffer = new StringBuffer(256); 145 pathBuffer.setLength(0); 146 */ 147 StringBuffer pathBuffer = new StringBuffer(0); 148 149 int lastIndex = path_components.length - 1; 150 for (int j = 0; j < lastIndex; j++) { 151 //attach every element 152 153 String comp = locale_decoder.decodeString( path_components[j]); 154 155 comp = FileUtil.convertOSSpecificChars( comp, true); 156 157 pathBuffer.append(comp); 158 pathBuffer.append(separator); 159 } 160 161 //no, then we must be a part of the path 162 //add the file entry to the file holder list 163 164 String last_comp = locale_decoder.decodeString(path_components[lastIndex]); 165 166 last_comp = FileUtil.convertOSSpecificChars( last_comp, false ); 167 168 btFileList.add( 169 new fileInfo( 170 torrent_file, 171 pathBuffer.toString(), 172 last_comp )); 173 } 174 175 176 177 public DMPieceMap getPieceMap()178 getPieceMap() 179 { 180 if ( btFileList.size() == 1 ){ 181 182 // optimise for the single file case 183 184 return( new DMPieceMapSimple( torrent, ((fileInfo)btFileList.get(0)).getFileInfo())); 185 186 }else{ 187 int piece_length = (int)torrent.getPieceLength(); 188 189 int piece_count = torrent.getNumberOfPieces(); 190 191 long total_length = torrent.getSize(); 192 193 DMPieceList[] pieceMap = new DMPieceList[piece_count]; 194 195 196 //for every piece, except the last one 197 //add files to the piece list until we have built enough space to hold the piece 198 //see how much space is available in the file 199 //if the space available isnt 0 200 //add the file to the piece->file mapping list 201 //if there is enough space available, stop 202 203 //fix for 1 piece torrents 204 205 int modified_piece_length = piece_length; 206 207 if (total_length < modified_piece_length) { 208 209 modified_piece_length = (int)total_length; 210 } 211 212 long fileOffset = 0; 213 int currentFile = 0; 214 for (int i = 0;(1 == piece_count && i < piece_count) || i < piece_count - 1; i++) { 215 ArrayList<PieceMapEntryImpl> pieceToFileList = new ArrayList<PieceMapEntryImpl>(); 216 int usedSpace = 0; 217 while (modified_piece_length > usedSpace) { 218 fileInfo tempFile = (fileInfo)btFileList.get(currentFile); 219 long length = tempFile.getLength(); 220 221 //get the available space 222 long availableSpace = length - fileOffset; 223 224 PieceMapEntryImpl tempPieceEntry = null; 225 226 //how much space do we need to use? 227 if (availableSpace <= (modified_piece_length - usedSpace)) { 228 //use the rest of the file's space 229 tempPieceEntry = 230 new PieceMapEntryImpl(tempFile.getFileInfo(), fileOffset, (int)availableSpace //safe to convert here 231 ); 232 233 //update the used space 234 usedSpace += availableSpace; 235 //update the file offset 236 fileOffset = 0; 237 //move the the next file 238 currentFile++; 239 } else //we don't need to use the whole file 240 { 241 tempPieceEntry = new PieceMapEntryImpl(tempFile.getFileInfo(), fileOffset, modified_piece_length - usedSpace); 242 243 //update the file offset 244 fileOffset += modified_piece_length - usedSpace; 245 //udate the used space 246 usedSpace += modified_piece_length - usedSpace; 247 } 248 249 //add the temp pieceEntry to the piece list 250 pieceToFileList.add(tempPieceEntry); 251 } 252 253 //add the list to the map 254 pieceMap[i] = PieceListImpl.convert(pieceToFileList); 255 } 256 257 //take care of final piece if there was more than 1 piece in the torrent 258 if (piece_count > 1) { 259 pieceMap[piece_count - 1] = 260 PieceListImpl.convert( 261 buildLastPieceToFileList( 262 btFileList, 263 currentFile, 264 fileOffset )); 265 266 } 267 268 return( new DMPieceMapImpl( pieceMap )); 269 } 270 } 271 272 private List<PieceMapEntryImpl> buildLastPieceToFileList( List<fileInfo> file_list, int current_file, long file_offset )273 buildLastPieceToFileList( 274 List<fileInfo> file_list, 275 int current_file, 276 long file_offset ) 277 { 278 ArrayList<PieceMapEntryImpl> piece_to_file_list = new ArrayList<PieceMapEntryImpl>(); 279 280 for ( int i=current_file;i<file_list.size();i++){ 281 282 fileInfo file = file_list.get( i ); 283 284 long space_in_file = file.getLength() - file_offset; 285 286 PieceMapEntryImpl piece_entry = new PieceMapEntryImpl( file.getFileInfo(), file_offset, (int)space_in_file); 287 288 piece_to_file_list.add( piece_entry ); 289 290 file_offset = 0; 291 } 292 293 return( piece_to_file_list ); 294 } 295 296 public long getTotalLength()297 getTotalLength() 298 { 299 return( torrent.getSize()); 300 } 301 302 public int getPieceLength()303 getPieceLength() 304 { 305 return((int)torrent.getPieceLength()); 306 } 307 308 public int getLastPieceLength()309 getLastPieceLength() 310 { 311 return( last_piece_length ); 312 } 313 314 public DMPieceMapperFile[] getFiles()315 getFiles() 316 { 317 DMPieceMapperFile[] res = new DMPieceMapperFile[ btFileList.size()]; 318 319 btFileList.toArray( res ); 320 321 return( res ); 322 } 323 324 protected static class 325 fileInfo 326 implements DMPieceMapperFile 327 { 328 private DiskManagerFileInfoImpl file; 329 private TOTorrentFile torrent_file; 330 private String path; 331 private String name; 332 333 public fileInfo( TOTorrentFile _torrent_file, String _path, String _name )334 fileInfo( 335 TOTorrentFile _torrent_file, 336 String _path, 337 String _name ) 338 { 339 torrent_file = _torrent_file; 340 path = StringInterner.intern(_path); 341 name = _name; 342 } 343 getLength()344 public long getLength() { 345 return torrent_file.getLength(); 346 } 347 public File getDataFile()348 getDataFile() 349 { 350 return( new File( path, name )); 351 } 352 public TOTorrentFile getTorrentFile()353 getTorrentFile() 354 { 355 return( torrent_file ); 356 } getFileInfo()357 public DiskManagerFileInfoImpl getFileInfo() { 358 return file; 359 } setFileInfo(DiskManagerFileInfoImpl _file)360 public void setFileInfo(DiskManagerFileInfoImpl _file) { 361 file = _file; 362 } 363 } 364 } 365