├── netz-bin
├── readme.txt
├── netz.exe
├── zip.dll
├── defcomp.dll
├── subsys.dll
├── net20comp.dll
└── license.txt
├── TorrentHardLinkHelper
├── ico2.ico
├── TorrentHardLinkHelper.ico
├── TorrentHardLinkHelper_TemporaryKey.pfx
├── Properties
│ ├── Settings.settings
│ ├── Settings.Designer.cs
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ └── Resources.resx
├── packages.config
├── App.xaml.cs
├── Models
│ ├── FolderModel.cs
│ ├── FileModel.cs
│ └── EntityModel.cs
├── app.config
├── Views
│ ├── HardLinkTool.xaml.cs
│ ├── MainWindow.xaml.cs
│ ├── HardLinkTool.xaml
│ └── MainWindow.xaml
├── App.xaml
├── ViewModels
│ ├── ViewModelLocator.cs
│ └── HardLinkToolViewModel.cs
└── TorrentHardLinkHelper.csproj
├── README.md
├── TorrentHardLinkHelper.Test
├── TestTorrents
│ ├── [U2].13680.torrent
│ └── [U2].14332.torrent
├── HardLinkTest.cs
├── Properties
│ └── AssemblyInfo.cs
├── LocateTest.cs
├── TorrentTest.cs
└── TorrentHardLinkHelper.Test.csproj
├── TorrentHardLinkHelper.Library
├── Locate
│ ├── LocateState.cs
│ ├── LinkState.cs
│ ├── FileLinkPiece.cs
│ ├── FileSystemFileSearcher.cs
│ ├── FileSystemFileInfo.cs
│ ├── LocateResult.cs
│ ├── TorrentFileLink.cs
│ ├── HashFileLinkPieces.cs
│ └── TorrentFileLocater.cs
├── Messages
│ ├── IMessage.cs
│ ├── MessageException.cs
│ └── Message.cs
├── Common
│ ├── EncryptionTypes.cs
│ ├── Toolbox.cs
│ ├── UriHelper.cs
│ └── Check.cs
├── Torrents
│ ├── TorrentException.cs
│ ├── HashAlgoFactory.cs
│ ├── Enums.cs
│ ├── RawTrackerTier.cs
│ ├── RawTrackerTiers.cs
│ ├── Hashes.cs
│ ├── InfoHash.cs
│ └── TorrentFile.cs
├── Properties
│ └── AssemblyInfo.cs
├── BEncoding
│ ├── BEncodingException.cs
│ ├── RawReader.cs
│ ├── BEncodedList.cs
│ ├── BEncodedNumber.cs
│ ├── BEncodedString.cs
│ ├── IBEncodedValue.cs
│ └── BEncodedDictionary.cs
├── TorrentHardLinkHelper.Library.csproj
└── HardLink
│ └── HardLinkHelper.cs
├── package.bat
├── LICENSE
├── TorrentHardLinkHelper.sln
└── .gitignore
/netz-bin/readme.txt:
--------------------------------------------------------------------------------
1 | http://madebits.com/netz/
2 |
3 |
--------------------------------------------------------------------------------
/netz-bin/netz.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrywong/torrenthardlinkhelper/HEAD/netz-bin/netz.exe
--------------------------------------------------------------------------------
/netz-bin/zip.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrywong/torrenthardlinkhelper/HEAD/netz-bin/zip.dll
--------------------------------------------------------------------------------
/netz-bin/defcomp.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrywong/torrenthardlinkhelper/HEAD/netz-bin/defcomp.dll
--------------------------------------------------------------------------------
/netz-bin/subsys.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrywong/torrenthardlinkhelper/HEAD/netz-bin/subsys.dll
--------------------------------------------------------------------------------
/netz-bin/net20comp.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrywong/torrenthardlinkhelper/HEAD/netz-bin/net20comp.dll
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/ico2.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrywong/torrenthardlinkhelper/HEAD/TorrentHardLinkHelper/ico2.ico
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | TorrentHardLinkHelper
2 | =====================
3 |
4 | A tool for locating files compared to torrent and make hard links.
5 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/TorrentHardLinkHelper.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrywong/torrenthardlinkhelper/HEAD/TorrentHardLinkHelper/TorrentHardLinkHelper.ico
--------------------------------------------------------------------------------
/netz-bin/license.txt:
--------------------------------------------------------------------------------
1 | .NETZ Copyright (c) 2004-2011 by Vasian Cepa. All rights reserved.
2 |
3 | See complete license at http://madebits.com/netz/download.php#license
4 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Test/TestTorrents/[U2].13680.torrent:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrywong/torrenthardlinkhelper/HEAD/TorrentHardLinkHelper.Test/TestTorrents/[U2].13680.torrent
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Test/TestTorrents/[U2].14332.torrent:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrywong/torrenthardlinkhelper/HEAD/TorrentHardLinkHelper.Test/TestTorrents/[U2].14332.torrent
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/TorrentHardLinkHelper_TemporaryKey.pfx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrywong/torrenthardlinkhelper/HEAD/TorrentHardLinkHelper/TorrentHardLinkHelper_TemporaryKey.pfx
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Locate/LocateState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace TorrentHardLinkHelper.Locate
7 | {
8 | public enum LocateState
9 | {
10 | Succeed,
11 | Fail
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Locate/LinkState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace TorrentHardLinkHelper.Locate
7 | {
8 | public enum LinkState
9 | {
10 | None,
11 | Fail,
12 | NeedConfirm,
13 | Located
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Messages/IMessage.cs:
--------------------------------------------------------------------------------
1 | namespace TorrentHardLinkHelper.Messages
2 | {
3 | interface IMessage
4 | {
5 | int ByteLength { get; }
6 |
7 | byte[] Encode();
8 | int Encode(byte[] buffer, int offset);
9 |
10 | void Decode(byte[] buffer, int offset, int length);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Windows;
7 |
8 | namespace TorrentHardLinkHelper
9 | {
10 | ///
11 | /// Interaction logic for App.xaml
12 | ///
13 | public partial class App : Application
14 | {
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/package.bat:
--------------------------------------------------------------------------------
1 | netz-bin\netz.exe -s -z TorrentHardLinkHelper\bin\Release\TorrentHardLinkHelper.exe TorrentHardLinkHelper\bin\Release\GalaSoft.MvvmLight.Extras.dll TorrentHardLinkHelper\bin\Release\GalaSoft.MvvmLight.dll TorrentHardLinkHelper\bin\Release\Microsoft.Practices.ServiceLocation.dll TorrentHardLinkHelper\bin\Release\Ookii.Dialogs.Wpf.dll TorrentHardLinkHelper\bin\Release\System.Windows.Interactivity.dll TorrentHardLinkHelper\bin\Release\TorrentHardLinkHelper.Library.dll -so
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Common/EncryptionTypes.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace TorrentHardLinkHelper.Common
7 | {
8 | [Flags]
9 | public enum EncryptionTypes
10 | {
11 | None = 0,
12 | PlainText = 1 << 0,
13 | RC4Header = 1 << 1,
14 | RC4Full = 1 << 2,
15 | All = PlainText | RC4Full | RC4Header
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/Models/FolderModel.cs:
--------------------------------------------------------------------------------
1 | namespace TorrentHardLinkHelper.Models
2 | {
3 | public sealed class FolderModel : EntityModel
4 | {
5 | public FolderModel()
6 | {
7 | this.Set(() => this.Located, ref this._locked, false);
8 | this.Set(() => this.Type, ref this._type, "Folder");
9 | }
10 |
11 | public FolderModel(string folderName)
12 | : this()
13 | {
14 | this.Set(() => this.Name, ref this._name, folderName);
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Locate/FileLinkPiece.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace TorrentHardLinkHelper.Locate
7 | {
8 | public class FileLinkPiece
9 | {
10 | public TorrentFileLink FileLink { get; set; }
11 | public ulong StartPos { get; set; }
12 | public ulong ReadLength { get; set; }
13 |
14 | public override string ToString()
15 | {
16 | return this.FileLink + ", startpos: " + this.StartPos + ", length: " + this.ReadLength;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/Views/HardLinkTool.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Windows;
6 | using System.Windows.Controls;
7 | using System.Windows.Data;
8 | using System.Windows.Documents;
9 | using System.Windows.Input;
10 | using System.Windows.Media;
11 | using System.Windows.Media.Imaging;
12 | using System.Windows.Shapes;
13 |
14 | namespace TorrentHardLinkHelper.Views
15 | {
16 | ///
17 | /// Interaction logic for HardLinkTool.xaml
18 | ///
19 | public partial class HardLinkTool : Window
20 | {
21 | public HardLinkTool()
22 | {
23 | InitializeComponent();
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/App.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/Views/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Windows;
6 | using System.Windows.Controls;
7 | using System.Windows.Data;
8 | using System.Windows.Documents;
9 | using System.Windows.Input;
10 | using System.Windows.Media;
11 | using System.Windows.Media.Imaging;
12 | using System.Windows.Navigation;
13 | using System.Windows.Shapes;
14 |
15 | namespace TorrentHardLinkHelper.Views
16 | {
17 | ///
18 | /// Interaction logic for MainWindow.xaml
19 | ///
20 | public partial class MainWindow : Window
21 | {
22 | public MainWindow()
23 | {
24 | InitializeComponent();
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Messages/MessageException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace TorrentHardLinkHelper.Messages
4 | {
5 | public class MessageException : Exception
6 | {
7 | public MessageException()
8 | : base()
9 | {
10 | }
11 |
12 |
13 | public MessageException(string message)
14 | : base(message)
15 | {
16 | }
17 |
18 |
19 | public MessageException(string message, Exception innerException)
20 | : base(message, innerException)
21 | {
22 | }
23 |
24 |
25 | public MessageException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
26 | : base(info, context)
27 | {
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Torrents/TorrentException.cs:
--------------------------------------------------------------------------------
1 | //
2 | // TorrentException.cs
3 | //
4 | // Authors:
5 | // Alan McGovern alan.mcgovern@gmail.com
6 | //
7 | // Copyright (C) 2006 Alan McGovern
8 |
9 | using System;
10 |
11 | namespace TorrentHardLinkHelper.Torrents
12 | {
13 | [Serializable]
14 | public class TorrentException : Exception
15 | {
16 | public TorrentException()
17 | : base()
18 | {
19 | }
20 |
21 | public TorrentException(string message)
22 | : base(message)
23 | {
24 | }
25 |
26 | public TorrentException(string message, Exception innerException)
27 | : base(message, innerException)
28 | {
29 | }
30 |
31 | public TorrentException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
32 | : base(info, context)
33 | {
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/Models/FileModel.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using TorrentHardLinkHelper.Torrents;
3 |
4 | namespace TorrentHardLinkHelper.Models
5 | {
6 | public sealed class FileModel : EntityModel
7 | {
8 | public FileModel()
9 | {
10 | this.Set(() => this.Located, ref this._locked, false);
11 | this.Set(() => this.Type, ref this._type, "File");
12 | }
13 |
14 | public FileModel(string fullName)
15 | : this()
16 | {
17 | this.Set(() => this.Name, ref this._name, Path.GetFileName(fullName));
18 | this.Set(() => this.FullName, ref this._fullName, fullName);
19 | }
20 |
21 | public FileModel(TorrentFile torrentFile)
22 | : this()
23 | {
24 | this.Set(() => this.Name, ref this._name, Path.GetFileName(torrentFile.Path));
25 | this.Set(() => this.FullName, ref this._fullName, torrentFile.Path);
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Locate/FileSystemFileSearcher.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 |
5 | namespace TorrentHardLinkHelper.Locate
6 | {
7 | public class FileSystemFileSearcher
8 | {
9 | public static IList SearchFolder(string path)
10 | {
11 | if (path == null)
12 | {
13 | throw new ArgumentNullException("path");
14 | }
15 | if (!Directory.Exists(path))
16 | {
17 | throw new DirectoryNotFoundException(path + " cannot be found.");
18 | }
19 |
20 | var fsFileInfos = new List();
21 | foreach (string fileName in Directory.GetFiles(path, "*", SearchOption.AllDirectories))
22 | {
23 | var fileInfo = new FileInfo(fileName);
24 | fsFileInfos.Add(new FileSystemFileInfo(fileInfo));
25 | }
26 | return fsFileInfos;
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Test/HardLinkTest.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 |
4 | namespace TorrentHardLinkHelper.Test
5 | {
6 | [TestClass]
7 | public class HardLinkTest
8 | {
9 | [TestMethod]
10 | public void TestHardTest()
11 | {
12 | ProcessStartInfo procStartInfo =
13 | new ProcessStartInfo("cmd", "/c " + @"fsutil hardlink create D:\b.cs D:\a.cs");
14 |
15 | // The following commands are needed to redirect the standard output.
16 | // This means that it will be redirected to the Process.StandardOutput StreamReader.
17 | procStartInfo.RedirectStandardOutput = true;
18 | procStartInfo.UseShellExecute = false;
19 | // Do not create the black window.
20 | procStartInfo.CreateNoWindow = true;
21 | // Now we create a process, assign its ProcessStartInfo and start it
22 | Process proc = new Process();
23 | proc.StartInfo = procStartInfo;
24 | proc.Start();
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.17929
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace TorrentHardLinkHelper.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | //
2 | // Torrent HardLink Helper
3 | //
4 | // Authors:
5 | // Harry Wong
6 | //
7 | // Copyright (C) 2013 Harry Wong
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining
10 | // a copy of this software and associated documentation files (the
11 | // "Software"), to deal in the Software without restriction, including
12 | // without limitation the rights to use, copy, modify, merge, publish,
13 | // distribute, sublicense, and/or sell copies of the Software, and to
14 | // permit persons to whom the Software is furnished to do so, subject to
15 | // the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Locate/FileSystemFileInfo.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace TorrentHardLinkHelper.Locate
4 | {
5 | public class FileSystemFileInfo
6 | {
7 | private string _fileName;
8 | private string _filePath;
9 | private long _length;
10 | private bool _located;
11 |
12 | public FileSystemFileInfo()
13 | {
14 | this._located = false;
15 | }
16 |
17 | public FileSystemFileInfo(FileInfo fileInfo)
18 | {
19 | this._fileName = fileInfo.Name;
20 | this._filePath = fileInfo.FullName;
21 | this._length = fileInfo.Length;
22 | }
23 |
24 | public string FileName
25 | {
26 | get { return this._fileName; }
27 | internal set { this._fileName = value; }
28 | }
29 |
30 | public string FilePath
31 | {
32 | get { return this._filePath; }
33 | internal set { this._filePath = value; }
34 | }
35 |
36 | public long Length
37 | {
38 | get { return this._length; }
39 | internal set { this._length = value; }
40 | }
41 |
42 | public bool Located
43 | {
44 | get { return this._located; }
45 | set { this._located = value; }
46 | }
47 |
48 | public override string ToString()
49 | {
50 | return this._filePath + ", length: " + this._length;
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Torrents/HashAlgoFactory.cs:
--------------------------------------------------------------------------------
1 | //
2 | // HashAlgoFactory.cs
3 | //
4 | // Authors:
5 | // Alan McGovern alan.mcgovern@gmail.com
6 | //
7 | // Copyright (C) 2009 Alan McGovern
8 |
9 |
10 | using System;
11 | using System.Collections.Generic;
12 | using System.Security.Cryptography;
13 | using TorrentHardLinkHelper.Common;
14 |
15 | namespace TorrentHardLinkHelper.Torrents
16 | {
17 | public static class HashAlgoFactory
18 | {
19 | static Dictionary algos = new Dictionary();
20 |
21 | static HashAlgoFactory()
22 | {
23 | Register();
24 | Register();
25 | }
26 |
27 | public static void Register()
28 | where T : HashAlgorithm
29 | where U : HashAlgorithm
30 | {
31 | Register(typeof(T), typeof(U));
32 | }
33 |
34 | public static void Register(Type baseType, Type specificType)
35 | {
36 | Check.BaseType(baseType);
37 | Check.SpecificType(specificType);
38 |
39 | lock (algos)
40 | algos[baseType] = specificType;
41 | }
42 |
43 | public static T Create()
44 | where T : HashAlgorithm
45 | {
46 | if (algos.ContainsKey(typeof(T)))
47 | return (T)Activator.CreateInstance(algos[typeof(T)]);
48 | return null;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/ViewModels/ViewModelLocator.cs:
--------------------------------------------------------------------------------
1 | using GalaSoft.MvvmLight.Ioc;
2 | using Microsoft.Practices.ServiceLocation;
3 |
4 | namespace TorrentHardLinkHelper.ViewModels
5 | {
6 | ///
7 | /// This class contains static references to all the view models in the
8 | /// application and provides an entry point for the bindings.
9 | ///
10 | public class ViewModelLocator
11 | {
12 | ///
13 | /// Initializes a new instance of the ViewModelLocator class.
14 | ///
15 | public ViewModelLocator()
16 | {
17 | var container = new SimpleIoc();
18 | container.Register();
19 | container.Register();
20 |
21 | //var builder = new ContainerBuilder();
22 | //builder.RegisterType();
23 |
24 | //IContainer container = builder.Build();
25 | //var locator = new AutofacServiceLocator(container);
26 |
27 | ServiceLocator.SetLocatorProvider(() => container);
28 | }
29 |
30 | public MainViewModel Main
31 | {
32 | get { return ServiceLocator.Current.GetInstance(); }
33 | }
34 |
35 | public HardLinkToolViewModel HardLinkTool
36 | {
37 | get { return ServiceLocator.Current.GetInstance(); }
38 | }
39 |
40 | public static void Cleanup()
41 | {
42 | // TODO Clear the ViewModels
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Test/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("TorrentHardLinkHelper.Test")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("TorrentHardLinkHelper.Test")]
13 | [assembly: AssemblyCopyright("Copyright © 2013")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("dcee5c8a-e906-4aa1-b059-473505480d0a")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("TorrentHardLinkHelper.Library")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("TorrentHardLinkHelper.Library")]
13 | [assembly: AssemblyCopyright("Copyright © 2013")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("c0378a11-3413-4204-90cb-8aafc86a2147")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Locate/LocateResult.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 |
4 | namespace TorrentHardLinkHelper.Locate
5 | {
6 | public class LocateResult
7 | {
8 | private readonly IList _torrentFileLinks;
9 | private readonly LocateState _locateState;
10 | private readonly int _locatedCount;
11 | private readonly int _unlocatedCount;
12 |
13 | public LocateResult(IList torrentFileLinks)
14 | {
15 | this._torrentFileLinks = torrentFileLinks;
16 | this._locateState = this._torrentFileLinks.Any(c => c.State != LinkState.Located)
17 | ? LocateState.Fail
18 | : LocateState.Succeed;
19 | if (this._locateState == LocateState.Succeed)
20 | {
21 | this._locatedCount = this._torrentFileLinks.Count;
22 | this._unlocatedCount = 0;
23 | }
24 | else
25 | {
26 | this._locatedCount = this._torrentFileLinks.Count(c => c.State == LinkState.Located);
27 | this._unlocatedCount = this._torrentFileLinks.Count - this._locatedCount;
28 | }
29 | }
30 |
31 | public IList TorrentFileLinks
32 | {
33 | get { return this._torrentFileLinks; }
34 | }
35 |
36 | public LocateState LocateState
37 | {
38 | get { return this._locateState; }
39 | }
40 |
41 | public int LocatedCount
42 | {
43 | get { return this._locatedCount; }
44 | }
45 |
46 | public int UnlocatedCount
47 | {
48 | get { return this._unlocatedCount; }
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Torrents/Enums.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Enums.cs
3 | //
4 | // Authors:
5 | // Alan McGovern alan.mcgovern@gmail.com
6 | //
7 | // Copyright (C) 2006 Alan McGovern
8 |
9 | namespace TorrentHardLinkHelper.Torrents
10 | {
11 | public enum ListenerStatus
12 | {
13 | Listening,
14 | PortNotFree,
15 | NotListening
16 | }
17 |
18 | public enum PeerStatus
19 | {
20 | Available,
21 | Connecting,
22 | Connected
23 | }
24 |
25 | public enum Direction
26 | {
27 | None,
28 | Incoming,
29 | Outgoing
30 | }
31 |
32 | public enum TorrentState
33 | {
34 | Stopped,
35 | Paused,
36 | Downloading,
37 | Seeding,
38 | Hashing,
39 | Stopping,
40 | Error,
41 | Metadata
42 | }
43 |
44 | public enum Priority
45 | {
46 | DoNotDownload = 0,
47 | Lowest = 1,
48 | Low = 2,
49 | Normal = 4,
50 | High = 8,
51 | Highest = 16,
52 | Immediate = 32
53 | }
54 |
55 | public enum TrackerState
56 | {
57 | Ok,
58 | Offline,
59 | InvalidResponse
60 | }
61 |
62 | public enum TorrentEvent
63 | {
64 | None,
65 | Started,
66 | Stopped,
67 | Completed
68 | }
69 |
70 | public enum PeerConnectionEvent
71 | {
72 | IncomingConnectionReceived,
73 | OutgoingConnectionCreated,
74 | Disconnected
75 | }
76 |
77 | public enum PieceEvent
78 | {
79 | BlockWriteQueued,
80 | BlockNotRequested,
81 | BlockWrittenToDisk,
82 | HashPassed,
83 | HashFailed
84 | }
85 |
86 | public enum PeerListType
87 | {
88 | NascentPeers,
89 | CandidatePeers,
90 | OptimisticUnchokeCandidatePeers
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2012
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TorrentHardLinkHelper", "TorrentHardLinkHelper\TorrentHardLinkHelper.csproj", "{F60A582A-C5E4-4D17-97AB-B30E24F22D08}"
5 | EndProject
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TorrentHardLinkHelper.Library", "TorrentHardLinkHelper.Library\TorrentHardLinkHelper.Library.csproj", "{C0E94189-B243-4492-A113-6EB2DE57BCC0}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TorrentHardLinkHelper.Test", "TorrentHardLinkHelper.Test\TorrentHardLinkHelper.Test.csproj", "{103E5401-FBB4-4DFB-9B10-4B40640B6E2D}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {F60A582A-C5E4-4D17-97AB-B30E24F22D08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {F60A582A-C5E4-4D17-97AB-B30E24F22D08}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {F60A582A-C5E4-4D17-97AB-B30E24F22D08}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {F60A582A-C5E4-4D17-97AB-B30E24F22D08}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {C0E94189-B243-4492-A113-6EB2DE57BCC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {C0E94189-B243-4492-A113-6EB2DE57BCC0}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {C0E94189-B243-4492-A113-6EB2DE57BCC0}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {C0E94189-B243-4492-A113-6EB2DE57BCC0}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {103E5401-FBB4-4DFB-9B10-4B40640B6E2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {103E5401-FBB4-4DFB-9B10-4B40640B6E2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {103E5401-FBB4-4DFB-9B10-4B40640B6E2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {103E5401-FBB4-4DFB-9B10-4B40640B6E2D}.Release|Any CPU.Build.0 = Release|Any CPU
28 | EndGlobalSection
29 | GlobalSection(SolutionProperties) = preSolution
30 | HideSolutionNode = FALSE
31 | EndGlobalSection
32 | EndGlobal
33 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/BEncoding/BEncodingException.cs:
--------------------------------------------------------------------------------
1 | //
2 | // BEncodingException.cs
3 | //
4 | // Authors:
5 | // Alan McGovern alan.mcgovern@gmail.com
6 | //
7 | // Copyright (C) 2006 Alan McGovern
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining
10 | // a copy of this software and associated documentation files (the
11 | // "Software"), to deal in the Software without restriction, including
12 | // without limitation the rights to use, copy, modify, merge, publish,
13 | // distribute, sublicense, and/or sell copies of the Software, and to
14 | // permit persons to whom the Software is furnished to do so, subject to
15 | // the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 |
30 |
31 | using System;
32 | using System.Text;
33 | using System.Runtime.Serialization;
34 |
35 | namespace TorrentHardLinkHelper.BEncoding
36 | {
37 | [Serializable]
38 | public class BEncodingException : Exception
39 | {
40 | public BEncodingException()
41 | : base()
42 | {
43 | }
44 |
45 | public BEncodingException(string message)
46 | : base(message)
47 | {
48 | }
49 |
50 | public BEncodingException(string message, Exception innerException)
51 | : base(message, innerException)
52 | {
53 | }
54 |
55 | protected BEncodingException(SerializationInfo info, StreamingContext context)
56 | : base(info, context)
57 | {
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Locate/TorrentFileLink.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using TorrentHardLinkHelper.Torrents;
3 |
4 | namespace TorrentHardLinkHelper.Locate
5 | {
6 | public class TorrentFileLink
7 | {
8 | private TorrentFile _torrentFile;
9 | private IList _fsFileInfos;
10 | private int _linkedFsFileIndex;
11 | private LinkState _state;
12 |
13 | public TorrentFileLink()
14 | {
15 | this._fsFileInfos = new List();
16 | this._linkedFsFileIndex = -1;
17 | this._state = LinkState.None;
18 | }
19 |
20 | public TorrentFileLink(TorrentFile torrentFile)
21 | : this()
22 | {
23 | this._torrentFile = torrentFile;
24 | }
25 |
26 | public TorrentFile TorrentFile
27 | {
28 | get { return this._torrentFile; }
29 | internal set { this._torrentFile = value; }
30 | }
31 |
32 | public IList FsFileInfos
33 | {
34 | get { return this._fsFileInfos; }
35 | internal set { this._fsFileInfos = value; }
36 | }
37 |
38 | public int LinkedFsFileIndex
39 | {
40 | get { return this._linkedFsFileIndex; }
41 | internal set { this._linkedFsFileIndex = value; }
42 | }
43 |
44 | public FileSystemFileInfo LinkedFsFileInfo
45 | {
46 | get
47 | {
48 | if (this._linkedFsFileIndex < 0 || this._linkedFsFileIndex >= this._fsFileInfos.Count)
49 | {
50 | return null;
51 | }
52 | return this._fsFileInfos[this._linkedFsFileIndex];
53 | }
54 | }
55 |
56 | public LinkState State
57 | {
58 | get { return this._state; }
59 | internal set { this._state = value; }
60 | }
61 |
62 | public override string ToString()
63 | {
64 | return this._torrentFile.FullPath + ", count: " + this._fsFileInfos.Count + ", state: " + this._state;
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Test/LocateTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using Microsoft.VisualStudio.TestTools.UnitTesting;
7 | using TorrentHardLinkHelper.Locate;
8 | using TorrentHardLinkHelper.Torrents;
9 |
10 | namespace TorrentHardLinkHelper.Test
11 | {
12 | [TestClass]
13 | public class LocateTest
14 | {
15 | ///
16 | /// 文件名字改动
17 | ///
18 | [TestMethod]
19 | public void TestLocate1()
20 | {
21 | string sourceFolder = @"I:\[BDMV][アニメ] ココロコネクト";
22 | string torrentPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestTorrents", "[U2].13680.torrent");
23 |
24 | IList fileInfos = GetFileSystemInfos(sourceFolder);
25 | var torrent = Torrent.Load(torrentPath);
26 | var locater = new TorrentFileLocater(torrent, fileInfos);
27 |
28 | var result = locater.Locate();
29 | }
30 |
31 | [TestMethod]
32 | public void TestLocate2()
33 | {
34 | string sourceFolder = @"I:\[BDMV][アニメ] ココロコネクト";
35 | string torrentPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestTorrents", "[U2].13680.torrent");
36 |
37 | IList fileInfos = GetFileSystemInfos(sourceFolder);
38 | var torrent = Torrent.Load(torrentPath);
39 |
40 | var locater = new PrivateObject(typeof(TorrentFileLocater), torrent, fileInfos);
41 | locater.Invoke("FindTorrentFileLinks");
42 | var result = (bool)locater.Invoke("CheckPiece", 10);
43 |
44 | Assert.IsTrue(result);
45 | }
46 |
47 | private IList GetFileSystemInfos(string path)
48 | {
49 | var fileInfos =
50 | Directory.GetFiles(path, "*", SearchOption.AllDirectories)
51 | .Select(file => new FileInfo(file))
52 | .Select(f => new FileSystemFileInfo(f))
53 | .ToList();
54 | return fileInfos;
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | [assembly: AssemblyTitle("TorrentHardLinkHelper")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("")]
14 | [assembly: AssemblyProduct("TorrentHardLinkHelper")]
15 | [assembly: AssemblyCopyright("Harry Copyright © 2017")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | [assembly: ComVisible(false)]
23 |
24 | //In order to begin building localizable applications, set
25 | //CultureYouAreCodingWith in your .csproj file
26 | //inside a . For example, if you are using US english
27 | //in your source files, set the to en-US. Then uncomment
28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in
29 | //the line below to match the UICulture setting in the project file.
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
36 | //(used if a resource is not found in the page,
37 | // or application resource dictionaries)
38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
39 | //(used if a resource is not found in the page,
40 | // app, or any theme specific resource dictionaries)
41 | )]
42 |
43 |
44 | // Version information for an assembly consists of the following four values:
45 | //
46 | // Major Version
47 | // Minor Version
48 | // Build Number
49 | // Revision
50 | //
51 | // You can specify all the values or you can default the Build and Revision Numbers
52 | // by using the '*' as shown below:
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("0.9.0.0")]
55 | [assembly: AssemblyFileVersion("0.9.0.0")]
56 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Test/TorrentTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using Microsoft.VisualStudio.TestTools.UnitTesting;
7 | using TorrentHardLinkHelper.Torrents;
8 |
9 | namespace TorrentHardLinkHelper.Test
10 | {
11 | ///
12 | /// Summary description for TorrentTest
13 | ///
14 | [TestClass]
15 | public class TorrentTest
16 | {
17 | public TorrentTest()
18 | {
19 | //
20 | // TODO: Add constructor logic here
21 | //
22 | }
23 |
24 | private TestContext testContextInstance;
25 |
26 | ///
27 | ///Gets or sets the test context which provides
28 | ///information about and functionality for the current test run.
29 | ///
30 | public TestContext TestContext
31 | {
32 | get
33 | {
34 | return testContextInstance;
35 | }
36 | set
37 | {
38 | testContextInstance = value;
39 | }
40 | }
41 |
42 | [TestMethod]
43 | public void TestLoadTorrent()
44 | {
45 | string torrentFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestTorrents", "[U2].14332.torrent");
46 | Torrent torrent = Torrent.Load(torrentFile);
47 |
48 | Console.WriteLine("{0,15}: {1}", "Name", torrent.Name);
49 | Console.WriteLine("{0,15}: {1}", "IsPrivate", torrent.IsPrivate);
50 | Console.WriteLine("{0,15}: {1}", "Pieces", torrent.Pieces.Count);
51 | Console.WriteLine("{0,15}: {1}", "PieceLength", torrent.PieceLength);
52 | Console.WriteLine("{0,15}: {1}", "Files", torrent.Files.Count());
53 | Console.WriteLine("----------Files------------------");
54 | foreach (var file in torrent.Files)
55 | {
56 | Console.WriteLine("{0,15}: {1}", "Path", file.Path);
57 | Console.WriteLine("{0,15}: {1}", "Length", file.Length);
58 | Console.WriteLine("{0,15}: {1}", "StartPieceIndex", file.StartPieceIndex);
59 | Console.WriteLine("{0,15}: {1}", "EndPieceIndex", file.EndPieceIndex);
60 | Console.WriteLine("{0,15}: {1}", "EndPieceIndex", file.Priority);
61 |
62 | Console.WriteLine("-----------------------------------------");
63 | }
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Torrents/RawTrackerTier.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using TorrentHardLinkHelper.BEncoding;
4 |
5 | namespace TorrentHardLinkHelper.Torrents
6 | {
7 | public class RawTrackerTier : IList
8 | {
9 | public string this[int index] {
10 | get { return ((BEncodedString) Tier [index]).Text; }
11 | set { Tier [index] = new BEncodedString (value );}
12 | }
13 |
14 | internal BEncodedList Tier {
15 | get; set;
16 | }
17 |
18 | public RawTrackerTier ()
19 | : this (new BEncodedList ())
20 | {
21 | }
22 |
23 | public RawTrackerTier (BEncodedList tier)
24 | {
25 | Tier = tier;
26 | }
27 |
28 | public RawTrackerTier (IEnumerable announces)
29 | : this ()
30 | {
31 | foreach (var v in announces)
32 | Add (v);
33 | }
34 |
35 | public int IndexOf (string item)
36 | {
37 | return Tier.IndexOf ((BEncodedString) item);
38 | }
39 |
40 | public void Insert (int index, string item)
41 | {
42 | Tier.Insert (index, (BEncodedString) item);
43 | }
44 |
45 | public void RemoveAt (int index)
46 | {
47 | Tier.RemoveAt (index);
48 | }
49 |
50 | public void Add (string item)
51 | {
52 | Tier.Add ((BEncodedString) item);
53 | }
54 |
55 | public void Clear ()
56 | {
57 | Tier.Clear ();
58 | }
59 |
60 | public bool Contains (string item)
61 | {
62 | return Tier.Contains ((BEncodedString) item);
63 | }
64 |
65 | public void CopyTo (string[] array, int arrayIndex)
66 | {
67 | foreach (var s in this)
68 | array [arrayIndex ++] = s;
69 | }
70 |
71 | public bool Remove (string item)
72 | {
73 | return Tier.Remove ((BEncodedString) item);
74 | }
75 |
76 | public int Count {
77 | get { return Tier.Count; }
78 | }
79 |
80 | public bool IsReadOnly {
81 | get { return Tier.IsReadOnly; }
82 | }
83 |
84 | public IEnumerator GetEnumerator ()
85 | {
86 | foreach (BEncodedString v in Tier)
87 | yield return v.Text;
88 | }
89 |
90 | IEnumerator IEnumerable.GetEnumerator ()
91 | {
92 | return GetEnumerator ();
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/Views/HardLinkTool.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | This tool help create a copy of a folder, the size of file below 1M will be copyed, others will be hard-linked.
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Torrents/RawTrackerTiers.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using TorrentHardLinkHelper.BEncoding;
4 |
5 | namespace TorrentHardLinkHelper.Torrents
6 | {
7 | public class RawTrackerTiers : IList
8 | {
9 | BEncodedList Tiers {
10 | get; set;
11 | }
12 |
13 | public RawTrackerTiers ()
14 | : this (new BEncodedList ())
15 | {
16 | }
17 |
18 | public RawTrackerTiers (BEncodedList tiers)
19 | {
20 | Tiers = tiers;
21 | }
22 |
23 | public int IndexOf (RawTrackerTier item)
24 | {
25 | if (item != null) {
26 | for (int i = 0; i < Tiers.Count; i++)
27 | if (item.Tier == Tiers [i])
28 | return i;
29 | }
30 | return -1;
31 | }
32 |
33 | public void Insert (int index, RawTrackerTier item)
34 | {
35 | Tiers.Insert (index, item.Tier);
36 | }
37 |
38 | public void RemoveAt (int index)
39 | {
40 | Tiers.RemoveAt (index);
41 | }
42 |
43 | public RawTrackerTier this[int index] {
44 | get { return new RawTrackerTier ((BEncodedList) Tiers [index]); }
45 | set { Tiers [index] = value.Tier; }
46 | }
47 |
48 | public void Add (RawTrackerTier item)
49 | {
50 | Tiers.Add (item.Tier);
51 | }
52 |
53 | public void AddRange (IEnumerable tiers)
54 | {
55 | foreach (var v in tiers)
56 | Add (v);
57 | }
58 |
59 | public void Clear ()
60 | {
61 | Tiers.Clear ();
62 | }
63 |
64 | public bool Contains (RawTrackerTier item)
65 | {
66 | return IndexOf (item) != -1;
67 | }
68 |
69 | public void CopyTo (RawTrackerTier[] array, int arrayIndex)
70 | {
71 | foreach (var v in this)
72 | array [arrayIndex ++] = v;
73 | }
74 |
75 | public bool Remove (RawTrackerTier item)
76 | {
77 | int index = IndexOf (item);
78 | if (index != -1)
79 | RemoveAt (index);
80 |
81 | return index != -1;
82 | }
83 |
84 | public int Count {
85 | get { return Tiers.Count; }
86 | }
87 |
88 | public bool IsReadOnly {
89 | get { return Tiers.IsReadOnly; }
90 | }
91 |
92 | public IEnumerator GetEnumerator ()
93 | {
94 | foreach (var v in Tiers)
95 | yield return new RawTrackerTier ((BEncodedList) v);
96 | }
97 |
98 | IEnumerator IEnumerable.GetEnumerator ()
99 | {
100 | return GetEnumerator ();
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.17929
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace TorrentHardLinkHelper.Properties
12 | {
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// Returns the cached ResourceManager instance used by this class.
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TorrentHardLinkHelper.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// Overrides the current thread's CurrentUICulture property for all
56 | /// resource lookups using this strongly typed resource class.
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Torrents/Hashes.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace TorrentHardLinkHelper.Torrents
4 | {
5 | public class Hashes
6 | {
7 | #region Constants
8 | ///
9 | /// Hash code length (in bytes)
10 | ///
11 | internal static readonly int HashCodeLength = 20;
12 | #endregion
13 |
14 |
15 | #region Private Fields
16 |
17 | private int count;
18 | private byte[] hashData;
19 |
20 | #endregion Private Fields
21 |
22 |
23 | #region Properties
24 |
25 | ///
26 | /// Number of Hashes (equivalent to number of Pieces)
27 | ///
28 | public int Count
29 | {
30 | get { return this.count; }
31 | }
32 |
33 | #endregion Properties
34 |
35 |
36 | #region Constructors
37 |
38 | internal Hashes(byte[] hashData, int count)
39 | {
40 | this.hashData = hashData;
41 | this.count = count;
42 | }
43 |
44 | #endregion Constructors
45 |
46 |
47 | #region Methods
48 |
49 | ///
50 | /// Determine whether a calculated hash is equal to our stored hash
51 | ///
52 | /// Hash code to check
53 | /// Index of hash/piece to verify against
54 | /// true iff hash is equal to our stored hash, false otherwise
55 | public bool IsValid(byte[] hash, int hashIndex)
56 | {
57 | if (hash == null)
58 | throw new ArgumentNullException("hash");
59 |
60 | if (hash.Length != HashCodeLength)
61 | throw new ArgumentException(string.Format("Hash must be {0} bytes in length", HashCodeLength), "hash");
62 |
63 | if (hashIndex < 0 || hashIndex > count)
64 | throw new ArgumentOutOfRangeException("hashIndex", string.Format("hashIndex must be between 0 and {0}", count));
65 |
66 | int start = hashIndex * HashCodeLength;
67 | for (int i = 0; i < HashCodeLength; i++)
68 | if (hash[i] != this.hashData[i + start])
69 | return false;
70 |
71 | return true;
72 | }
73 |
74 | ///
75 | /// Returns the hash for a specific piece
76 | ///
77 | /// Piece/hash index to return
78 | /// byte[] (length HashCodeLength) containing hashdata
79 | public byte[] ReadHash(int hashIndex)
80 | {
81 | if (hashIndex < 0 || hashIndex >= count)
82 | throw new ArgumentOutOfRangeException("hashIndex");
83 |
84 | // Read out our specified piece's hash data
85 | byte[] hash = new byte[HashCodeLength];
86 | Buffer.BlockCopy(this.hashData, hashIndex * HashCodeLength, hash, 0, HashCodeLength);
87 |
88 | return hash;
89 | }
90 |
91 | #endregion Methods
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # HOW TO USE THIS FILE
2 |
3 | # Installing this package works best if you do a little preparation first.
4 | # Whether you create your initial repository on GitHub, or use the Git Source Control Provider Visual Studio extension,
5 | # a default .gitignore file will already be at the root of your git repository.
6 | # Usually, this means it is directly within your main solution folder, as a sibling to your MyProject.sln file,
7 | # your .git folder, and possibly your packages directory.
8 |
9 | # In the Visual Studio Solution Explorer, right click your Solution node and select `Add > Existing Item`.
10 | # Navigate to the root .gitignore file and add it.
11 | # It will appear in your "Solution Items" folder, but only the path, not the file name.
12 | # This is because the file does not contain a name before the extension. Yay windows.
13 | # Regardless, this provides an easy way to get at your .gitignore file, which you will need to do after installing this package.
14 |
15 | # Now install this package. You will notice that a git.ignore file is added to your project directory (not your solution directory).
16 | # This is another wonderful windows *feature* that prevents nuget packages from copying nameless / extension-only files.
17 | # It doesn't matter though. All you have to do is open this git.ignore file (which you already have done), select all, copy,
18 | # then open your other .gitignore from the Solution Items folder select all, and paste.
19 | # When you are done, REMOVE THIS PACKAGE. You don't need it any more. It's pointless and it's wasting bits.
20 |
21 | # Unless you want to push all of your packages to your remote repository, enable NuGet Package Restore on your solution.
22 | # This .gitignore will make sure that NuGet.exe gets added, and your packages stay off of the remote.
23 |
24 | # Finally, you can delete all of this text to and including the #BEGIN GIT IGNORES line below.
25 | # For more information, see the README at https://github.com/danludwig/VisualStudioGitIgnore
26 | ===================================================================================================================================
27 |
28 | #BEGIN GIT IGNORES
29 | #Ignore thumbnails created by windows
30 | Thumbs.db
31 |
32 | #Ignore files built by Visual Studio
33 | *.obj
34 | *.exe
35 | *.pdb
36 | *.user
37 | *.aps
38 | *.pch
39 | *.vspscc
40 | *_i.c
41 | *_p.c
42 | *.ncb
43 | *.suo
44 | *.tlb
45 | *.tlh
46 | *.bak
47 | *.cache
48 | *.ilk
49 | *.log
50 | [Bb]in
51 | [Dd]ebug*/
52 | *.lib
53 | *.sbr
54 | obj/
55 | [Rr]elease*/
56 | _ReSharper*/
57 | [Tt]est[Rr]esult*
58 |
59 | #Ignore packages directory
60 | Packages/
61 |
62 | #Allow NuGet.exe
63 | !NuGet.exe
64 |
65 | #Allow Net-z
66 | !netz.exe
67 |
68 | #Ignore generated nupkg files
69 | *.nupkg
70 |
71 | #Allow released nupkg files
72 | !MyProjectName.1.0.nupkg
73 |
74 | #Ignore local testsettings
75 | Local.testsettings
76 |
77 | #Allow R# .DotSettings
78 | !*.csproj.DotSettings
79 |
80 | #Ignore Azure build csdef & Pubxml files
81 | ServiceDefinition.build.csdef
82 | *.azurePubxml
83 |
84 | #Ignore WebDeploy publish profile
85 | *.Publish.xml
86 |
87 | #Ignore email files delivered to specified pickup directory
88 | *.eml
89 |
90 | #Allow chromedriver.exe
91 | !chromedriver.exe
92 |
93 | #Ignore _vti folders in ExpressionWeb
94 | desktop.ini
95 | _vti_cnf/
96 | _vti_pvt/
97 |
98 | #Ignore private folder
99 | /Private/
100 | /.vs
101 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/TorrentHardLinkHelper.Library.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {C0E94189-B243-4492-A113-6EB2DE57BCC0}
8 | Library
9 | Properties
10 | TorrentHardLinkHelper
11 | TorrentHardLinkHelper.Library
12 | v4.0
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
87 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/ViewModels/HardLinkToolViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using System.IO;
3 | using GalaSoft.MvvmLight;
4 | using GalaSoft.MvvmLight.Command;
5 | using Ookii.Dialogs.Wpf;
6 | using TorrentHardLinkHelper.HardLink;
7 |
8 | namespace TorrentHardLinkHelper.ViewModels
9 | {
10 | public class HardLinkToolViewModel : ViewModelBase
11 | {
12 | private string _sourceFolder;
13 | private string _parentFolder;
14 | private string _folderName;
15 |
16 | private RelayCommand _selectSourceFolderCommand;
17 | private RelayCommand _selectParentFolderCommand;
18 | private RelayCommand _defaultCommand;
19 | private RelayCommand _linkCommand;
20 |
21 | public HardLinkToolViewModel()
22 | {
23 | this.InitCommands();
24 | }
25 |
26 | public void InitCommands()
27 | {
28 | this._selectSourceFolderCommand = new RelayCommand(() =>
29 | {
30 | var dialog = new VistaFolderBrowserDialog();
31 | dialog.ShowNewFolderButton = true;
32 | dialog.ShowDialog();
33 | if (!string.IsNullOrWhiteSpace(dialog.SelectedPath))
34 | {
35 | this.Set(() => this.SourceFolder, ref this._sourceFolder, dialog.SelectedPath);
36 | this.Set(() => this.ParentFolder, ref this._parentFolder, Directory.GetParent(dialog.SelectedPath).FullName);
37 | this.Set(() => this.FolderName, ref this._folderName, Path.GetFileName(dialog.SelectedPath) + "_Copy");
38 | }
39 | });
40 |
41 | this._selectParentFolderCommand = new RelayCommand(() =>
42 | {
43 | var dialog = new VistaFolderBrowserDialog();
44 | dialog.ShowNewFolderButton = true;
45 | dialog.ShowDialog();
46 | if (dialog.SelectedPath != null)
47 | {
48 | this.Set(() => this.ParentFolder, ref this._parentFolder, dialog.SelectedPath);
49 | }
50 | });
51 |
52 | this._defaultCommand = new RelayCommand(() =>
53 | {
54 | if (string.IsNullOrWhiteSpace(this._sourceFolder))
55 | {
56 | this.Set(() => this.FolderName, ref this._folderName, "");
57 | }
58 | else
59 | {
60 | this.Set(() => this.FolderName, ref this._folderName,
61 | Path.GetDirectoryName(_folderName) + "_HLinked");
62 | }
63 | });
64 |
65 | this._linkCommand = new RelayCommand(() =>
66 | {
67 | var helper = new HardLinkHelper();
68 | helper.HardLink(this._sourceFolder, this._parentFolder, this._folderName, 1024000);
69 | Process.Start("explorer.exe", Path.Combine(this._parentFolder, this._folderName));
70 | }, () => !string.IsNullOrWhiteSpace(this._sourceFolder) && !string.IsNullOrWhiteSpace(this._parentFolder) && !string.IsNullOrWhiteSpace(this._folderName));
71 | }
72 |
73 | public string SourceFolder
74 | {
75 | get { return _sourceFolder; }
76 | set { _sourceFolder = value; }
77 | }
78 |
79 | public string ParentFolder
80 | {
81 | get { return _parentFolder; }
82 | set { _parentFolder = value; }
83 | }
84 |
85 | public string FolderName
86 | {
87 | get { return _folderName; }
88 | set { _folderName = value; }
89 | }
90 |
91 | public RelayCommand SelectSourceFolderCommand
92 | {
93 | get { return _selectSourceFolderCommand; }
94 | set { _selectSourceFolderCommand = value; }
95 | }
96 |
97 | public RelayCommand SelectParentFolderCommand
98 | {
99 | get { return _selectParentFolderCommand; }
100 | set { _selectParentFolderCommand = value; }
101 | }
102 |
103 | public RelayCommand DefaultCommand
104 | {
105 | get { return _defaultCommand; }
106 | set { _defaultCommand = value; }
107 | }
108 |
109 | public RelayCommand LinkCommand
110 | {
111 | get { return _linkCommand; }
112 | set { _linkCommand = value; }
113 | }
114 | }
115 | }
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Common/Toolbox.cs:
--------------------------------------------------------------------------------
1 | //
2 | // ToolBox.cs
3 | //
4 | // Authors:
5 | // Alan McGovern alan.mcgovern@gmail.com
6 | //
7 | // Copyright (C) 2006 Alan McGovern
8 |
9 | using System;
10 | using System.Collections.Generic;
11 | using System.Threading;
12 |
13 | namespace TorrentHardLinkHelper.Common
14 | {
15 | public delegate long Operation(T target);
16 |
17 | public static class Toolbox
18 | {
19 | private static Random r = new Random();
20 | public static int Count(IEnumerable enumerable, Predicate predicate)
21 | {
22 | int count = 0;
23 |
24 | foreach (T t in enumerable)
25 | if (predicate(t))
26 | count++;
27 |
28 | return count;
29 | }
30 |
31 | public static long Accumulate(IEnumerable enumerable, Operation action)
32 | {
33 | long count = 0;
34 |
35 | foreach (T t in enumerable)
36 | count += action(t);
37 |
38 | return count;
39 | }
40 |
41 | public static void RaiseAsyncEvent(EventHandler e, object o, T args)
42 | where T : EventArgs
43 | {
44 | if (e == null)
45 | return;
46 |
47 | ThreadPool.QueueUserWorkItem(delegate
48 | {
49 | if (e != null)
50 | e(o, args);
51 | });
52 | }
53 | ///
54 | /// Randomizes the contents of the array
55 | ///
56 | ///
57 | ///
58 | public static void Randomize(List array)
59 | {
60 | List clone = new List(array);
61 | array.Clear();
62 |
63 | while (clone.Count > 0)
64 | {
65 | int index = r.Next(0, clone.Count);
66 | array.Add(clone[index]);
67 | clone.RemoveAt(index);
68 | }
69 | }
70 |
71 | ///
72 | /// Switches the positions of two elements in an array
73 | ///
74 | ///
75 | ///
76 | ///
77 | ///
78 | public static void Switch(IList array, int first, int second)
79 | {
80 | T obj = array[first];
81 | array[first] = array[second];
82 | array[second] = obj;
83 | }
84 |
85 | ///
86 | /// Checks to see if the contents of two byte arrays are equal
87 | ///
88 | /// The first array
89 | /// The second array
90 | /// True if the arrays are equal, false if they aren't
91 | public static bool ByteMatch(byte[] array1, byte[] array2)
92 | {
93 | if (array1 == null)
94 | throw new ArgumentNullException("array1");
95 | if (array2 == null)
96 | throw new ArgumentNullException("array2");
97 |
98 | if (array1.Length != array2.Length)
99 | return false;
100 |
101 | return ByteMatch(array1, 0, array2, 0, array1.Length);
102 | }
103 |
104 | ///
105 | /// Checks to see if the contents of two byte arrays are equal
106 | ///
107 | /// The first array
108 | /// The second array
109 | /// The starting index for the first array
110 | /// The starting index for the second array
111 | /// The number of bytes to check
112 | ///
113 | public static bool ByteMatch(byte[] array1, int offset1, byte[] array2, int offset2, int count)
114 | {
115 | if (array1 == null)
116 | throw new ArgumentNullException("array1");
117 | if (array2 == null)
118 | throw new ArgumentNullException("array2");
119 |
120 | // If either of the arrays is too small, they're not equal
121 | if ((array1.Length - offset1) < count || (array2.Length - offset2) < count)
122 | return false;
123 |
124 | // Check if any elements are unequal
125 | for (int i = 0; i < count; i++)
126 | if (array1[offset1 + i] != array2[offset2 + i])
127 | return false;
128 |
129 | return true;
130 | }
131 |
132 | internal static bool HasEncryption(EncryptionTypes available, EncryptionTypes check)
133 | {
134 | return (available & check) == check;
135 | }
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/BEncoding/RawReader.cs:
--------------------------------------------------------------------------------
1 | //
2 | // RawReader.cs
3 | //
4 | // Authors:
5 | // Alan McGovern alan.mcgovern@gmail.com
6 | //
7 | // Copyright (C) 2008 Alan McGovern
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining
10 | // a copy of this software and associated documentation files (the
11 | // "Software"), to deal in the Software without restriction, including
12 | // without limitation the rights to use, copy, modify, merge, publish,
13 | // distribute, sublicense, and/or sell copies of the Software, and to
14 | // permit persons to whom the Software is furnished to do so, subject to
15 | // the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 | using System;
30 | using System.Collections.Generic;
31 | using System.Text;
32 | using System.IO;
33 |
34 | namespace TorrentHardLinkHelper.BEncoding
35 | {
36 | public class RawReader : Stream
37 | {
38 | bool hasPeek;
39 | Stream input;
40 | byte[] peeked;
41 | bool strictDecoding;
42 |
43 | public bool StrictDecoding
44 | {
45 | get { return strictDecoding; }
46 | }
47 |
48 | public RawReader(Stream input)
49 | : this(input, true)
50 | {
51 |
52 | }
53 |
54 | public RawReader(Stream input, bool strictDecoding)
55 | {
56 | this.input = input;
57 | this.peeked = new byte[1];
58 | this.strictDecoding = strictDecoding;
59 | }
60 |
61 | public override bool CanRead
62 | {
63 | get { return input.CanRead; }
64 | }
65 |
66 | public override bool CanSeek
67 | {
68 | get { return input.CanSeek; }
69 | }
70 |
71 | public override bool CanWrite
72 | {
73 | get { return false; }
74 | }
75 |
76 | public override void Flush()
77 | {
78 | throw new NotSupportedException();
79 | }
80 |
81 | public override long Length
82 | {
83 | get { return input.Length; }
84 | }
85 |
86 | public int PeekByte()
87 | {
88 | if (!hasPeek)
89 | hasPeek = Read(peeked, 0, 1) == 1;
90 | return hasPeek ? peeked[0] : -1;
91 | }
92 |
93 | public override int ReadByte()
94 | {
95 | if (hasPeek)
96 | {
97 | hasPeek = false;
98 | return peeked[0];
99 | }
100 | return base.ReadByte();
101 | }
102 |
103 | public override long Position
104 | {
105 | get
106 | {
107 | if (hasPeek)
108 | return input.Position - 1;
109 | return input.Position;
110 | }
111 | set
112 | {
113 | if (value != Position)
114 | {
115 | hasPeek = false;
116 | input.Position = value;
117 | }
118 | }
119 | }
120 |
121 | public override int Read(byte[] buffer, int offset, int count)
122 | {
123 | int read = 0;
124 | if (hasPeek && count > 0)
125 | {
126 | hasPeek = false;
127 | buffer[offset] = peeked[0];
128 | offset++;
129 | count--;
130 | read++;
131 | }
132 | read += input.Read(buffer, offset, count);
133 | return read;
134 | }
135 |
136 | public override long Seek(long offset, SeekOrigin origin)
137 | {
138 | long val;
139 | if (hasPeek && origin == SeekOrigin.Current)
140 | val = input.Seek(offset - 1, origin);
141 | else
142 | val = input.Seek(offset, origin);
143 | hasPeek = false;
144 | return val;
145 | }
146 |
147 | public override void SetLength(long value)
148 | {
149 | throw new NotSupportedException();
150 | }
151 |
152 | public override void Write(byte[] buffer, int offset, int count)
153 | {
154 | throw new NotSupportedException();
155 | }
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Test/TorrentHardLinkHelper.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {103E5401-FBB4-4DFB-9B10-4B40640B6E2D}
7 | Library
8 | Properties
9 | TorrentHardLinkHelper.Test
10 | TorrentHardLinkHelper.Test
11 | v4.0
12 | 512
13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 10.0
15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
17 | False
18 | UnitTest
19 |
20 |
21 | true
22 | full
23 | false
24 | bin\Debug\
25 | DEBUG;TRACE
26 | prompt
27 | 4
28 |
29 |
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 |
37 |
38 |
39 |
40 | 3.5
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | PreserveNewest
64 |
65 |
66 | PreserveNewest
67 |
68 |
69 |
70 |
71 | {c0e94189-b243-4492-a113-6eb2de57bcc0}
72 | TorrentHardLinkHelper.Library
73 |
74 |
75 |
76 |
77 |
78 |
79 | False
80 |
81 |
82 | False
83 |
84 |
85 | False
86 |
87 |
88 | False
89 |
90 |
91 |
92 |
93 |
94 |
95 |
102 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Common/UriHelper.cs:
--------------------------------------------------------------------------------
1 | //
2 | // System.Web.HttpUtility/HttpEncoder
3 | //
4 | // Authors:
5 | // Patrik Torstensson (Patrik.Torstensson@labs2.com)
6 | // Wictor Wilén (decode/encode functions) (wictor@ibizkit.se)
7 | // Tim Coleman (tim@timcoleman.com)
8 | // Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 | // Marek Habersack
10 | //
11 | // Copyright (C) 2005-2010 Novell, Inc (http://www.novell.com)
12 |
13 | using System;
14 | using System.Collections.Generic;
15 | using System.IO;
16 | using System.Text;
17 |
18 | namespace TorrentHardLinkHelper.Common
19 | {
20 | static class UriHelper
21 | {
22 | static readonly char [] hexChars = "0123456789abcdef".ToCharArray ();
23 |
24 | public static string UrlEncode (byte[] bytes)
25 | {
26 | if (bytes == null)
27 | throw new ArgumentNullException ("bytes");
28 |
29 | var result = new MemoryStream (bytes.Length);
30 | for (int i = 0; i < bytes.Length; i++)
31 | UrlEncodeChar ((char)bytes [i], result, false);
32 |
33 | return Encoding.ASCII.GetString (result.ToArray());
34 | }
35 |
36 | public static byte [] UrlDecode (string s)
37 | {
38 | if (null == s)
39 | return null;
40 |
41 | var e = Encoding.UTF8;
42 | if (s.IndexOf ('%') == -1 && s.IndexOf ('+') == -1)
43 | return e.GetBytes (s);
44 |
45 | long len = s.Length;
46 | var bytes = new List ();
47 | int xchar;
48 | char ch;
49 |
50 | for (int i = 0; i < len; i++) {
51 | ch = s [i];
52 | if (ch == '%' && i + 2 < len && s [i + 1] != '%') {
53 | if (s [i + 1] == 'u' && i + 5 < len) {
54 | // unicode hex sequence
55 | xchar = GetChar (s, i + 2, 4);
56 | if (xchar != -1) {
57 | WriteCharBytes (bytes, (char)xchar, e);
58 | i += 5;
59 | } else
60 | WriteCharBytes (bytes, '%', e);
61 | } else if ((xchar = GetChar (s, i + 1, 2)) != -1) {
62 | WriteCharBytes (bytes, (char)xchar, e);
63 | i += 2;
64 | } else {
65 | WriteCharBytes (bytes, '%', e);
66 | }
67 | continue;
68 | }
69 |
70 | if (ch == '+')
71 | WriteCharBytes (bytes, ' ', e);
72 | else
73 | WriteCharBytes (bytes, ch, e);
74 | }
75 |
76 | return bytes.ToArray ();
77 | }
78 |
79 | static void UrlEncodeChar (char c, Stream result, bool isUnicode) {
80 | if (c > ' ' && NotEncoded (c)) {
81 | result.WriteByte ((byte)c);
82 | return;
83 | }
84 | if (c==' ') {
85 | result.WriteByte ((byte)'+');
86 | return;
87 | }
88 | if ( (c < '0') ||
89 | (c < 'A' && c > '9') ||
90 | (c > 'Z' && c < 'a') ||
91 | (c > 'z')) {
92 | if (isUnicode && c > 127) {
93 | result.WriteByte ((byte)'%');
94 | result.WriteByte ((byte)'u');
95 | result.WriteByte ((byte)'0');
96 | result.WriteByte ((byte)'0');
97 | }
98 | else
99 | result.WriteByte ((byte)'%');
100 |
101 | int idx = ((int) c) >> 4;
102 | result.WriteByte ((byte)hexChars [idx]);
103 | idx = ((int) c) & 0x0F;
104 | result.WriteByte ((byte)hexChars [idx]);
105 | }
106 | else {
107 | result.WriteByte ((byte)c);
108 | }
109 | }
110 |
111 | static int GetChar (string str, int offset, int length)
112 | {
113 | int val = 0;
114 | int end = length + offset;
115 | for (int i = offset; i < end; i++) {
116 | char c = str [i];
117 | if (c > 127)
118 | return -1;
119 |
120 | int current = GetInt ((byte) c);
121 | if (current == -1)
122 | return -1;
123 | val = (val << 4) + current;
124 | }
125 |
126 | return val;
127 | }
128 |
129 | static int GetInt (byte b)
130 | {
131 | char c = (char) b;
132 | if (c >= '0' && c <= '9')
133 | return c - '0';
134 |
135 | if (c >= 'a' && c <= 'f')
136 | return c - 'a' + 10;
137 |
138 | if (c >= 'A' && c <= 'F')
139 | return c - 'A' + 10;
140 |
141 | return -1;
142 | }
143 |
144 | static bool NotEncoded (char c)
145 | {
146 | return c == '!' || c == '(' || c == ')' || c == '*' || c == '-' || c == '.' || c == '_' || c == '\'';
147 | }
148 |
149 | static void WriteCharBytes (List buf, char ch, Encoding e)
150 | {
151 | if (ch > 255) {
152 | foreach (byte b in e.GetBytes (new char[] { ch }))
153 | buf.Add (b);
154 | } else
155 | buf.Add ((byte)ch);
156 | }
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Locate/HashFileLinkPieces.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Security.Cryptography;
6 | using System.Threading;
7 | using TorrentHardLinkHelper.Torrents;
8 |
9 | namespace TorrentHardLinkHelper.Locate
10 | {
11 | internal class HashFileLinkPieces
12 | {
13 | private class CheckResult
14 | {
15 | public string Pattern { get; set; }
16 | public bool Matched { get; set; }
17 | }
18 |
19 | private int _result;
20 | private readonly IList _fileLinkPieces;
21 | private readonly Torrent _torrent;
22 | private readonly int _pieceIndex;
23 | private string _validPattern;
24 | private IDictionary> _cleanedFileInfos;
25 |
26 | private delegate CheckResult CheckPatternFunc(string pattern);
27 |
28 | public HashFileLinkPieces(Torrent torrent, int pieceIndex,
29 | IList fileLinkPieces)
30 | {
31 | this._pieceIndex = pieceIndex;
32 | this._fileLinkPieces = fileLinkPieces;
33 | this._result = -1;
34 | this._torrent = torrent;
35 | }
36 |
37 | public string Run()
38 | {
39 | if (_fileLinkPieces.Any(c => c.FileLink.FsFileInfos.Count == 0))
40 | {
41 | return null;
42 | }
43 | this.CleanDuplicateFiles();
44 | this.Run(0, "");
45 | return this._validPattern;
46 | }
47 |
48 | private void CleanDuplicateFiles()
49 | {
50 | this._cleanedFileInfos = new Dictionary>();
51 | for (int i = 0; i < this._fileLinkPieces.Count; i++)
52 | {
53 | var piece = this._fileLinkPieces[i];
54 | var hashes = new List();
55 | this._cleanedFileInfos.Add(i, new List(piece.FileLink.FsFileInfos.Count));
56 |
57 | foreach (FileSystemFileInfo fileInfo in piece.FileLink.FsFileInfos)
58 | {
59 | if (piece.FileLink.TorrentFile.StartPieceIndex == this._pieceIndex &&
60 | piece.FileLink.TorrentFile.EndPieceIndex == this._pieceIndex)
61 | {
62 | if (fileInfo.Located)
63 | {
64 | continue;
65 | }
66 | }
67 | string hash = this.HashFilePiece(fileInfo.FilePath,
68 | piece.StartPos, piece.ReadLength);
69 | if (hashes.Contains(hash))
70 | {
71 | continue;
72 | }
73 | hashes.Add(hash);
74 | this._cleanedFileInfos[i].Add(fileInfo);
75 | }
76 | }
77 | }
78 |
79 | private void GroupFiles()
80 | {
81 |
82 | }
83 |
84 | private void Run(int index, string pattern)
85 | {
86 | if (this._result == 1)
87 | {
88 | return;
89 | }
90 | if (index < this._fileLinkPieces.Count)
91 | {
92 | for (int i = 0; i < this._cleanedFileInfos[index].Count; i++)
93 | {
94 | string nextPattern = pattern + i + ',';
95 | int nextIndex = index + 1;
96 | Run(nextIndex, nextPattern);
97 | }
98 | }
99 | else
100 | {
101 | using (var pieceStream = new MemoryStream(this._torrent.PieceLength))
102 | {
103 | for (int i = 0; i < this._fileLinkPieces.Count; i++)
104 | {
105 | int fileIndex = int.Parse(pattern.Split(',')[i]);
106 | using (FileStream fileStream =
107 | File.OpenRead(this._cleanedFileInfos[i][fileIndex].FilePath))
108 | {
109 | var buffer = new byte[this._fileLinkPieces[i].ReadLength];
110 | fileStream.Position = (long)this._fileLinkPieces[i].StartPos;
111 | fileStream.Read(buffer, 0, buffer.Length);
112 | pieceStream.Write(buffer, 0, buffer.Length);
113 | }
114 | }
115 |
116 | var sha1 = HashAlgoFactory.Create();
117 | byte[] hash = sha1.ComputeHash(pieceStream.ToArray());
118 | if (this._torrent.Pieces.IsValid(hash, this._pieceIndex))
119 | {
120 | this._validPattern = pattern;
121 | this._result = 1;
122 | }
123 | }
124 | }
125 | }
126 |
127 | private string HashFilePiece(string path, ulong start, ulong length)
128 | {
129 | var sha1 = HashAlgoFactory.Create();
130 | FileStream fileStream =
131 | File.OpenRead(path);
132 | var buffer = new byte[length];
133 | fileStream.Position = (long)start;
134 | fileStream.Read(buffer, 0, buffer.Length);
135 | byte[] hash = sha1.ComputeHash(buffer);
136 | fileStream.Close();
137 | return Convert.ToBase64String(hash);
138 | }
139 | }
140 | }
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Messages/Message.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using IMessage = TorrentHardLinkHelper.Messages.IMessage;
4 |
5 | namespace TorrentHardLinkHelper.Messages
6 | {
7 | public abstract class Message : IMessage
8 | {
9 | public abstract int ByteLength { get; }
10 |
11 | protected int CheckWritten(int written)
12 | {
13 | if (written != ByteLength)
14 | throw new MessageException("Message encoded incorrectly. Incorrect number of bytes written");
15 | return written;
16 | }
17 |
18 | public abstract void Decode(byte[] buffer, int offset, int length);
19 |
20 | public byte[] Encode()
21 | {
22 | byte[] buffer = new byte[ByteLength];
23 | Encode(buffer, 0);
24 | return buffer;
25 | }
26 |
27 | public abstract int Encode(byte[] buffer, int offset);
28 |
29 | static public byte ReadByte(byte[] buffer, int offset)
30 | {
31 | return buffer[offset];
32 | }
33 |
34 | static public byte ReadByte(byte[] buffer, ref int offset)
35 | {
36 | byte b = buffer[offset];
37 | offset++;
38 | return b;
39 | }
40 |
41 | static public byte[] ReadBytes(byte[] buffer, int offset, int count)
42 | {
43 | return ReadBytes(buffer, ref offset, count);
44 | }
45 |
46 | static public byte[] ReadBytes(byte[] buffer, ref int offset, int count)
47 | {
48 | byte[] result = new byte[count];
49 | Buffer.BlockCopy(buffer, offset, result, 0, count);
50 | offset += count;
51 | return result;
52 | }
53 |
54 | static public short ReadShort(byte[] buffer, int offset)
55 | {
56 | return ReadShort(buffer, ref offset);
57 | }
58 |
59 | static public short ReadShort(byte[] buffer, ref int offset)
60 | {
61 | short ret = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, offset));
62 | offset += 2;
63 | return ret;
64 | }
65 |
66 | static public string ReadString(byte[] buffer, int offset, int count)
67 | {
68 | return ReadString(buffer, ref offset, count);
69 | }
70 |
71 | static public string ReadString(byte[] buffer, ref int offset, int count)
72 | {
73 | string s = System.Text.Encoding.ASCII.GetString(buffer, offset, count);
74 | offset += count;
75 | return s;
76 | }
77 |
78 | static public int ReadInt(byte[] buffer, int offset)
79 | {
80 | return ReadInt(buffer, ref offset);
81 | }
82 |
83 | static public int ReadInt(byte[] buffer, ref int offset)
84 | {
85 | int ret = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buffer, offset));
86 | offset += 4;
87 | return ret;
88 | }
89 |
90 | static public long ReadLong(byte[] buffer, int offset)
91 | {
92 | return ReadLong(buffer, ref offset);
93 | }
94 |
95 | static public long ReadLong(byte[] buffer, ref int offset)
96 | {
97 | long ret = IPAddress.NetworkToHostOrder(BitConverter.ToInt64(buffer, offset));
98 | offset += 8;
99 | return ret;
100 | }
101 |
102 | static public int Write(byte[] buffer, int offset, byte value)
103 | {
104 | buffer[offset] = value;
105 | return 1;
106 | }
107 |
108 | static public int Write(byte[] dest, int destOffset, byte[] src, int srcOffset, int count)
109 | {
110 | Buffer.BlockCopy(src, srcOffset, dest, destOffset, count);
111 | return count;
112 | }
113 |
114 | static public int Write(byte[] buffer, int offset, ushort value)
115 | {
116 | return Write(buffer, offset, (short)value);
117 | }
118 |
119 | static public int Write(byte[] buffer, int offset, short value)
120 | {
121 | offset += Write(buffer, offset, (byte)(value >> 8));
122 | offset += Write(buffer, offset, (byte)value);
123 | return 2;
124 | }
125 |
126 | static public int Write(byte[] buffer, int offset, int value)
127 | {
128 | offset += Write(buffer, offset, (byte)(value >> 24));
129 | offset += Write(buffer, offset, (byte)(value >> 16));
130 | offset += Write(buffer, offset, (byte)(value >> 8));
131 | offset += Write(buffer, offset, (byte)(value));
132 | return 4;
133 | }
134 |
135 | static public int Write(byte[] buffer, int offset, uint value)
136 | {
137 | return Write(buffer, offset, (int)value);
138 | }
139 |
140 | static public int Write(byte[] buffer, int offset, long value)
141 | {
142 | offset += Write(buffer, offset, (int)(value >> 32));
143 | offset += Write(buffer, offset, (int)value);
144 | return 8;
145 | }
146 |
147 | static public int Write(byte[] buffer, int offset, ulong value)
148 | {
149 | return Write(buffer, offset, (long)value);
150 | }
151 |
152 | static public int Write(byte[] buffer, int offset, byte[] value)
153 | {
154 | return Write(buffer, offset, value, 0, value.Length);
155 | }
156 |
157 | static public int WriteAscii(byte[] buffer, int offset, string text)
158 | {
159 | for (int i = 0; i < text.Length; i++)
160 | Write(buffer, offset + i, (byte)text[i]);
161 | return text.Length;
162 | }
163 | }
164 | }
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/Models/EntityModel.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.IO;
3 | using System.Windows.Media;
4 | using GalaSoft.MvvmLight;
5 | using TorrentHardLinkHelper.Locate;
6 | using TorrentHardLinkHelper.Torrents;
7 |
8 | namespace TorrentHardLinkHelper.Models
9 | {
10 | public class EntityModel : ObservableObject
11 | {
12 | public EntityModel()
13 | {
14 | this.Entities = new List();
15 | }
16 |
17 | protected string _name;
18 | protected string _fullName;
19 | protected bool _locked;
20 | protected string _type;
21 | protected IList _entities;
22 |
23 | public string Name
24 | {
25 | get { return this._name; }
26 | set { this._name = value; }
27 | }
28 |
29 | public string FullName
30 | {
31 | get { return this._fullName; }
32 | set { this._fullName = value; }
33 | }
34 |
35 | public bool Located
36 | {
37 | get { return this._locked; }
38 | set { this._locked = value; }
39 | }
40 |
41 | public string Type
42 | {
43 | get { return this._type; }
44 | set { this._type = value; }
45 | }
46 |
47 | public IList Entities
48 | {
49 | get { return this._entities; }
50 | set { this._entities = value; }
51 | }
52 |
53 | public Brush TextColor
54 | {
55 | get
56 | {
57 | if (this.Type == "Folder")
58 | {
59 | return Brushes.Black;
60 | }
61 | if (this.Located)
62 | {
63 | return Brushes.Blue;
64 | }
65 | return Brushes.Red;
66 | }
67 | }
68 |
69 | public override string ToString()
70 | {
71 | return string.Format("[{0,-8}]{1}", this.Type, this.Name);
72 | }
73 |
74 | public static EntityModel Load(string path)
75 | {
76 | if (!Directory.Exists(path))
77 | {
78 | return null;
79 | }
80 | var folderModel = new FolderModel(Path.GetFileName(path));
81 | folderModel.FullName = path;
82 | foreach (var file in Directory.GetFiles(path))
83 | {
84 | folderModel.Entities.Add(new FileModel(file));
85 | }
86 | foreach (var subFolder in Directory.GetDirectories(path))
87 | {
88 | folderModel.Entities.Add(Load(subFolder));
89 | }
90 | return folderModel;
91 | }
92 |
93 | public static EntityModel Load(Torrent torrent)
94 | {
95 | var root = new FolderModel(torrent.Name);
96 | foreach (TorrentFile file in torrent.Files)
97 | {
98 | var folder = FindOrCreateFolder(root, file.Path);
99 | folder.Entities.Add(new FileModel(file));
100 | }
101 | return root;
102 | }
103 |
104 | public static EntityModel Load(string title, LocateResult result)
105 | {
106 | var root = new FolderModel(title);
107 | foreach (TorrentFileLink file in result.TorrentFileLinks)
108 | {
109 | var folder = FindOrCreateFolder(root, file.TorrentFile.Path);
110 | var fileModel = new FileModel(file.TorrentFile);
111 | fileModel.Located = file.State == LinkState.Located;
112 | folder.Entities.Add(fileModel);
113 | }
114 | return root;
115 | }
116 |
117 | public static void Update(EntityModel model, IEnumerable fsFileInfos)
118 | {
119 | foreach (EntityModel entity in model.Entities)
120 | {
121 | if (entity.Type == "File")
122 | {
123 | foreach (var fsInfo in fsFileInfos)
124 | {
125 | if (fsInfo == null)
126 | {
127 | continue;
128 | }
129 | if (fsInfo.FilePath == entity.FullName)
130 | {
131 | entity.Located = true;
132 | entity.RaisePropertyChanged("TextColor");
133 | }
134 | }
135 | }
136 | else
137 | {
138 | Update(entity, fsFileInfos);
139 | }
140 | }
141 | }
142 |
143 | private static EntityModel FindOrCreateFolder(FolderModel rootFolder, string path)
144 | {
145 | string[] pathItems = path.Split('\\');
146 | if (pathItems.Length > 1)
147 | {
148 | EntityModel parentFolder = rootFolder;
149 | for (int i = 0; i < pathItems.Length - 1; i++)
150 | {
151 | bool found = false;
152 | foreach (EntityModel subFolder in parentFolder.Entities)
153 | {
154 | if (subFolder.Type == "Folder")
155 | {
156 | if (subFolder.Name == pathItems[i])
157 | {
158 | found = true;
159 | parentFolder = subFolder;
160 | }
161 | }
162 | }
163 | if (!found)
164 | {
165 | var childFolder = new FolderModel(pathItems[i]);
166 | parentFolder.Entities.Add(childFolder);
167 | parentFolder = childFolder;
168 | }
169 | }
170 | return parentFolder;
171 | }
172 | return rootFolder;
173 | }
174 | }
175 | }
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Torrents/InfoHash.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Web;
5 | using TorrentHardLinkHelper.Common;
6 |
7 | namespace TorrentHardLinkHelper.Torrents
8 | {
9 | public class InfoHash : IEquatable
10 | {
11 | static Dictionary base32DecodeTable;
12 |
13 | static InfoHash()
14 | {
15 | base32DecodeTable = new Dictionary();
16 | string table = "abcdefghijklmnopqrstuvwxyz234567";
17 | for (int i = 0; i < table.Length; i++)
18 | base32DecodeTable[table[i]] = (byte)i;
19 | }
20 |
21 | byte[] hash;
22 |
23 | internal byte[] Hash
24 | {
25 | get { return hash; }
26 | }
27 |
28 | public InfoHash(byte[] infoHash)
29 | {
30 | Check.InfoHash(infoHash);
31 | if (infoHash.Length != 20)
32 | throw new ArgumentException("Infohash must be exactly 20 bytes long");
33 | hash = (byte[])infoHash.Clone();
34 | }
35 |
36 | public override bool Equals(object obj)
37 | {
38 | return Equals(obj as InfoHash);
39 | }
40 |
41 | public bool Equals(byte[] other)
42 | {
43 | return other == null || other.Length != 20 ? false : Toolbox.ByteMatch(Hash, other);
44 | }
45 |
46 | public bool Equals(InfoHash other)
47 | {
48 | return this == other;
49 | }
50 |
51 | public override int GetHashCode()
52 | {
53 | // Equality is based generally on checking 20 positions, checking 4 should be enough
54 | // for the hashcode as infohashes are randomly distributed.
55 | return Hash[0] | (Hash[1] << 8) | (Hash[2] << 16) | (Hash[3] << 24);
56 | }
57 |
58 | public byte[] ToArray()
59 | {
60 | return (byte[])hash.Clone();
61 | }
62 |
63 | public string ToHex()
64 | {
65 | StringBuilder sb = new StringBuilder(40);
66 | for (int i = 0; i < hash.Length; i++)
67 | {
68 | string hex = hash[i].ToString("X");
69 | if (hex.Length != 2)
70 | sb.Append("0");
71 | sb.Append(hex);
72 | }
73 | return sb.ToString();
74 | }
75 |
76 | public override string ToString()
77 | {
78 | return BitConverter.ToString(hash);
79 | }
80 |
81 | public string UrlEncode()
82 | {
83 | return UriHelper.UrlEncode(Hash);
84 | }
85 |
86 | public static bool operator ==(InfoHash left, InfoHash right)
87 | {
88 | if ((object)left == null)
89 | return (object)right == null;
90 | if ((object)right == null)
91 | return false;
92 | return Toolbox.ByteMatch(left.Hash, right.Hash);
93 | }
94 |
95 | public static bool operator !=(InfoHash left, InfoHash right)
96 | {
97 | return !(left == right);
98 | }
99 |
100 | public static InfoHash FromBase32(string infoHash)
101 | {
102 | Check.InfoHash (infoHash);
103 | if (infoHash.Length != 32)
104 | throw new ArgumentException("Infohash must be a base32 encoded 32 character string");
105 |
106 | infoHash = infoHash.ToLower();
107 | int infohashOffset =0 ;
108 | byte[] hash = new byte[20];
109 | var temp = new byte[8];
110 | for (int i = 0; i < hash.Length; ) {
111 | for (int j=0; j < 8; j++)
112 | if (!base32DecodeTable.TryGetValue(infoHash[infohashOffset++], out temp[j]))
113 | throw new ArgumentException ("infoHash", "Value is not a valid base32 encoded string");
114 |
115 | //8 * 5bits = 40 bits = 5 bytes
116 | hash[i++] = (byte)((temp[0] << 3) | (temp [1]>> 2));
117 | hash[i++] = (byte)((temp[1] << 6) | (temp[2] << 1) | (temp[3] >> 4));
118 | hash[i++] = (byte)((temp[3] << 4) | (temp [4]>> 1));
119 | hash[i++] = (byte)((temp[4] << 7) | (temp[5] << 2) | (temp [6]>> 3));
120 | hash[i++] = (byte)((temp[6] << 5) | temp[7]);
121 | }
122 |
123 | return new InfoHash(hash);
124 | }
125 |
126 | public static InfoHash FromHex(string infoHash)
127 | {
128 | Check.InfoHash (infoHash);
129 | if (infoHash.Length != 40)
130 | throw new ArgumentException("Infohash must be 40 characters long");
131 |
132 | byte[] hash = new byte[20];
133 | for (int i = 0; i < hash.Length; i++)
134 | hash[i] = byte.Parse(infoHash.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber);
135 |
136 | return new InfoHash(hash);
137 | }
138 |
139 | public static InfoHash FromMagnetLink(string magnetLink)
140 | {
141 | Check.MagnetLink(magnetLink);
142 | if (!magnetLink.StartsWith("magnet:?"))
143 | throw new ArgumentException("Invalid magnet link format");
144 | magnetLink = magnetLink.Substring("magnet:?".Length);
145 | int hashStart = magnetLink.IndexOf("xt=urn:btih:");
146 | if (hashStart == -1)
147 | throw new ArgumentException("Magnet link does not contain an infohash");
148 | hashStart += "xt=urn:btih:".Length;
149 |
150 | int hashEnd = magnetLink.IndexOf('&', hashStart);
151 | if (hashEnd == -1)
152 | hashEnd = magnetLink.Length;
153 |
154 | switch (hashEnd - hashStart)
155 | {
156 | case 32:
157 | return FromBase32(magnetLink.Substring(hashStart, 32));
158 | case 40:
159 | return FromHex(magnetLink.Substring(hashStart, 40));
160 | default:
161 | throw new ArgumentException("Infohash must be base32 or hex encoded.");
162 | }
163 | }
164 |
165 | public static InfoHash UrlDecode(string infoHash)
166 | {
167 | Check.InfoHash(infoHash);
168 | return new InfoHash(UriHelper.UrlDecode(infoHash));
169 | }
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Torrents/TorrentFile.cs:
--------------------------------------------------------------------------------
1 | //
2 | // TorrentFile.cs
3 | //
4 | // Authors:
5 | // Alan McGovern alan.mcgovern@gmail.com
6 | //
7 | // Copyright (C) 2006 Alan McGovern
8 |
9 | using System;
10 | using System.Collections.Generic;
11 | using System.Text;
12 |
13 | namespace TorrentHardLinkHelper.Torrents
14 | {
15 | ///
16 | /// This is the base class for the files available to download from within a .torrent.
17 | /// This should be inherited by both Client and Tracker "TorrentFile" classes
18 | ///
19 | public class TorrentFile : IEquatable
20 | {
21 | #region Private Fields
22 |
23 | private BitField bitfield;
24 | private BitField selector;
25 | private byte[] ed2k;
26 | private int endPiece;
27 | private string fullPath;
28 | private long length;
29 | private byte[] md5;
30 | private string path;
31 | private Priority priority;
32 | private byte[] sha1;
33 | private int startPiece;
34 |
35 | #endregion Private Fields
36 |
37 |
38 | #region Member Variables
39 |
40 | ///
41 | /// The number of pieces which have been successfully downloaded which are from this file
42 | ///
43 | public BitField BitField
44 | {
45 | get { return this.bitfield; }
46 | }
47 |
48 | public long BytesDownloaded
49 | {
50 | get { return (long)(BitField.PercentComplete * Length / 100.0); }
51 | }
52 |
53 | ///
54 | /// The ED2K hash of the file
55 | ///
56 | public byte[] ED2K
57 | {
58 | get { return ed2k; }
59 | }
60 |
61 | ///
62 | /// The index of the last piece of this file
63 | ///
64 | public int EndPieceIndex
65 | {
66 | get { return this.endPiece; }
67 | }
68 |
69 | public string FullPath
70 | {
71 | get { return fullPath; }
72 | internal set { fullPath = value; }
73 | }
74 |
75 | ///
76 | /// The length of the file in bytes
77 | ///
78 | public long Length
79 | {
80 | get { return length; }
81 | }
82 |
83 | ///
84 | /// The MD5 hash of the file
85 | ///
86 | public byte[] MD5
87 | {
88 | get { return this.md5; }
89 | internal set { md5 = value; }
90 | }
91 |
92 | ///
93 | /// In the case of a single torrent file, this is the name of the file.
94 | /// In the case of a multi-file torrent this is the relative path of the file
95 | /// (including the filename) from the base directory
96 | ///
97 | public string Path
98 | {
99 | get { return path; }
100 | }
101 |
102 | ///
103 | /// The priority of this torrent file
104 | ///
105 | public Priority Priority
106 | {
107 | get { return this.priority; }
108 | set { this.priority = value; }
109 | }
110 |
111 | ///
112 | /// The SHA1 hash of the file
113 | ///
114 | public byte[] SHA1
115 | {
116 | get { return this.sha1; }
117 | }
118 |
119 | ///
120 | /// The index of the first piece of this file
121 | ///
122 | public int StartPieceIndex
123 | {
124 | get { return this.startPiece; }
125 | }
126 |
127 | #endregion
128 |
129 |
130 | #region Constructors
131 | public TorrentFile(string path, long length)
132 | : this(path, length, path)
133 | {
134 |
135 | }
136 |
137 | public TorrentFile (string path, long length, string fullPath)
138 | : this (path, length, fullPath, 0, 0)
139 | {
140 |
141 | }
142 |
143 | public TorrentFile (string path, long length, int startIndex, int endIndex)
144 | : this (path, length, path, startIndex, endIndex)
145 | {
146 |
147 | }
148 |
149 | public TorrentFile(string path, long length, string fullPath, int startIndex, int endIndex)
150 | : this(path, length, fullPath, startIndex, endIndex, null, null, null)
151 | {
152 |
153 | }
154 |
155 | public TorrentFile(string path, long length, string fullPath, int startIndex, int endIndex, byte[] md5, byte[] ed2k, byte[] sha1)
156 | {
157 | this.bitfield = new BitField(endIndex - startIndex + 1);
158 | this.ed2k = ed2k;
159 | this.endPiece = endIndex;
160 | this.fullPath = fullPath;
161 | this.length = length;
162 | this.md5 = md5;
163 | this.path = path;
164 | this.priority = Priority.Normal;
165 | this.sha1 = sha1;
166 | this.startPiece = startIndex;
167 | }
168 |
169 | #endregion
170 |
171 |
172 | #region Methods
173 |
174 | public override bool Equals(object obj)
175 | {
176 | return Equals(obj as TorrentFile);
177 | }
178 |
179 | public bool Equals(TorrentFile other)
180 | {
181 | return other == null ? false : path == other.path && length == other.length; ;
182 | }
183 |
184 | public override int GetHashCode()
185 | {
186 | return path.GetHashCode();
187 | }
188 |
189 | internal BitField GetSelector(int totalPieces)
190 | {
191 | if (selector != null)
192 | return selector;
193 |
194 | selector = new BitField(totalPieces);
195 | for (int i = StartPieceIndex; i <= EndPieceIndex; i++)
196 | selector[i] = true;
197 | return selector;
198 | }
199 |
200 | public override string ToString()
201 | {
202 | StringBuilder sb = new StringBuilder(32);
203 | sb.Append("File: ");
204 | sb.Append(path);
205 | sb.Append(" StartIndex: ");
206 | sb.Append(StartPieceIndex);
207 | sb.Append(" EndIndex: ");
208 | sb.Append(EndPieceIndex);
209 | return sb.ToString();
210 | }
211 |
212 | #endregion Methods
213 | }
214 | }
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Common/Check.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace TorrentHardLinkHelper.Common
4 | {
5 | public static class Check
6 | {
7 | static void DoCheck(object toCheck, string name)
8 | {
9 | if (toCheck == null)
10 | throw new ArgumentNullException(name);
11 | }
12 |
13 | static void IsNullOrEmpty(string toCheck, string name)
14 | {
15 | DoCheck(toCheck, name);
16 | if (toCheck.Length == 0)
17 | throw new ArgumentException("Cannot be empty", name);
18 | }
19 |
20 | public static void Address(object address)
21 | {
22 | DoCheck(address, "address");
23 | }
24 |
25 | public static void AddressRange(object addressRange)
26 | {
27 | DoCheck(addressRange, "addressRange");
28 | }
29 |
30 | public static void AddressRanges(object addressRanges)
31 | {
32 | DoCheck(addressRanges, "addressRanges");
33 | }
34 |
35 | public static void Announces(object announces)
36 | {
37 | DoCheck(announces, "announces");
38 | }
39 |
40 | public static void BaseDirectory(object baseDirectory)
41 | {
42 | DoCheck(baseDirectory, "baseDirectory");
43 | }
44 |
45 | internal static void BaseType(Type baseType)
46 | {
47 | DoCheck(baseType, "baseType");
48 | }
49 |
50 | internal static void Buffer(object buffer)
51 | {
52 | DoCheck(buffer, "buffer");
53 | }
54 |
55 | internal static void Cache(object cache)
56 | {
57 | DoCheck(cache, "cache");
58 | }
59 |
60 | public static void Data(object data)
61 | {
62 | DoCheck(data, "data");
63 | }
64 |
65 | public static void Destination(object destination)
66 | {
67 | DoCheck(destination, "destination");
68 | }
69 |
70 | public static void Endpoint(object endpoint)
71 | {
72 | DoCheck(endpoint, "endpoint");
73 | }
74 |
75 | public static void File(object file)
76 | {
77 | DoCheck(file, "file");
78 | }
79 |
80 | public static void Files(object files)
81 | {
82 | DoCheck(files, "files");
83 | }
84 |
85 | public static void FileSource(object fileSource)
86 | {
87 | DoCheck(fileSource, "fileSource");
88 | }
89 |
90 | public static void InfoHash(object infoHash)
91 | {
92 | DoCheck(infoHash, "infoHash");
93 | }
94 |
95 | public static void Key(object key)
96 | {
97 | DoCheck(key, "key");
98 | }
99 |
100 | public static void Limiter(object limiter)
101 | {
102 | DoCheck(limiter, "limiter");
103 | }
104 |
105 | public static void Listener(object listener)
106 | {
107 | DoCheck(listener, "listener");
108 | }
109 |
110 | public static void Location(object location)
111 | {
112 | DoCheck(location, "location");
113 | }
114 |
115 | public static void MagnetLink(object magnetLink)
116 | {
117 | DoCheck(magnetLink, "magnetLink");
118 | }
119 |
120 | public static void Manager(object manager)
121 | {
122 | DoCheck(manager, "manager");
123 | }
124 |
125 | public static void Mappings(object mappings)
126 | {
127 | DoCheck(mappings, "mappings");
128 | }
129 |
130 | public static void Metadata(object metadata)
131 | {
132 | DoCheck(metadata, "metadata");
133 | }
134 |
135 | public static void Name(object name)
136 | {
137 | DoCheck(name, "name");
138 | }
139 |
140 | public static void Path(object path)
141 | {
142 | DoCheck(path, "path");
143 | }
144 |
145 | public static void Paths(object paths)
146 | {
147 | DoCheck(paths, "paths");
148 | }
149 |
150 | public static void PathNotEmpty(string path)
151 | {
152 | IsNullOrEmpty(path, "path");
153 | }
154 |
155 | public static void Peer(object peer)
156 | {
157 | DoCheck(peer, "peer");
158 | }
159 |
160 | public static void Peers(object peers)
161 | {
162 | DoCheck(peers, "peers");
163 | }
164 |
165 | public static void Picker(object picker)
166 | {
167 | DoCheck(picker, "picker");
168 | }
169 |
170 | public static void Result(object result)
171 | {
172 | DoCheck(result, "result");
173 | }
174 |
175 | public static void SavePath(object savePath)
176 | {
177 | DoCheck(savePath, "savePath");
178 | }
179 |
180 | public static void Settings(object settings)
181 | {
182 | DoCheck(settings, "settings");
183 | }
184 |
185 | internal static void SpecificType(Type specificType)
186 | {
187 | DoCheck(specificType, "specificType");
188 | }
189 |
190 | public static void Stream(object stream)
191 | {
192 | DoCheck(stream, "stream");
193 | }
194 |
195 | public static void Torrent(object torrent)
196 | {
197 | DoCheck(torrent, "torrent");
198 | }
199 |
200 | public static void TorrentInformation(object torrentInformation)
201 | {
202 | DoCheck(torrentInformation, "torrentInformation");
203 | }
204 |
205 | public static void TorrentSave(object torrentSave)
206 | {
207 | DoCheck(torrentSave, "torrentSave");
208 | }
209 |
210 | public static void Tracker(object tracker)
211 | {
212 | DoCheck(tracker, "tracker");
213 | }
214 |
215 | public static void Url(object url)
216 | {
217 | DoCheck(url, "url");
218 | }
219 |
220 | public static void Uri(Uri uri)
221 | {
222 | DoCheck(uri, "uri");
223 | }
224 |
225 | public static void Value(object value)
226 | {
227 | DoCheck(value, "value");
228 | }
229 |
230 | public static void Writer(object writer)
231 | {
232 | DoCheck(writer, "writer");
233 | }
234 | }
235 | }
236 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/HardLink/HardLinkHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Text;
6 | using TorrentHardLinkHelper.Locate;
7 |
8 | namespace TorrentHardLinkHelper.HardLink
9 | {
10 | public class HardLinkHelper
11 | {
12 | private StringBuilder _builder;
13 | private List _createdFolders;
14 |
15 | public void HardLink(string sourceFolder, string targetParentFolder, string folderName, int copyLimitSize)
16 | {
17 |
18 | this._builder = new StringBuilder();
19 | this._builder.AppendLine("chcp 65001");
20 | this._builder.AppendLine("::==============================================::");
21 | this._builder.AppendLine(":: Torrent Hard-Link Helper v0.8");
22 | this._builder.AppendLine(":: By Harry Wong(harrywong@live.com), 2013-2014");
23 | this._builder.AppendLine("::");
24 | this._builder.AppendLine(":: Created at " + DateTime.Now);
25 | this._builder.AppendLine("::==============================================::");
26 | this._builder.AppendLine("::.");
27 |
28 | string rootFolder = Path.Combine(targetParentFolder, folderName);
29 | if (!Directory.Exists(rootFolder))
30 | {
31 | CreateFolder(rootFolder);
32 | }
33 | if (!Directory.Exists(targetParentFolder))
34 | {
35 | CreateFolder(targetParentFolder);
36 | }
37 | this.SearchFolder(sourceFolder, rootFolder, copyLimitSize);
38 | var utf8bom = new UTF8Encoding(false);
39 | File.WriteAllText(Path.Combine(rootFolder, "!hard-link.cmd"), this._builder.ToString(), utf8bom);
40 | }
41 |
42 | private void SearchFolder(string folder, string targetParentFolder, int copyLimitSize)
43 | {
44 | if (this._createdFolders == null)
45 | {
46 | this._createdFolders = new List();
47 | }
48 | if (this._createdFolders.Contains(folder))
49 | {
50 | return;
51 | }
52 | foreach (var file in Directory.GetFiles(folder))
53 | {
54 | string targetFile = Path.Combine(targetParentFolder, Path.GetFileName(file));
55 | var fileInfo = new FileInfo(file);
56 | if (fileInfo.Length >= copyLimitSize)
57 | {
58 | CreateHarkLink(file, targetFile);
59 | }
60 | else
61 | {
62 | Copy(file, targetFile);
63 | }
64 | }
65 | foreach (var subFolder in Directory.GetDirectories(folder))
66 | {
67 | string targetSubFolder = Path.Combine(targetParentFolder, Path.GetFileName(subFolder));
68 | if (!Directory.Exists(targetSubFolder))
69 | {
70 | this.CreateFolder(targetSubFolder);
71 | this._createdFolders.Add(targetSubFolder);
72 | }
73 | SearchFolder(subFolder, targetSubFolder, copyLimitSize);
74 | }
75 | }
76 |
77 | public void HardLink(IList links, int copyLimitSize, string folderName, string baseFolde)
78 | {
79 | string rootFolder = Path.Combine(baseFolde, folderName);
80 |
81 | this._builder = new StringBuilder();
82 | this._builder.AppendLine("chcp 65001");
83 | this._builder.AppendLine("::==============================================::");
84 | this._builder.AppendLine(":: Torrent Hard-Link Helper v0.8");
85 | this._builder.AppendLine(":: By Harry Wong(harrywong@live.com), 2013-2014");
86 | this._builder.AppendLine("::");
87 | this._builder.AppendLine(":: Created at " + DateTime.Now);
88 | this._builder.AppendLine("::==============================================::");
89 | this._builder.AppendLine("::.");
90 | if (!Directory.Exists(rootFolder))
91 | {
92 | this.CreateFolder(rootFolder);
93 | }
94 | foreach (var link in links)
95 | {
96 | if (link.LinkedFsFileInfo == null)
97 | {
98 | continue;
99 | }
100 | string[] pathParts = link.TorrentFile.Path.Split('\\');
101 | for (int i = 0; i < pathParts.Length - 1; i++)
102 | {
103 | var targetPathParts = new string[i + 2];
104 | targetPathParts[0] = rootFolder;
105 | Array.Copy(pathParts, 0, targetPathParts, 1, i + 1);
106 | string targetPath = Path.Combine(targetPathParts);
107 | if (!Directory.Exists(targetPath))
108 | {
109 | this.CreateFolder(targetPath);
110 | }
111 | }
112 | string targetFile = Path.Combine(rootFolder, link.TorrentFile.Path);
113 |
114 | if (link.TorrentFile.Length >= copyLimitSize)
115 | {
116 | CreateHarkLink(link.LinkedFsFileInfo.FilePath, targetFile);
117 | }
118 | else
119 | {
120 | Copy(link.LinkedFsFileInfo.FilePath, targetFile);
121 | }
122 | }
123 | File.WriteAllText(Path.Combine(rootFolder, "!hard-link.cmd"), this._builder.ToString(), Encoding.UTF8);
124 | }
125 |
126 | private void CreateHarkLink(string source, string target)
127 | {
128 | this._builder.AppendLine(string.Format("fsutil hardlink create \"{0}\" \"{1}\"", target, source));
129 | var procStartInfo =
130 | new ProcessStartInfo("cmd",
131 | "/c " + string.Format("fsutil hardlink create \"{0}\" \"{1}\"", target, source));
132 |
133 | // The following commands are needed to redirect the standard output.
134 | // This means that it will be redirected to the Process.StandardOutput StreamReader.
135 | procStartInfo.RedirectStandardOutput = true;
136 | procStartInfo.UseShellExecute = false;
137 | // Do not create the black window.
138 | procStartInfo.CreateNoWindow = true;
139 | // Now we create a process, assign its ProcessStartInfo and start it
140 | Process proc = new Process();
141 | proc.StartInfo = procStartInfo;
142 | proc.Start();
143 | }
144 |
145 | public void Copy(string source, string target)
146 | {
147 | this._builder.AppendLine(string.Format("copy /y \"{0}\" \"{1}\"", source, target));
148 | var procStartInfo =
149 | new ProcessStartInfo("cmd",
150 | "/c " + string.Format("copy /y \"{0}\" \"{1}\"", source, target));
151 |
152 | // The following commands are needed to redirect the standard output.
153 | // This means that it will be redirected to the Process.StandardOutput StreamReader.
154 | procStartInfo.RedirectStandardOutput = true;
155 | procStartInfo.UseShellExecute = false;
156 | // Do not create the black window.
157 | procStartInfo.CreateNoWindow = true;
158 | // Now we create a process, assign its ProcessStartInfo and start it
159 | Process proc = new Process();
160 | proc.StartInfo = procStartInfo;
161 | proc.Start();
162 | }
163 |
164 | private void CreateFolder(string path)
165 | {
166 | this._builder.AppendLine(string.Format("mkdir \"{0}\"", path));
167 | Directory.CreateDirectory(path);
168 | }
169 | }
170 | }
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/BEncoding/BEncodedList.cs:
--------------------------------------------------------------------------------
1 | //
2 | // BEncodedList.cs
3 | //
4 | // Authors:
5 | // Alan McGovern alan.mcgovern@gmail.com
6 | //
7 | // Copyright (C) 2006 Alan McGovern
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining
10 | // a copy of this software and associated documentation files (the
11 | // "Software"), to deal in the Software without restriction, including
12 | // without limitation the rights to use, copy, modify, merge, publish,
13 | // distribute, sublicense, and/or sell copies of the Software, and to
14 | // permit persons to whom the Software is furnished to do so, subject to
15 | // the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 |
30 |
31 | using System;
32 | using System.Collections.Generic;
33 | using System.Text;
34 | using System.IO;
35 |
36 | namespace TorrentHardLinkHelper.BEncoding
37 | {
38 | ///
39 | /// Class representing a BEncoded list
40 | ///
41 | public class BEncodedList : BEncodedValue, IList
42 | {
43 | #region Member Variables
44 |
45 | private List list;
46 |
47 | #endregion
48 |
49 |
50 | #region Constructors
51 | ///
52 | /// Create a new BEncoded List with default capacity
53 | ///
54 | public BEncodedList()
55 | : this(new List())
56 | {
57 | }
58 |
59 | ///
60 | /// Create a new BEncoded List with the supplied capacity
61 | ///
62 | /// The initial capacity
63 | public BEncodedList(int capacity)
64 | : this(new List(capacity))
65 | {
66 |
67 | }
68 |
69 | public BEncodedList(IEnumerable list)
70 | {
71 | if (list == null)
72 | throw new ArgumentNullException("list");
73 |
74 | this.list = new List(list);
75 | }
76 |
77 | private BEncodedList(List value)
78 | {
79 | this.list = value;
80 | }
81 |
82 | #endregion
83 |
84 |
85 | #region Encode/Decode Methods
86 |
87 |
88 | ///
89 | /// Encodes the list to a byte[]
90 | ///
91 | /// The buffer to encode the list to
92 | /// The offset to start writing the data at
93 | ///
94 | public override int Encode(byte[] buffer, int offset)
95 | {
96 | int written = 0;
97 | buffer[offset] = (byte)'l';
98 | written++;
99 | for (int i = 0; i < this.list.Count; i++)
100 | written += this.list[i].Encode(buffer, offset + written);
101 | buffer[offset + written] = (byte)'e';
102 | written++;
103 | return written;
104 | }
105 |
106 | ///
107 | /// Decodes a BEncodedList from the given StreamReader
108 | ///
109 | ///
110 | internal override void DecodeInternal(RawReader reader)
111 | {
112 | if (reader.ReadByte() != 'l') // Remove the leading 'l'
113 | throw new BEncodingException("Invalid data found. Aborting");
114 |
115 | while ((reader.PeekByte() != -1) && (reader.PeekByte() != 'e'))
116 | list.Add(BEncodedValue.Decode(reader));
117 |
118 | if (reader.ReadByte() != 'e') // Remove the trailing 'e'
119 | throw new BEncodingException("Invalid data found. Aborting");
120 | }
121 | #endregion
122 |
123 |
124 | #region Helper Methods
125 | ///
126 | /// Returns the size of the list in bytes
127 | ///
128 | ///
129 | public override int LengthInBytes()
130 | {
131 | int length = 0;
132 |
133 | length += 1; // Lists start with 'l'
134 | for (int i=0; i < this.list.Count; i++)
135 | length += this.list[i].LengthInBytes();
136 |
137 | length += 1; // Lists end with 'e'
138 | return length;
139 | }
140 | #endregion
141 |
142 |
143 | #region Overridden Methods
144 | public override bool Equals(object obj)
145 | {
146 | BEncodedList other = obj as BEncodedList;
147 |
148 | if (other == null)
149 | return false;
150 |
151 | for (int i = 0; i < this.list.Count; i++)
152 | if (!this.list[i].Equals(other.list[i]))
153 | return false;
154 |
155 | return true;
156 | }
157 |
158 |
159 | public override int GetHashCode()
160 | {
161 | int result = 0;
162 | for (int i = 0; i < list.Count; i++)
163 | result ^= list[i].GetHashCode();
164 |
165 | return result;
166 | }
167 |
168 |
169 | public override string ToString()
170 | {
171 | return System.Text.Encoding.UTF8.GetString(Encode());
172 | }
173 | #endregion
174 |
175 |
176 | #region IList methods
177 | public void Add(BEncodedValue item)
178 | {
179 | this.list.Add(item);
180 | }
181 |
182 | public void AddRange (IEnumerable collection)
183 | {
184 | list.AddRange (collection);
185 | }
186 |
187 | public void Clear()
188 | {
189 | this.list.Clear();
190 | }
191 |
192 | public bool Contains(BEncodedValue item)
193 | {
194 | return this.list.Contains(item);
195 | }
196 |
197 | public void CopyTo(BEncodedValue[] array, int arrayIndex)
198 | {
199 | this.list.CopyTo(array, arrayIndex);
200 | }
201 |
202 | public int Count
203 | {
204 | get { return this.list.Count; }
205 | }
206 |
207 | public int IndexOf(BEncodedValue item)
208 | {
209 | return this.list.IndexOf(item);
210 | }
211 |
212 | public void Insert(int index, BEncodedValue item)
213 | {
214 | this.list.Insert(index, item);
215 | }
216 |
217 | public bool IsReadOnly
218 | {
219 | get { return false; }
220 | }
221 |
222 | public bool Remove(BEncodedValue item)
223 | {
224 | return this.list.Remove(item);
225 | }
226 |
227 | public void RemoveAt(int index)
228 | {
229 | this.list.RemoveAt(index);
230 | }
231 |
232 | public BEncodedValue this[int index]
233 | {
234 | get { return this.list[index]; }
235 | set { this.list[index] = value; }
236 | }
237 |
238 | public IEnumerator GetEnumerator()
239 | {
240 | return this.list.GetEnumerator();
241 | }
242 |
243 | System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
244 | {
245 | return this.GetEnumerator();
246 | }
247 | #endregion
248 | }
249 | }
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/BEncoding/BEncodedNumber.cs:
--------------------------------------------------------------------------------
1 | //
2 | // BEncodedNumber.cs
3 | //
4 | // Authors:
5 | // Alan McGovern alan.mcgovern@gmail.com
6 | //
7 | // Copyright (C) 2006 Alan McGovern
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining
10 | // a copy of this software and associated documentation files (the
11 | // "Software"), to deal in the Software without restriction, including
12 | // without limitation the rights to use, copy, modify, merge, publish,
13 | // distribute, sublicense, and/or sell copies of the Software, and to
14 | // permit persons to whom the Software is furnished to do so, subject to
15 | // the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 |
30 |
31 | using System;
32 | using System.IO;
33 | using System.Text;
34 | using System.Collections.Generic;
35 |
36 | namespace TorrentHardLinkHelper.BEncoding
37 | {
38 | ///
39 | /// Class representing a BEncoded number
40 | ///
41 | public class BEncodedNumber : BEncodedValue, IComparable
42 | {
43 | #region Member Variables
44 | ///
45 | /// The value of the BEncodedNumber
46 | ///
47 | public long Number
48 | {
49 | get { return number; }
50 | set { number = value; }
51 | }
52 | internal long number;
53 | #endregion
54 |
55 |
56 | #region Constructors
57 | public BEncodedNumber()
58 | : this(0)
59 | {
60 | }
61 |
62 | ///
63 | /// Create a new BEncoded number with the given value
64 | ///
65 | /// The inital value of the BEncodedNumber
66 | public BEncodedNumber(long value)
67 | {
68 | this.number = value;
69 | }
70 |
71 | public static implicit operator BEncodedNumber(long value)
72 | {
73 | return new BEncodedNumber(value);
74 | }
75 | #endregion
76 |
77 |
78 | #region Encode/Decode Methods
79 |
80 | ///
81 | /// Encodes this number to the supplied byte[] starting at the supplied offset
82 | ///
83 | /// The buffer to write the data to
84 | /// The offset to start writing the data at
85 | ///
86 | public override int Encode(byte[] buffer, int offset)
87 | {
88 | long number = this.number;
89 |
90 | int written = offset;
91 | buffer[written++] = (byte)'i';
92 |
93 | if (number < 0)
94 | {
95 | buffer[written++] = (byte)'-';
96 | number = -number;
97 | }
98 | // Reverse the number '12345' to get '54321'
99 | long reversed = 0;
100 | for (long i = number; i != 0; i /= 10)
101 | reversed = reversed * 10 + i % 10;
102 |
103 | // Write each digit of the reversed number to the array. We write '1'
104 | // first, then '2', etc
105 | for (long i = reversed; i != 0; i /= 10)
106 | buffer[written++] = (byte)(i % 10 + '0');
107 |
108 | if (number == 0)
109 | buffer[written++] = (byte)'0';
110 |
111 | // If the original number ends in one or more zeros, they are lost
112 | // when we reverse the number. We add them back in here.
113 | for (long i = number; i % 10 == 0 && number != 0; i /= 10)
114 | buffer[written++] = (byte)'0';
115 |
116 | buffer[written++] = (byte)'e';
117 | return written - offset;
118 | }
119 |
120 |
121 | ///
122 | /// Decodes a BEncoded number from the supplied RawReader
123 | ///
124 | /// RawReader containing a BEncoded Number
125 | internal override void DecodeInternal(RawReader reader)
126 | {
127 | int sign = 1;
128 | if (reader == null)
129 | throw new ArgumentNullException("reader");
130 |
131 | if (reader.ReadByte() != 'i') // remove the leading 'i'
132 | throw new BEncodingException("Invalid data found. Aborting.");
133 |
134 | if (reader.PeekByte() == '-')
135 | {
136 | sign = -1;
137 | reader.ReadByte ();
138 | }
139 |
140 | int letter;
141 | while (((letter = reader.PeekByte()) != -1) && letter != 'e')
142 | {
143 | if(letter < '0' || letter > '9')
144 | throw new BEncodingException("Invalid number found.");
145 | number = number * 10 + (letter - '0');
146 | reader.ReadByte ();
147 | }
148 | if (reader.ReadByte() != 'e') //remove the trailing 'e'
149 | throw new BEncodingException("Invalid data found. Aborting.");
150 |
151 | number *= sign;
152 | }
153 | #endregion
154 |
155 |
156 | #region Helper Methods
157 | ///
158 | /// Returns the length of the encoded string in bytes
159 | ///
160 | ///
161 | public override int LengthInBytes()
162 | {
163 | long number = this.number;
164 | int count = 2; // account for the 'i' and 'e'
165 |
166 | if (number == 0)
167 | return count + 1;
168 |
169 | if (number < 0)
170 | {
171 | number = -number;
172 | count++;
173 | }
174 | for (long i = number; i != 0; i /= 10)
175 | count++;
176 |
177 | return count;
178 | }
179 |
180 |
181 | public int CompareTo(object other)
182 | {
183 | if (other is BEncodedNumber || other is long || other is int)
184 | return CompareTo((BEncodedNumber)other);
185 |
186 | return -1;
187 | }
188 |
189 | public int CompareTo(BEncodedNumber other)
190 | {
191 | if (other == null)
192 | throw new ArgumentNullException("other");
193 |
194 | return this.number.CompareTo(other.number);
195 | }
196 |
197 |
198 | public int CompareTo(long other)
199 | {
200 | return this.number.CompareTo(other);
201 | }
202 | #endregion
203 |
204 |
205 | #region Overridden Methods
206 | ///
207 | ///
208 | ///
209 | ///
210 | ///
211 | public override bool Equals(object obj)
212 | {
213 | BEncodedNumber obj2 = obj as BEncodedNumber;
214 | if (obj2 == null)
215 | return false;
216 |
217 | return (this.number == obj2.number);
218 | }
219 |
220 | ///
221 | ///
222 | ///
223 | ///
224 | public override int GetHashCode()
225 | {
226 | return this.number.GetHashCode();
227 | }
228 |
229 | ///
230 | ///
231 | ///
232 | ///
233 | public override string ToString()
234 | {
235 | return (this.number.ToString());
236 | }
237 | #endregion
238 | }
239 | }
240 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/Views/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/BEncoding/BEncodedString.cs:
--------------------------------------------------------------------------------
1 | //
2 | // BEncodedString.cs
3 | //
4 | // Authors:
5 | // Alan McGovern alan.mcgovern@gmail.com
6 | //
7 | // Copyright (C) 2006 Alan McGovern
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining
10 | // a copy of this software and associated documentation files (the
11 | // "Software"), to deal in the Software without restriction, including
12 | // without limitation the rights to use, copy, modify, merge, publish,
13 | // distribute, sublicense, and/or sell copies of the Software, and to
14 | // permit persons to whom the Software is furnished to do so, subject to
15 | // the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 |
30 |
31 | using System;
32 | using System.IO;
33 | using System.Collections;
34 | using System.Text;
35 | using TorrentHardLinkHelper.Common;
36 | using TorrentHardLinkHelper.Messages;
37 |
38 | namespace TorrentHardLinkHelper.BEncoding
39 | {
40 | ///
41 | /// Class representing a BEncoded string
42 | ///
43 | public class BEncodedString : BEncodedValue, IComparable
44 | {
45 | #region Member Variables
46 |
47 | ///
48 | /// The value of the BEncodedString
49 | ///
50 | public string Text
51 | {
52 | get { return Encoding.UTF8.GetString(textBytes); }
53 | set { textBytes = Encoding.UTF8.GetBytes(value); }
54 | }
55 |
56 | ///
57 | /// The underlying byte[] associated with this BEncodedString
58 | ///
59 | public byte[] TextBytes
60 | {
61 | get { return this.textBytes; }
62 | }
63 | private byte[] textBytes;
64 | #endregion
65 |
66 |
67 | #region Constructors
68 | ///
69 | /// Create a new BEncodedString using UTF8 encoding
70 | ///
71 | public BEncodedString()
72 | : this(new byte[0])
73 | {
74 | }
75 |
76 | ///
77 | /// Create a new BEncodedString using UTF8 encoding
78 | ///
79 | ///
80 | public BEncodedString(char[] value)
81 | : this(System.Text.Encoding.UTF8.GetBytes(value))
82 | {
83 | }
84 |
85 | ///
86 | /// Create a new BEncodedString using UTF8 encoding
87 | ///
88 | /// Initial value for the string
89 | public BEncodedString(string value)
90 | : this(System.Text.Encoding.UTF8.GetBytes(value))
91 | {
92 | }
93 |
94 |
95 | ///
96 | /// Create a new BEncodedString using UTF8 encoding
97 | ///
98 | ///
99 | public BEncodedString(byte[] value)
100 | {
101 | this.textBytes = value;
102 | }
103 |
104 |
105 | public static implicit operator BEncodedString(string value)
106 | {
107 | return new BEncodedString(value);
108 | }
109 | public static implicit operator BEncodedString(char[] value)
110 | {
111 | return new BEncodedString(value);
112 | }
113 | public static implicit operator BEncodedString(byte[] value)
114 | {
115 | return new BEncodedString(value);
116 | }
117 | #endregion
118 |
119 |
120 | #region Encode/Decode Methods
121 |
122 |
123 | ///
124 | /// Encodes the BEncodedString to a byte[] using the supplied Encoding
125 | ///
126 | /// The buffer to encode the string to
127 | /// The offset at which to save the data to
128 | /// The encoding to use
129 | /// The number of bytes encoded
130 | public override int Encode(byte[] buffer, int offset)
131 | {
132 | int written = offset;
133 | written += Message.WriteAscii(buffer, written, textBytes.Length.ToString ());
134 | written += Message.WriteAscii(buffer, written, ":");
135 | written += Message.Write(buffer, written, textBytes);
136 | return written - offset;
137 | }
138 |
139 |
140 | ///
141 | /// Decodes a BEncodedString from the supplied StreamReader
142 | ///
143 | /// The StreamReader containing the BEncodedString
144 | internal override void DecodeInternal(RawReader reader)
145 | {
146 | if (reader == null)
147 | throw new ArgumentNullException("reader");
148 |
149 | int letterCount;
150 | string length = string.Empty;
151 |
152 | while ((reader.PeekByte() != -1) && (reader.PeekByte() != ':')) // read in how many characters
153 | length += (char)reader.ReadByte(); // the string is
154 |
155 | if (reader.ReadByte() != ':') // remove the ':'
156 | throw new BEncodingException("Invalid data found. Aborting");
157 |
158 | if (!int.TryParse(length, out letterCount))
159 | throw new BEncodingException(string.Format("Invalid BEncodedString. Length was '{0}' instead of a number", length));
160 |
161 | this.textBytes = new byte[letterCount];
162 | if (reader.Read(textBytes, 0, letterCount) != letterCount)
163 | throw new BEncodingException("Couldn't decode string");
164 | }
165 | #endregion
166 |
167 |
168 | #region Helper Methods
169 | public string Hex
170 | {
171 | get { return BitConverter.ToString(TextBytes); }
172 | }
173 |
174 | public override int LengthInBytes()
175 | {
176 | // The length is equal to the length-prefix + ':' + length of data
177 | int prefix = 1; // Account for ':'
178 |
179 | // Count the number of characters needed for the length prefix
180 | for (int i = textBytes.Length; i != 0; i = i/10)
181 | prefix += 1;
182 |
183 | if (textBytes.Length == 0)
184 | prefix++;
185 |
186 | return prefix + textBytes.Length;
187 | }
188 |
189 | public int CompareTo(object other)
190 | {
191 | return CompareTo(other as BEncodedString);
192 | }
193 |
194 |
195 | public int CompareTo(BEncodedString other)
196 | {
197 | if (other == null)
198 | return 1;
199 |
200 | int difference=0;
201 | int length = this.textBytes.Length > other.textBytes.Length ? other.textBytes.Length : this.textBytes.Length;
202 |
203 | for (int i = 0; i < length; i++)
204 | if ((difference = this.textBytes[i].CompareTo(other.textBytes[i])) != 0)
205 | return difference;
206 |
207 | if (this.textBytes.Length == other.textBytes.Length)
208 | return 0;
209 |
210 | return this.textBytes.Length > other.textBytes.Length ? 1 : -1;
211 | }
212 |
213 | #endregion
214 |
215 |
216 | #region Overridden Methods
217 |
218 | public override bool Equals(object obj)
219 | {
220 | if (obj == null)
221 | return false;
222 |
223 | BEncodedString other;
224 | if (obj is string)
225 | other = new BEncodedString((string)obj);
226 | else if (obj is BEncodedString)
227 | other = (BEncodedString)obj;
228 | else
229 | return false;
230 |
231 | return Toolbox.ByteMatch(this.textBytes, other.textBytes);
232 | }
233 |
234 | public override int GetHashCode()
235 | {
236 | int hash = 0;
237 | for (int i = 0; i < this.textBytes.Length; i++)
238 | hash += this.textBytes[i];
239 |
240 | return hash;
241 | }
242 |
243 | public override string ToString()
244 | {
245 | return System.Text.Encoding.UTF8.GetString(textBytes);
246 | }
247 |
248 | #endregion
249 | }
250 | }
251 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/Locate/TorrentFileLocater.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Security.Cryptography;
6 | using TorrentHardLinkHelper.Torrents;
7 |
8 | namespace TorrentHardLinkHelper.Locate
9 | {
10 | public class TorrentFileLocater
11 | {
12 | private readonly IList _fsfiFileInfos;
13 | private readonly IList _torrentFileLinks;
14 | private readonly Dictionary _pieceCheckedReusltsDictionary;
15 | private readonly Torrent _torrent;
16 |
17 | private readonly Action _fileLocating;
18 |
19 | public TorrentFileLocater()
20 | {
21 | this._torrentFileLinks = new List();
22 | }
23 |
24 | public TorrentFileLocater(Torrent torrent)
25 | : this()
26 | {
27 | this._torrent = torrent;
28 | this._pieceCheckedReusltsDictionary = new Dictionary(this._torrent.Pieces.Count);
29 | }
30 |
31 | public TorrentFileLocater(Torrent torrent, IList fsfiFileInfos)
32 | : this(torrent)
33 | {
34 | this._fsfiFileInfos = fsfiFileInfos;
35 | }
36 |
37 | public TorrentFileLocater(Torrent torrent, IList fsfiFileInfos, Action fileLocating)
38 | : this(torrent, fsfiFileInfos)
39 | {
40 | this._fileLocating = fileLocating;
41 | }
42 |
43 |
44 | public LocateResult Locate()
45 | {
46 | if (this._torrent == null)
47 | {
48 | throw new ArgumentException("Torrent cannot be null.");
49 | }
50 | if (this._fsfiFileInfos == null || this._fsfiFileInfos.Count == 0)
51 | {
52 | throw new ArgumentException("FsFileInfos cannot be null or zero");
53 | }
54 |
55 | this.FindTorrentFileLinks();
56 | this.ConfirmFileSystemFiles();
57 | return new LocateResult(this._torrentFileLinks);
58 | }
59 |
60 | private void FindTorrentFileLinks()
61 | {
62 | foreach (TorrentFile torrentFile in this._torrent.Files)
63 | {
64 | var fileLink = new TorrentFileLink(torrentFile);
65 | foreach (FileSystemFileInfo fsFileInfo in this._fsfiFileInfos)
66 | {
67 | if (fsFileInfo.Length == torrentFile.Length)
68 | {
69 | fileLink.FsFileInfos.Add(fsFileInfo);
70 | }
71 | }
72 | if (fileLink.FsFileInfos.Count > 1)
73 | {
74 | var torrentFilePathParts = torrentFile.Path.Split('\\').ToList();
75 | torrentFilePathParts.Insert(0, this._torrent.Name);
76 | for (int i = 0; i < torrentFilePathParts.Count; i++)
77 | {
78 | var links = new List();
79 | foreach (var fileInfo in fileLink.FsFileInfos)
80 | {
81 | var filePathPaths = fileInfo.FilePath.Split('\\');
82 | if (filePathPaths.Length > i + 1 &&
83 | filePathPaths[filePathPaths.Length - i - 1].ToUpperInvariant() ==
84 | torrentFilePathParts[torrentFilePathParts.Count - i - 1].ToUpperInvariant())
85 | {
86 | links.Add(fileInfo);
87 | }
88 | }
89 | if (links.Count == 0)
90 | {
91 | break;
92 | }
93 | if (links.Count >= 1)
94 | {
95 | fileLink.FsFileInfos = links;
96 | if (links.Count == 1)
97 | {
98 | break;
99 | }
100 | }
101 | }
102 | }
103 | if (fileLink.FsFileInfos.Count == 1)
104 | {
105 | fileLink.State = LinkState.Located;
106 | fileLink.LinkedFsFileIndex = 0;
107 | }
108 | else if (fileLink.FsFileInfos.Count > 1)
109 | {
110 | fileLink.State = LinkState.NeedConfirm;
111 | }
112 | else
113 | {
114 | fileLink.State = LinkState.Fail;
115 | }
116 |
117 | this._torrentFileLinks.Add(fileLink);
118 | }
119 | }
120 |
121 | private void ConfirmFileSystemFiles()
122 | {
123 | foreach (TorrentFileLink fileLink in this._torrentFileLinks)
124 | {
125 | if (this._fileLocating != null)
126 | {
127 | this._fileLocating.Invoke();
128 | }
129 | if (fileLink.State == LinkState.Located)
130 | {
131 | continue;
132 | }
133 | if (fileLink.State == LinkState.Fail)
134 | {
135 | if (fileLink.TorrentFile.EndPieceIndex - fileLink.TorrentFile.StartPieceIndex > 2)
136 | {
137 | fileLink.State = CheckPiece(fileLink.TorrentFile.StartPieceIndex + 1)
138 | ? LinkState.Located
139 | : LinkState.Fail;
140 | }
141 | continue;
142 | }
143 | for (int i = fileLink.TorrentFile.StartPieceIndex; i <= fileLink.TorrentFile.EndPieceIndex; i++)
144 | {
145 | if (!CheckPiece(i))
146 | {
147 | break;
148 | }
149 | if (fileLink.State == LinkState.Located)
150 | {
151 | break;
152 | }
153 | }
154 | }
155 | }
156 |
157 | private bool CheckPiece(int pieceIndex)
158 | {
159 | bool result;
160 | if (this._pieceCheckedReusltsDictionary.TryGetValue(pieceIndex, out result))
161 | {
162 | return result;
163 | }
164 | ulong startPos = (ulong)pieceIndex * (ulong)this._torrent.PieceLength;
165 | ulong pos = 0;
166 | ulong writenLength = 0;
167 | var filePieces = new List();
168 | foreach (TorrentFileLink fileLink in this._torrentFileLinks)
169 | {
170 | if (pos + (ulong)fileLink.TorrentFile.Length >= startPos)
171 | {
172 | ulong readPos = startPos - pos;
173 | ulong readLength = (ulong)fileLink.TorrentFile.Length - readPos;
174 | if (writenLength + readLength > (ulong)this._torrent.PieceLength)
175 | {
176 | readLength = (ulong)this._torrent.PieceLength - writenLength;
177 | }
178 |
179 | var filePiece = new FileLinkPiece
180 | {
181 | FileLink = fileLink,
182 | ReadLength = readLength,
183 | StartPos = readPos
184 | };
185 | filePieces.Add(filePiece);
186 |
187 | writenLength += readLength;
188 | startPos += readLength;
189 | if (writenLength == (ulong)this._torrent.PieceLength)
190 | {
191 | break;
192 | }
193 | }
194 | pos += (ulong)fileLink.TorrentFile.Length;
195 | }
196 |
197 | var hash = new HashFileLinkPieces(this._torrent, pieceIndex, filePieces);
198 | string pattern = hash.Run();
199 | if (string.IsNullOrEmpty(pattern))
200 | {
201 | foreach (FileLinkPiece piece in filePieces)
202 | {
203 | if (piece.FileLink.State == LinkState.NeedConfirm)
204 | {
205 | piece.FileLink.State = LinkState.Fail;
206 | }
207 | }
208 | this._pieceCheckedReusltsDictionary.Add(pieceIndex, false);
209 | return false;
210 | }
211 | for (int i = 0; i < filePieces.Count; i++)
212 | {
213 | if (filePieces[i].FileLink.State == LinkState.NeedConfirm)
214 | {
215 | filePieces[i].FileLink.LinkedFsFileIndex = int.Parse(pattern.Split(',')[i]);
216 | filePieces[i].FileLink.LinkedFsFileInfo.Located = true;
217 | filePieces[i].FileLink.State = LinkState.Located;
218 | }
219 | }
220 | this._pieceCheckedReusltsDictionary.Add(pieceIndex, true);
221 | return true;
222 | }
223 | }
224 | }
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/BEncoding/IBEncodedValue.cs:
--------------------------------------------------------------------------------
1 | //
2 | // IBEncodedValue.cs
3 | //
4 | // Authors:
5 | // Alan McGovern alan.mcgovern@gmail.com
6 | //
7 | // Copyright (C) 2006 Alan McGovern
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining
10 | // a copy of this software and associated documentation files (the
11 | // "Software"), to deal in the Software without restriction, including
12 | // without limitation the rights to use, copy, modify, merge, publish,
13 | // distribute, sublicense, and/or sell copies of the Software, and to
14 | // permit persons to whom the Software is furnished to do so, subject to
15 | // the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 |
30 |
31 | using System;
32 | using System.IO;
33 | using System.Text;
34 | using TorrentHardLinkHelper.BEncoding;
35 | using TorrentHardLinkHelper.Common;
36 |
37 | namespace TorrentHardLinkHelper.BEncoding
38 | {
39 | ///
40 | /// Base interface for all BEncoded values.
41 | ///
42 | public abstract class BEncodedValue
43 | {
44 | internal abstract void DecodeInternal(RawReader reader);
45 |
46 | ///
47 | /// Encodes the BEncodedValue into a byte array
48 | ///
49 | /// Byte array containing the BEncoded Data
50 | public byte[] Encode()
51 | {
52 | byte[] buffer = new byte[LengthInBytes()];
53 | if (Encode(buffer, 0) != buffer.Length)
54 | throw new BEncodingException("Error encoding the data");
55 |
56 | return buffer;
57 | }
58 |
59 |
60 | ///
61 | /// Encodes the BEncodedValue into the supplied buffer
62 | ///
63 | /// The buffer to encode the information to
64 | /// The offset in the buffer to start writing the data
65 | ///
66 | public abstract int Encode(byte[] buffer, int offset);
67 |
68 | public static T Clone (T value)
69 | where T : BEncodedValue
70 | {
71 | Check.Value (value);
72 | return (T) BEncodedValue.Decode (value.Encode ());
73 | }
74 |
75 | ///
76 | /// Interface for all BEncoded values
77 | ///
78 | /// The byte array containing the BEncoded data
79 | ///
80 | public static BEncodedValue Decode(byte[] data)
81 | {
82 | if (data == null)
83 | throw new ArgumentNullException("data");
84 |
85 | using (RawReader stream = new RawReader(new MemoryStream(data)))
86 | return (Decode(stream));
87 | }
88 |
89 | internal static BEncodedValue Decode(byte[] buffer, bool strictDecoding)
90 | {
91 | return Decode(buffer, 0, buffer.Length, strictDecoding);
92 | }
93 |
94 | ///
95 | /// Decode BEncoded data in the given byte array
96 | ///
97 | /// The byte array containing the BEncoded data
98 | /// The offset at which the data starts at
99 | /// The number of bytes to be decoded
100 | /// BEncodedValue containing the data that was in the byte[]
101 | public static BEncodedValue Decode(byte[] buffer, int offset, int length)
102 | {
103 | return Decode(buffer, offset, length, true);
104 | }
105 |
106 | public static BEncodedValue Decode(byte[] buffer, int offset, int length, bool strictDecoding)
107 | {
108 | if (buffer == null)
109 | throw new ArgumentNullException("buffer");
110 |
111 | if (offset < 0 || length < 0)
112 | throw new IndexOutOfRangeException("Neither offset or length can be less than zero");
113 |
114 | if (offset > buffer.Length - length)
115 | throw new ArgumentOutOfRangeException("length");
116 |
117 | using (RawReader reader = new RawReader(new MemoryStream(buffer, offset, length), strictDecoding))
118 | return (BEncodedValue.Decode(reader));
119 | }
120 |
121 |
122 | ///
123 | /// Decode BEncoded data in the given stream
124 | ///
125 | /// The stream containing the BEncoded data
126 | /// BEncodedValue containing the data that was in the stream
127 | public static BEncodedValue Decode(Stream stream)
128 | {
129 | if (stream == null)
130 | throw new ArgumentNullException("stream");
131 |
132 | return Decode(new RawReader(stream));
133 | }
134 |
135 |
136 | ///
137 | /// Decode BEncoded data in the given RawReader
138 | ///
139 | /// The RawReader containing the BEncoded data
140 | /// BEncodedValue containing the data that was in the stream
141 | public static BEncodedValue Decode(RawReader reader)
142 | {
143 | if (reader == null)
144 | throw new ArgumentNullException("reader");
145 |
146 | BEncodedValue data;
147 | switch (reader.PeekByte())
148 | {
149 | case ('i'): // Integer
150 | data = new BEncodedNumber();
151 | break;
152 |
153 | case ('d'): // Dictionary
154 | data = new BEncodedDictionary();
155 | break;
156 |
157 | case ('l'): // List
158 | data = new BEncodedList();
159 | break;
160 |
161 | case ('1'): // String
162 | case ('2'):
163 | case ('3'):
164 | case ('4'):
165 | case ('5'):
166 | case ('6'):
167 | case ('7'):
168 | case ('8'):
169 | case ('9'):
170 | case ('0'):
171 | data = new BEncodedString();
172 | break;
173 |
174 | default:
175 | throw new BEncodingException("Could not find what value to decode");
176 | }
177 |
178 | data.DecodeInternal(reader);
179 | return data;
180 | }
181 |
182 |
183 | ///
184 | /// Interface for all BEncoded values
185 | ///
186 | /// The byte array containing the BEncoded data
187 | ///
188 | public static T Decode(byte[] data) where T : BEncodedValue
189 | {
190 | return (T)BEncodedValue.Decode(data);
191 | }
192 |
193 |
194 | ///
195 | /// Decode BEncoded data in the given byte array
196 | ///
197 | /// The byte array containing the BEncoded data
198 | /// The offset at which the data starts at
199 | /// The number of bytes to be decoded
200 | /// BEncodedValue containing the data that was in the byte[]
201 | public static T Decode(byte[] buffer, int offset, int length) where T : BEncodedValue
202 | {
203 | return BEncodedValue.Decode(buffer, offset, length, true);
204 | }
205 |
206 | public static T Decode(byte[] buffer, int offset, int length, bool strictDecoding) where T : BEncodedValue
207 | {
208 | return (T)BEncodedValue.Decode(buffer, offset, length, strictDecoding);
209 | }
210 |
211 |
212 | ///
213 | /// Decode BEncoded data in the given stream
214 | ///
215 | /// The stream containing the BEncoded data
216 | /// BEncodedValue containing the data that was in the stream
217 | public static T Decode(Stream stream) where T : BEncodedValue
218 | {
219 | return (T)BEncodedValue.Decode(stream);
220 | }
221 |
222 |
223 | public static T Decode(RawReader reader) where T : BEncodedValue
224 | {
225 | return (T)BEncodedValue.Decode(reader);
226 | }
227 |
228 |
229 | ///
230 | /// Returns the size of the byte[] needed to encode this BEncodedValue
231 | ///
232 | ///
233 | public abstract int LengthInBytes();
234 | }
235 | }
236 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper/TorrentHardLinkHelper.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {F60A582A-C5E4-4D17-97AB-B30E24F22D08}
8 | WinExe
9 | Properties
10 | TorrentHardLinkHelper
11 | TorrentHardLinkHelper
12 | v4.0
13 | 512
14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
15 | 4
16 | false
17 | D:\hardlinktest\
18 | true
19 | Disk
20 | false
21 | Foreground
22 | 7
23 | Days
24 | false
25 | false
26 | true
27 | 1
28 | 1.0.0.%2a
29 | false
30 | true
31 | true
32 |
33 |
34 | AnyCPU
35 | true
36 | full
37 | false
38 | bin\Debug\
39 | DEBUG;TRACE
40 | prompt
41 | 4
42 |
43 |
44 | AnyCPU
45 | pdbonly
46 | true
47 | bin\Release\
48 | TRACE
49 | prompt
50 | 4
51 |
52 |
53 | 6221D2BFC157999FB0D7F00DE2A9B0318A0A1495
54 |
55 |
56 | TorrentHardLinkHelper_TemporaryKey.pfx
57 |
58 |
59 | true
60 |
61 |
62 | false
63 |
64 |
65 | ico2.ico
66 |
67 |
68 |
69 | ..\packages\MvvmLightLibs.5.3.0.0\lib\net40\GalaSoft.MvvmLight.dll
70 | True
71 |
72 |
73 | ..\packages\MvvmLightLibs.5.3.0.0\lib\net40\GalaSoft.MvvmLight.Extras.dll
74 | True
75 |
76 |
77 | ..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll
78 |
79 |
80 | ..\packages\Ookii.Dialogs.1.0\lib\net35\Ookii.Dialogs.Wpf.dll
81 |
82 |
83 |
84 |
85 |
86 | ..\packages\MvvmLightLibs.5.3.0.0\lib\net40\System.Windows.Interactivity.dll
87 | True
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 | 4.0
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 | MSBuild:Compile
104 | Designer
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 | Designer
114 | MSBuild:Compile
115 |
116 |
117 | MSBuild:Compile
118 | Designer
119 |
120 |
121 | App.xaml
122 | Code
123 |
124 |
125 | HardLinkTool.xaml
126 |
127 |
128 | MainWindow.xaml
129 | Code
130 |
131 |
132 |
133 |
134 | Code
135 |
136 |
137 | True
138 | True
139 | Resources.resx
140 |
141 |
142 | True
143 | Settings.settings
144 | True
145 |
146 |
147 | ResXFileCodeGenerator
148 | Resources.Designer.cs
149 |
150 |
151 |
152 |
153 | SettingsSingleFileGenerator
154 | Settings.Designer.cs
155 |
156 |
157 |
158 |
159 |
160 |
161 | {c0e94189-b243-4492-a113-6eb2de57bcc0}
162 | TorrentHardLinkHelper.Library
163 |
164 |
165 |
166 |
167 | False
168 | Microsoft .NET Framework 4 %28x86 and x64%29
169 | true
170 |
171 |
172 | False
173 | .NET Framework 3.5 SP1 Client Profile
174 | false
175 |
176 |
177 | False
178 | .NET Framework 3.5 SP1
179 | false
180 |
181 |
182 | False
183 | Windows Installer 4.5
184 | true
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
201 |
--------------------------------------------------------------------------------
/TorrentHardLinkHelper.Library/BEncoding/BEncodedDictionary.cs:
--------------------------------------------------------------------------------
1 | //
2 | // BEncodedDictionary.cs
3 | //
4 | // Authors:
5 | // Alan McGovern alan.mcgovern@gmail.com
6 | //
7 | // Copyright (C) 2006 Alan McGovern
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining
10 | // a copy of this software and associated documentation files (the
11 | // "Software"), to deal in the Software without restriction, including
12 | // without limitation the rights to use, copy, modify, merge, publish,
13 | // distribute, sublicense, and/or sell copies of the Software, and to
14 | // permit persons to whom the Software is furnished to do so, subject to
15 | // the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 |
30 | using System;
31 | using System.Collections.Generic;
32 | using System.IO;
33 |
34 | namespace TorrentHardLinkHelper.BEncoding
35 | {
36 | ///
37 | /// Class representing a BEncoded Dictionary
38 | ///
39 | public class BEncodedDictionary : BEncodedValue, IDictionary
40 | {
41 | #region Member Variables
42 |
43 | private SortedDictionary dictionary;
44 |
45 | #endregion
46 |
47 |
48 | #region Constructors
49 |
50 | ///
51 | /// Create a new BEncodedDictionary
52 | ///
53 | public BEncodedDictionary()
54 | {
55 | this.dictionary = new SortedDictionary();
56 | }
57 |
58 | #endregion
59 |
60 |
61 | #region Encode/Decode Methods
62 |
63 | ///
64 | /// Encodes the dictionary to a byte[]
65 | ///
66 | /// The buffer to encode the data to
67 | /// The offset to start writing the data to
68 | ///
69 | public override int Encode(byte[] buffer, int offset)
70 | {
71 | int written = 0;
72 |
73 | //Dictionaries start with 'd'
74 | buffer[offset] = (byte)'d';
75 | written++;
76 |
77 | foreach (KeyValuePair keypair in this)
78 | {
79 | written += keypair.Key.Encode(buffer, offset + written);
80 | written += keypair.Value.Encode(buffer, offset + written);
81 | }
82 |
83 | // Dictionaries end with 'e'
84 | buffer[offset + written] = (byte)'e';
85 | written++;
86 | return written;
87 | }
88 |
89 |
90 | ///
91 | ///
92 | ///
93 | ///
94 | internal override void DecodeInternal(RawReader reader)
95 | {
96 | DecodeInternal(reader, reader.StrictDecoding);
97 | }
98 |
99 | private void DecodeInternal(RawReader reader, bool strictDecoding)
100 | {
101 | BEncodedString key = null;
102 | BEncodedValue value = null;
103 | BEncodedString oldkey = null;
104 |
105 | if (reader.ReadByte() != 'd')
106 | throw new BEncodingException("Invalid data found. Aborting"); // Remove the leading 'd'
107 |
108 | while ((reader.PeekByte() != -1) && (reader.PeekByte() != 'e'))
109 | {
110 | key = (BEncodedString)BEncodedValue.Decode(reader); // keys have to be BEncoded strings
111 |
112 | if (oldkey != null && oldkey.CompareTo(key) > 0)
113 | if (strictDecoding)
114 | throw new BEncodingException(String.Format(
115 | "Illegal BEncodedDictionary. The attributes are not ordered correctly. Old key: {0}, New key: {1}",
116 | oldkey, key));
117 |
118 | oldkey = key;
119 | value = BEncodedValue.Decode(reader); // the value is a BEncoded value
120 | dictionary.Add(key, value);
121 | }
122 |
123 | if (reader.ReadByte() != 'e') // remove the trailing 'e'
124 | throw new BEncodingException("Invalid data found. Aborting");
125 | }
126 |
127 | public static BEncodedDictionary DecodeTorrent(byte[] bytes)
128 | {
129 | return DecodeTorrent(new MemoryStream(bytes));
130 | }
131 |
132 | public static BEncodedDictionary DecodeTorrent(Stream s)
133 | {
134 | return DecodeTorrent(new RawReader(s));
135 | }
136 |
137 |
138 | ///
139 | /// Special decoding method for torrent files - allows dictionary attributes to be out of order for the
140 | /// overall torrent file, but imposes strict rules on the info dictionary.
141 | ///
142 | ///
143 | public static BEncodedDictionary DecodeTorrent(RawReader reader)
144 | {
145 | BEncodedString key = null;
146 | BEncodedValue value = null;
147 | BEncodedDictionary torrent = new BEncodedDictionary();
148 | if (reader.ReadByte() != 'd')
149 | throw new BEncodingException("Invalid data found. Aborting"); // Remove the leading 'd'
150 |
151 | while ((reader.PeekByte() != -1) && (reader.PeekByte() != 'e'))
152 | {
153 | key = (BEncodedString)BEncodedValue.Decode(reader); // keys have to be BEncoded strings
154 |
155 | if (reader.PeekByte() == 'd')
156 | {
157 | value = new BEncodedDictionary();
158 | if (key.Text.ToLower().Equals("info"))
159 | ((BEncodedDictionary)value).DecodeInternal(reader, true);
160 | else
161 | ((BEncodedDictionary)value).DecodeInternal(reader, false);
162 | }
163 | else
164 | value = BEncodedValue.Decode(reader); // the value is a BEncoded value
165 |
166 | torrent.dictionary.Add(key, value);
167 | }
168 |
169 | if (reader.ReadByte() != 'e') // remove the trailing 'e'
170 | throw new BEncodingException("Invalid data found. Aborting");
171 |
172 | return torrent;
173 | }
174 |
175 | #endregion
176 |
177 |
178 | #region Helper Methods
179 |
180 | ///
181 | /// Returns the size of the dictionary in bytes using UTF8 encoding
182 | ///
183 | ///
184 | public override int LengthInBytes()
185 | {
186 | int length = 0;
187 | length += 1; // Dictionaries start with 'd'
188 |
189 | foreach (KeyValuePair keypair in this.dictionary)
190 | {
191 | length += keypair.Key.LengthInBytes();
192 | length += keypair.Value.LengthInBytes();
193 | }
194 | length += 1; // Dictionaries end with 'e'
195 | return length;
196 | }
197 |
198 | #endregion
199 |
200 |
201 | #region Overridden Methods
202 | public override bool Equals(object obj)
203 | {
204 | BEncodedValue val;
205 | BEncodedDictionary other = obj as BEncodedDictionary;
206 | if (other == null)
207 | return false;
208 |
209 | if (this.dictionary.Count != other.dictionary.Count)
210 | return false;
211 |
212 | foreach (KeyValuePair keypair in this.dictionary)
213 | {
214 | if (!other.TryGetValue(keypair.Key, out val))
215 | return false;
216 |
217 | if (!keypair.Value.Equals(val))
218 | return false;
219 | }
220 |
221 | return true;
222 | }
223 |
224 | public override int GetHashCode()
225 | {
226 | int result = 0;
227 | foreach (KeyValuePair keypair in dictionary)
228 | {
229 | result ^= keypair.Key.GetHashCode();
230 | result ^= keypair.Value.GetHashCode();
231 | }
232 |
233 | return result;
234 | }
235 |
236 | public override string ToString()
237 | {
238 | return System.Text.Encoding.UTF8.GetString(Encode());
239 | }
240 | #endregion
241 |
242 |
243 | #region IDictionary and IList methods
244 | public void Add(BEncodedString key, BEncodedValue value)
245 | {
246 | this.dictionary.Add(key, value);
247 | }
248 |
249 | public void Add(KeyValuePair item)
250 | {
251 | this.dictionary.Add(item.Key, item.Value);
252 | }
253 | public void Clear()
254 | {
255 | this.dictionary.Clear();
256 | }
257 |
258 | public bool Contains(KeyValuePair item)
259 | {
260 | if (!this.dictionary.ContainsKey(item.Key))
261 | return false;
262 |
263 | return this.dictionary[item.Key].Equals(item.Value);
264 | }
265 |
266 | public bool ContainsKey(BEncodedString key)
267 | {
268 | return this.dictionary.ContainsKey(key);
269 | }
270 |
271 | public void CopyTo(KeyValuePair[] array, int arrayIndex)
272 | {
273 | this.dictionary.CopyTo(array, arrayIndex);
274 | }
275 |
276 | public int Count
277 | {
278 | get { return this.dictionary.Count; }
279 | }
280 |
281 | //public int IndexOf(KeyValuePair item)
282 | //{
283 | // return this.dictionary.IndexOf(item);
284 | //}
285 |
286 | //public void Insert(int index, KeyValuePair item)
287 | //{
288 | // this.dictionary.Insert(index, item);
289 | //}
290 |
291 | public bool IsReadOnly
292 | {
293 | get { return false; }
294 | }
295 |
296 | public bool Remove(BEncodedString key)
297 | {
298 | return this.dictionary.Remove(key);
299 | }
300 |
301 | public bool Remove(KeyValuePair item)
302 | {
303 | return this.dictionary.Remove(item.Key);
304 | }
305 |
306 | //public void RemoveAt(int index)
307 | //{
308 | // this.dictionary.RemoveAt(index);
309 | //}
310 |
311 | public bool TryGetValue(BEncodedString key, out BEncodedValue value)
312 | {
313 | return this.dictionary.TryGetValue(key, out value);
314 | }
315 |
316 | public BEncodedValue this[BEncodedString key]
317 | {
318 | get { return this.dictionary[key]; }
319 | set { this.dictionary[key] = value; }
320 | }
321 |
322 | //public KeyValuePair this[int index]
323 | //{
324 | // get { return this.dictionary[index]; }
325 | // set { this.dictionary[index] = value; }
326 | //}
327 |
328 | public ICollection Keys
329 | {
330 | get { return this.dictionary.Keys; }
331 | }
332 |
333 | public ICollection Values
334 | {
335 | get { return this.dictionary.Values; }
336 | }
337 |
338 | public IEnumerator> GetEnumerator()
339 | {
340 | return this.dictionary.GetEnumerator();
341 | }
342 |
343 | System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
344 | {
345 | return this.dictionary.GetEnumerator();
346 | }
347 | #endregion
348 | }
349 | }
--------------------------------------------------------------------------------