Password protected archives support

This commit is contained in:
chudov
2008-11-12 05:45:48 +00:00
parent bb1648393e
commit c64b097c07
10 changed files with 584 additions and 153 deletions

View File

@@ -28,10 +28,11 @@ namespace ArCueDotNet
StringWriter sw = new StringWriter();
try
{
CUESheet cueSheet = new CUESheet(pathIn, config);
CUESheet cueSheet = new CUESheet(config);
cueSheet.Open(pathIn);
cueSheet.GenerateFilenames(OutputAudioFormat.NoAudio, pathIn);
cueSheet.AccurateRip = true;
cueSheet.WriteAudioFiles(Path.GetDirectoryName(pathIn), CUEStyle.SingleFile, new SetStatus(ArCueSetStatus));
cueSheet.WriteAudioFiles(Path.GetDirectoryName(pathIn), CUEStyle.SingleFile);
cueSheet.GenerateAccurateRipLog(sw);
}
catch (Exception ex)
@@ -41,8 +42,5 @@ namespace ArCueDotNet
sw.Close();
Console.Write(sw.ToString());
}
public static void ArCueSetStatus(string status, uint percentTrack, double percentDisk, string input, string output)
{
}
}
}

View File

@@ -96,6 +96,12 @@
<Compile Include="frmFilenameCorrector.Designer.cs">
<DependentUpon>frmFilenameCorrector.cs</DependentUpon>
</Compile>
<Compile Include="frmPassword.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="frmPassword.Designer.cs">
<DependentUpon>frmPassword.cs</DependentUpon>
</Compile>
<Compile Include="frmReport.cs">
<SubType>Form</SubType>
</Compile>
@@ -140,6 +146,10 @@
<SubType>Designer</SubType>
<DependentUpon>frmFilenameCorrector.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="frmPassword.resx">
<SubType>Designer</SubType>
<DependentUpon>frmPassword.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="frmReport.resx">
<SubType>Designer</SubType>
<DependentUpon>frmReport.cs</DependentUpon>

28
CUETools/Settings.cs Normal file
View File

@@ -0,0 +1,28 @@
namespace JDP.Properties {
// This class allows you to handle specific events on the settings class:
// The SettingChanging event is raised before a setting's value is changed.
// The PropertyChanged event is raised after a setting's value is changed.
// The SettingsLoaded event is raised after the setting values are loaded.
// The SettingsSaving event is raised before the setting values are saved.
internal sealed partial class Settings {
public Settings() {
// // To add event handlers for saving and changing settings, uncomment the lines below:
//
// this.SettingChanging += this.SettingChangingEventHandler;
//
// this.SettingsSaving += this.SettingsSavingEventHandler;
//
}
private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) {
// Add code to handle the SettingChangingEvent event here.
}
private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) {
// Add code to handle the SettingsSaving event here.
}
}
}

View File

@@ -57,39 +57,55 @@ namespace JDP
DateTime _startedAt;
List<string> _batchPaths;
public string ShortenString(string input, int max)
public static string ShortenString(string input, int max)
{
if (input.Length < max)
return input;
return "..." + input.Substring(input.Length - max);
}
public void SetStatus(string status, uint percentTrack, double percentDisk, string input, string output)
public void SetStatus(object sender, CUEToolsProgressEventArgs e)
{
this.BeginInvoke((MethodInvoker)delegate()
{
if (percentDisk == 0)
if (e.percentDisk == 0)
{
_startedAt = DateTime.Now;
Text = e.status;
}
else if (percentDisk > 0.02)
else if (e.percentDisk > 0.02)
{
TimeSpan span = DateTime.Now - _startedAt;
TimeSpan eta = new TimeSpan ((long) (span.Ticks/percentDisk));
Text = String.Format("{0}, ETA {1}:{2:00}.", status, (int)eta.TotalMinutes, eta.Seconds);
TimeSpan eta = new TimeSpan ((long) (span.Ticks/e.percentDisk));
Text = String.Format("{0}, ETA {1}:{2:00}.", e.status, (int)eta.TotalMinutes, eta.Seconds);
} else
Text = status;
progressBar1.Value = (int)percentTrack;
progressBar2.Value = (int)(percentDisk*100);
string inputSuffix = output != null ? "=>" : "";
if (input == null)
Text = e.status;
progressBar1.Value = (int)e.percentTrack;
progressBar2.Value = (int)(e.percentDisk*100);
string inputSuffix = e.output != null ? "=>" : "";
if (e.input == null)
txtInputFile.Text = inputSuffix;
else
txtInputFile.Text = ShortenString(input, 120) + " " + inputSuffix;
if (output == null)
txtInputFile.Text = ShortenString(e.input, 120) + " " + inputSuffix;
if (e.output == null)
txtOutputFile.Text = "";
else
txtOutputFile.Text = ShortenString(output, 120);
txtOutputFile.Text = ShortenString(e.output, 120);
});
}
private void PasswordRequired(object sender, ArchivePasswordRequiredEventArgs e)
{
this.Invoke((MethodInvoker)delegate()
{
frmPassword dlg = new frmPassword();
if (dlg.ShowDialog(this) == DialogResult.OK)
{
e.Password = dlg.txtPassword.Text;
e.ContinueOperation = true;
}
else
e.ContinueOperation = false;
});
}
@@ -99,7 +115,59 @@ namespace JDP
try
{
cueSheet.WriteAudioFiles(Path.GetDirectoryName(pathOut), _cueStyle, new SetStatus(this.SetStatus));
_startedAt = DateTime.Now;
if (_batchPaths.Count != 0)
pathIn = _batchPaths[0];
pathIn = Path.GetFullPath(pathIn);
textBox1.Text += "Processing " + pathIn + ":\r\n";
textBox1.Select(0, 0);
string cueName;
if (!File.Exists(pathIn))
{
if (!Directory.Exists(pathIn))
throw new Exception("Input CUE Sheet not found.");
if (!pathIn.EndsWith(new string(Path.DirectorySeparatorChar, 1)))
pathIn = pathIn + Path.DirectorySeparatorChar;
cueName = Path.GetFileNameWithoutExtension(Path.GetDirectoryName(pathIn)) + ".cue";
}
else
cueName = Path.GetFileNameWithoutExtension(pathIn) + ".cue";
bool outputAudio = _accurateOffset || !_accurateRip;
cueSheet.Open(pathIn);
if (outputAudio)
{
bool pathFound = false;
for (int i = 0; i < 20; i++)
{
string outDir = Path.Combine(Path.GetDirectoryName(pathIn), "CUEToolsOutput" + (i > 0 ? String.Format("({0})", i) : ""));
if (!Directory.Exists(outDir))
{
Directory.CreateDirectory(outDir);
pathOut = Path.Combine(outDir, cueName);
pathFound = true;
break;
}
}
if (!pathFound)
throw new Exception("Could not create a folder.");
}
else
pathOut = Path.Combine(Path.GetDirectoryName(pathIn), cueName);
cueSheet.GenerateFilenames(_audioFormat, pathOut);
if (outputAudio)
{
if (_cueStyle == CUEStyle.SingleFileWithCUE)
cueSheet.SingleFilename = Path.ChangeExtension(Path.GetFileName(pathOut), General.FormatExtension(_audioFormat));
}
cueSheet.UsePregapForFirstTrackInSingleFile = false;
cueSheet.AccurateRip = _accurateRip;
cueSheet.AccurateOffset = _accurateOffset;
cueSheet.WriteAudioFiles(Path.GetDirectoryName(pathOut), _cueStyle);
this.Invoke((MethodInvoker)delegate()
{
if (_batchPaths.Count == 0)
@@ -138,8 +206,10 @@ namespace JDP
{
Text = "Error: " + ex.Message;
textBox1.Show();
textBox1.Text += "Error: " + ex.Message + "\r\n";
textBox1.Text += "----------------------------------------------------------\r\n";
textBox1.Text += "Error";
for (Exception e = ex; e != null; e = e.InnerException)
textBox1.Text += ": " + e.Message;
textBox1.Text += "\r\n----------------------------------------------------------\r\n";
textBox1.Select(0, 0);
});
}
@@ -164,62 +234,11 @@ namespace JDP
public void StartConvert()
{
CUESheet cueSheet;
try
{
_startedAt = DateTime.Now;
_workThread = null;
if (_batchPaths.Count != 0)
pathIn = _batchPaths[0];
pathIn = Path.GetFullPath(pathIn);
textBox1.Text += "Processing " + pathIn + ":\r\n";
textBox1.Select (0,0);
string cueName;
if (!File.Exists(pathIn))
{
if (!Directory.Exists (pathIn))
throw new Exception("Input CUE Sheet not found.");
if (!pathIn.EndsWith(new string(Path.DirectorySeparatorChar, 1)))
pathIn = pathIn + Path.DirectorySeparatorChar;
cueName = Path.GetFileNameWithoutExtension(Path.GetDirectoryName(pathIn)) + ".cue";
} else
cueName = Path.GetFileNameWithoutExtension(pathIn) + ".cue";
bool outputAudio = _accurateOffset || !_accurateRip;
cueSheet = new CUESheet(pathIn, _config);
if (outputAudio)
{
bool pathFound = false;
for (int i = 0; i < 20; i++)
{
string outDir = Path.Combine(Path.GetDirectoryName (pathIn), "CUEToolsOutput" + (i > 0? String.Format("({0})",i) : ""));
if (!Directory.Exists(outDir))
{
Directory.CreateDirectory(outDir);
pathOut = Path.Combine(outDir, cueName);
pathFound = true;
break;
}
}
if (!pathFound)
throw new Exception("Could not create a folder.");
} else
pathOut = Path.Combine(Path.GetDirectoryName(pathIn), cueName);
cueSheet.GenerateFilenames(_audioFormat, pathOut);
if (outputAudio)
{
if (_cueStyle == CUEStyle.SingleFileWithCUE)
cueSheet.SingleFilename = Path.ChangeExtension(Path.GetFileName (pathOut), General.FormatExtension (_audioFormat));
}
cueSheet.UsePregapForFirstTrackInSingleFile = false;
cueSheet.AccurateRip = _accurateRip;
cueSheet.AccurateOffset = _accurateOffset;
CUESheet cueSheet = new CUESheet(_config);
cueSheet.PasswordRequired += new ArchivePasswordRequiredHandler(PasswordRequired);
cueSheet.CUEToolsProgress += new CUEToolsProgressHandler(SetStatus);
_workThread = new Thread(WriteAudioFilesThread);
_workClass = cueSheet;
@@ -235,16 +254,6 @@ namespace JDP
textBox1.Text += "----------------------------------------------------------\r\n";
textBox1.Select(0, 0);
}
if ((_workThread == null) && (_batchPaths.Count != 0))
{
_batchPaths.RemoveAt(0);
if (_batchPaths.Count == 0)
{
Text = "All done.";
}
else
StartConvert();
}
}
private void frmBatch_Load(object sender, EventArgs e)

View File

@@ -240,10 +240,11 @@ namespace JDP {
}
}
cueSheet = new CUESheet(pathIn, _config);
cueSheet = new CUESheet(_config);
cueSheet.PasswordRequired += new ArchivePasswordRequiredHandler(PasswordRequired);
cueSheet.WriteOffset = _writeOffset;
cueSheet.Open(pathIn);
UpdateOutputPath(cueSheet.Artist != "" ? cueSheet.Artist : "Unknown Artist", cueSheet.Title != "" ? cueSheet.Title : "Unknown Title");
pathOut = txtOutputPath.Text;
cueSheet.GenerateFilenames(SelectedOutputAudioFormat, pathOut);
@@ -326,6 +327,22 @@ namespace JDP {
}
}
private void PasswordRequired(object sender, ArchivePasswordRequiredEventArgs e)
{
//if (this.InvokeRequired)
// this.Invoke(this.PasswordRequired, sender, e);
//this.Invoke((MethodInvoker)delegate()
//{
frmPassword dlg = new frmPassword();
if (dlg.ShowDialog() == DialogResult.OK)
{
e.Password = dlg.txtPassword.Text;
e.ContinueOperation = true;
} else
e.ContinueOperation = false;
//});
}
private void WriteAudioFilesThread(object o) {
object[] p = (object[])o;
@@ -334,7 +351,8 @@ namespace JDP {
CUEStyle cueStyle = (CUEStyle)p[2];
try {
cueSheet.WriteAudioFiles(outDir, cueStyle, new SetStatus(this.SetStatus));
cueSheet.CUEToolsProgress += new CUEToolsProgressHandler(SetStatus);
cueSheet.WriteAudioFiles(outDir, cueStyle);
this.Invoke((MethodInvoker)delegate() {
if (_batchPaths.Count == 0)
{
@@ -390,11 +408,12 @@ namespace JDP {
}
}
public void SetStatus(string status, uint percentTrack, double percentDisk, string input, string output) {
public void SetStatus(object sender, CUEToolsProgressEventArgs e)
{
this.BeginInvoke((MethodInvoker)delegate() {
toolStripStatusLabel1.Text = status;
toolStripProgressBar1.Value = (int)percentTrack;
toolStripProgressBar2.Value = (int)(percentDisk*100);
toolStripStatusLabel1.Text = e.status;
toolStripProgressBar1.Value = (int)e.percentTrack;
toolStripProgressBar2.Value = (int)(e.percentDisk*100);
});
}

72
CUETools/frmPassword.Designer.cs generated Normal file
View File

@@ -0,0 +1,72 @@
namespace JDP
{
partial class frmPassword
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(frmPassword));
this.txtPassword = new System.Windows.Forms.TextBox();
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// txtPassword
//
resources.ApplyResources(this.txtPassword, "txtPassword");
this.txtPassword.Name = "txtPassword";
this.txtPassword.UseSystemPasswordChar = true;
//
// button1
//
this.button1.DialogResult = System.Windows.Forms.DialogResult.OK;
resources.ApplyResources(this.button1, "button1");
this.button1.Name = "button1";
this.button1.UseVisualStyleBackColor = true;
//
// frmPassword
//
this.AcceptButton = this.button1;
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.button1);
this.Controls.Add(this.txtPassword);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "frmPassword";
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.TopMost = true;
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button button1;
public System.Windows.Forms.TextBox txtPassword;
}
}

18
CUETools/frmPassword.cs Normal file
View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace JDP
{
public partial class frmPassword : Form
{
public frmPassword()
{
InitializeComponent();
}
}
}

195
CUETools/frmPassword.resx Normal file
View File

@@ -0,0 +1,195 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="txtPassword.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Left, Right</value>
</data>
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="txtPassword.Location" type="System.Drawing.Point, System.Drawing">
<value>12, 12</value>
</data>
<assembly alias="mscorlib" name="mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="txtPassword.MaxLength" type="System.Int32, mscorlib">
<value>256</value>
</data>
<data name="txtPassword.Size" type="System.Drawing.Size, System.Drawing">
<value>350, 20</value>
</data>
<data name="txtPassword.TabIndex" type="System.Int32, mscorlib">
<value>0</value>
</data>
<data name="&gt;&gt;txtPassword.Name" xml:space="preserve">
<value>txtPassword</value>
</data>
<data name="&gt;&gt;txtPassword.Type" xml:space="preserve">
<value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;txtPassword.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;txtPassword.ZOrder" xml:space="preserve">
<value>1</value>
</data>
<data name="button1.Location" type="System.Drawing.Point, System.Drawing">
<value>304, 40</value>
</data>
<data name="button1.Size" type="System.Drawing.Size, System.Drawing">
<value>58, 23</value>
</data>
<data name="button1.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
</data>
<data name="button1.Text" xml:space="preserve">
<value>Ok</value>
</data>
<data name="&gt;&gt;button1.Name" xml:space="preserve">
<value>button1</value>
</data>
<data name="&gt;&gt;button1.Type" xml:space="preserve">
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;button1.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;button1.ZOrder" xml:space="preserve">
<value>0</value>
</data>
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
<value>6, 13</value>
</data>
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
<value>374, 75</value>
</data>
<data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms">
<value>CenterParent</value>
</data>
<data name="$this.Text" xml:space="preserve">
<value>Password required</value>
</data>
<data name="&gt;&gt;$this.Name" xml:space="preserve">
<value>frmPassword</value>
</data>
<data name="&gt;&gt;$this.Type" xml:space="preserve">
<value>System.Windows.Forms.Form, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>

View File

@@ -194,8 +194,6 @@ namespace CUEToolsLib
}
}
public delegate void SetStatus(string status, uint percentTrack, double percentDisk, string input, string output);
public enum CUEStyle {
SingleFileWithCUE,
SingleFile,
@@ -396,6 +394,24 @@ namespace CUEToolsLib
}
}
public class CUEToolsProgressEventArgs
{
public string status = string.Empty;
public uint percentTrack = 0;
public double percentDisk = 0.0;
public string input = string.Empty;
public string output = string.Empty;
}
public class ArchivePasswordRequiredEventArgs
{
public string Password = string.Empty;
public bool ContinueOperation = true;
}
public delegate void CUEToolsProgressHandler(object sender, CUEToolsProgressEventArgs e);
public delegate void ArchivePasswordRequiredHandler(object sender, ArchivePasswordRequiredEventArgs e);
public class CUESheet {
private bool _stop, _pause;
private List<CUELine> _attributes;
@@ -423,35 +439,23 @@ namespace CUEToolsLib
string _cddbDiscIdTag;
private bool _isArchive;
private string _archivePath;
private string _archivePassword;
private CUEToolsProgressEventArgs _progress;
public CUESheet(string pathIn, CUEConfig config)
public event ArchivePasswordRequiredHandler PasswordRequired;
public event CUEToolsProgressHandler CUEToolsProgress;
public CUESheet(CUEConfig config)
{
_config = config;
hdcdDecoder = null;
if (_config.detectHDCD)
{
try { hdcdDecoder = new HDCDDotNet.HDCDDotNet(2, 44100, _config.decodeHDCD); }
catch { }
}
string cueDir, lineStr, command, pathAudio, fileType;
CUELine line;
TrackInfo trackInfo;
int tempTimeLength, timeRelativeToFileStart, absoluteFileStartTime;
int fileTimeLengthSamples, fileTimeLengthFrames, i, trackNumber;
bool seenFirstFileIndex, seenDataTrack;
List<IndexInfo> indexes;
IndexInfo indexInfo;
SourceInfo sourceInfo;
NameValueCollection _trackTags = null;
_stop = false;
_pause = false;
_progress = new CUEToolsProgressEventArgs();
_attributes = new List<CUELine>();
_tracks = new List<TrackInfo>();
_sources = new List<SourceInfo>();
_sourcePaths = new List<string>();
_albumTags = new NameValueCollection();
_stop = false;
_pause = false;
_cuePath = null;
_paddedToFrame = false;
_truncated4608 = false;
@@ -461,20 +465,37 @@ namespace CUEToolsLib
_appliedWriteOffset = false;
_dataTrackLength = null;
_minDataTrackLength = null;
_albumTags = new NameValueCollection();
hdcdDecoder = null;
_hasEmbeddedCUESheet = false;
_isArchive = false;
accDisks = new List<AccDisk>();
}
public void Open(string pathIn)
{
if (_config.detectHDCD)
{
try { hdcdDecoder = new HDCDDotNet.HDCDDotNet(2, 44100, _config.decodeHDCD); }
catch { }
}
string cueDir, lineStr, command, pathAudio = null, fileType;
CUELine line;
TrackInfo trackInfo;
int tempTimeLength, timeRelativeToFileStart, absoluteFileStartTime;
int fileTimeLengthSamples, fileTimeLengthFrames, i, trackNumber;
bool seenFirstFileIndex = false, seenDataTrack = false;
List<IndexInfo> indexes = new List<IndexInfo>();
IndexInfo indexInfo;
SourceInfo sourceInfo;
NameValueCollection _trackTags = null;
cueDir = Path.GetDirectoryName(pathIn);
pathAudio = null;
indexes = new List<IndexInfo>();
trackInfo = null;
absoluteFileStartTime = 0;
fileTimeLengthSamples = 0;
fileTimeLengthFrames = 0;
trackNumber = 0;
seenFirstFileIndex = false;
seenDataTrack = false;
accDisks = new List<AccDisk>();
_hasEmbeddedCUESheet = false;
_isArchive = false;
TextReader sr;
@@ -494,6 +515,7 @@ namespace CUEToolsLib
else if (Path.GetExtension(pathIn).ToLower() == ".rar")
{
Unrar _unrar = new Unrar();
_unrar.PasswordRequired += new PasswordRequiredHandler(unrar_PasswordRequired);
string cueName = null, cueText = null;
_unrar.Open(pathIn, Unrar.OpenMode.List);
while (_unrar.ReadHeader())
@@ -508,15 +530,16 @@ namespace CUEToolsLib
}
_unrar.Close();
if (cueName != null)
try
{
RarStream rarStream = new RarStream(pathIn, cueName);
rarStream.PasswordRequired += new PasswordRequiredHandler(unrar_PasswordRequired);
StreamReader cueReader = new StreamReader(rarStream, CUESheet.Encoding);
cueText = cueReader.ReadToEnd();
cueReader.Close();
rarStream.Close();
if (cueText == "")
throw new Exception("Empty cue sheet.");
}
catch { }
if (cueText == null)
throw new Exception("Input archive doesn't contain a cue sheet.");
sr = new StringReader(cueText);
@@ -864,6 +887,49 @@ namespace CUEToolsLib
}
}
private void ShowProgress(string status, uint percentTrack, double percentDisk, string input, string output)
{
if (this.CUEToolsProgress == null)
return;
_progress.status = status;
_progress.percentTrack = percentTrack;
_progress.percentDisk = percentDisk;
_progress.input = input;
_progress.output = output;
this.CUEToolsProgress(this, _progress);
}
#if !MONO
private void unrar_ExtractionProgress(object sender, ExtractionProgressEventArgs e)
{
_progress.percentTrack = (uint) Math.Round(e.PercentComplete);
this.CUEToolsProgress(this, _progress);
}
private void unrar_PasswordRequired(object sender, PasswordRequiredEventArgs e)
{
if (_archivePassword != null)
{
e.ContinueOperation = true;
e.Password = _archivePassword;
return;
}
if (this.PasswordRequired != null)
{
ArchivePasswordRequiredEventArgs e1 = new ArchivePasswordRequiredEventArgs();
this.PasswordRequired(this, e1);
if (e1.ContinueOperation && e1.Password != "")
{
_archivePassword = e1.Password;
e.ContinueOperation = true;
e.Password = e1.Password;
return;
}
}
throw new IOException("Password is required for extraction.");
}
#endif
public string GetCommonTag(string tagName)
{
if (_hasEmbeddedCUESheet || _hasSingleFilename)
@@ -1013,10 +1079,13 @@ namespace CUEToolsLib
{
IAudioSource audioSource;
ShowProgress("Opening source file...", 0, 0.0, path, null);
#if !MONO
if (_isArchive)
{
RarStream IO = new RarStream(_archivePath, path);
IO.PasswordRequired += new PasswordRequiredHandler(unrar_PasswordRequired);
IO.ExtractionProgress += new ExtractionProgressHandler(unrar_ExtractionProgress);
audioSource = AudioReadWrite.GetAudioSource(path, IO);
} else
#endif
@@ -1618,7 +1687,7 @@ namespace CUEToolsLib
outTracksMatch = bestTracksMatch;
}
public void WriteAudioFiles(string dir, CUEStyle style, SetStatus statusDel) {
public void WriteAudioFiles(string dir, CUEStyle style) {
string[] destPaths;
int[] destLengths;
bool htoaToFile = ((style == CUEStyle.GapsAppended) && _config.preserveHTOA &&
@@ -1656,7 +1725,7 @@ namespace CUEToolsLib
bool SkipOutput = false;
if (_accurateRip) {
statusDel((string)"Contacting AccurateRip database...", 0, 0, null, null);
ShowProgress((string)"Contacting AccurateRip database...", 0, 0, null, null);
if (!_dataTrackLength.HasValue && _minDataTrackLength.HasValue && _accurateRipId == _accurateRipIdActual && _config.bruteForceDTL)
{
uint minDTL = _minDataTrackLength.Value;
@@ -1667,13 +1736,13 @@ namespace CUEToolsLib
ContactAccurateRip();
if (accResult != HttpStatusCode.NotFound)
break;
statusDel((string)"Contacting AccurateRip database...", 0, (dtl-minDTL)/75.0, null, null);
ShowProgress((string)"Contacting AccurateRip database...", 0, (dtl - minDTL) / 75.0, null, null);
lock (this) {
if (_stop)
throw new StopException();
if (_pause)
{
statusDel("Paused...", 0, 0, null, null);
ShowProgress("Paused...", 0, 0, null, null);
Monitor.Wait(this);
}
else
@@ -1714,7 +1783,7 @@ namespace CUEToolsLib
else if (_accurateOffset)
{
_writeOffset = 0;
WriteAudioFilesPass(dir, style, statusDel, destPaths, destLengths, htoaToFile, true);
WriteAudioFilesPass(dir, style, destPaths, destLengths, htoaToFile, true);
uint tracksMatch;
int bestOffset;
@@ -1749,12 +1818,12 @@ namespace CUEToolsLib
if (style != CUEStyle.SingleFileWithCUE && style != CUEStyle.SingleFile && _config.createM3U)
WriteM3U(Path.ChangeExtension(_cuePath, ".m3u"), style);
}
WriteAudioFilesPass(dir, style, statusDel, destPaths, destLengths, htoaToFile, verifyOnly);
WriteAudioFilesPass(dir, style, destPaths, destLengths, htoaToFile, verifyOnly);
}
if (_accurateRip)
{
statusDel((string)"Generating AccurateRip report...", 0, 0, null, null);
ShowProgress((string)"Generating AccurateRip report...", 0, 0, null, null);
if (!_accurateOffset && _config.writeArTagsOnVerify && _writeOffset == 0 && !_isArchive)
{
uint tracksMatch;
@@ -1930,7 +1999,7 @@ namespace CUEToolsLib
audioDest.SetTags(destTags);
}
public void WriteAudioFilesPass(string dir, CUEStyle style, SetStatus statusDel, string[] destPaths, int[] destLengths, bool htoaToFile, bool noOutput)
public void WriteAudioFilesPass(string dir, CUEStyle style, string[] destPaths, int[] destLengths, bool htoaToFile, bool noOutput)
{
const int buffLen = 16384;
int iTrack, iIndex;
@@ -2024,7 +2093,7 @@ namespace CUEToolsLib
diskLength += _tracks[iTrack].IndexLengths[iIndex] * 588;
statusDel(String.Format("{2} track {0:00} ({1:00}%)...", 0, 0, noOutput ? "Verifying" : "Writing"), 0, 0.0, null, null);
ShowProgress(String.Format("{2} track {0:00} ({1:00}%)...", 0, 0, noOutput ? "Verifying" : "Writing"), 0, 0.0, null, null);
for (iTrack = 0; iTrack < TrackCount; iTrack++) {
track = _tracks[iTrack];
@@ -2111,7 +2180,7 @@ namespace CUEToolsLib
trackPercent = (uint)(currentOffset / 0.01 / trackLength);
double diskPercent = ((float)diskOffset) / diskLength;
if (trackPercent != lastTrackPercent)
statusDel(String.Format("{2} track {0:00} ({1:00}%)...", iIndex > 0 ? iTrack + 1 : iTrack, trackPercent,
ShowProgress(String.Format("{2} track {0:00} ({1:00}%)...", iIndex > 0 ? iTrack + 1 : iTrack, trackPercent,
noOutput ? "Verifying" : "Writing"), trackPercent, diskPercent,
audioSource.Path, discardOutput ? null : audioDest.Path);
lastTrackPercent = trackPercent;
@@ -2176,7 +2245,7 @@ namespace CUEToolsLib
}
if (_pause)
{
statusDel ("Paused...", 0, 0, null, null);
ShowProgress("Paused...", 0, 0, null, null);
Monitor.Wait(this);
}
}
@@ -2413,6 +2482,7 @@ namespace CUEToolsLib
if (_isArchive)
{
RarStream IO = new RarStream(_archivePath, sourceInfo.Path);
IO.PasswordRequired += new PasswordRequiredHandler(unrar_PasswordRequired);
audioSource = AudioReadWrite.GetAudioSource(sourceInfo.Path, IO);
}
else

View File

@@ -25,12 +25,7 @@ namespace UnRarDotNet
_pos = 0;
_path = path;
_fileName = fileName;
_unrar.PasswordRequired += new PasswordRequiredHandler(unrar_PasswordRequired);
_unrar.DataAvailable += new DataAvailableHandler(unrar_DataAvailable);
_workThread = new Thread(Decompress);
_workThread.Priority = ThreadPriority.BelowNormal;
_workThread.IsBackground = true;
_workThread.Start(null);
_workThread = null;
}
public override bool CanRead
{
@@ -48,11 +43,14 @@ namespace UnRarDotNet
{
get
{
Go();
lock (this)
{
while (_size == null && !_close)
Monitor.Wait(this);
}
if (_ex != null)
throw _ex;
if (_size == null)
throw new NotSupportedException();
return _size.Value;
@@ -93,12 +91,15 @@ namespace UnRarDotNet
public override int Read(byte[] array, int offset, int count)
{
int total = 0;
Go();
while (count > 0)
{
lock (this)
{
while (_buffer == null && !_eof)
while (_buffer == null && !_eof && !_close)
Monitor.Wait(this);
if (_close)
throw new IOException("Decompression failed", _ex);
if (_buffer == null)
return total;
if (_seek_to != null)
@@ -139,6 +140,7 @@ namespace UnRarDotNet
}
public override long Seek(long offset, SeekOrigin origin)
{
Go();
lock (this)
{
while (_size == null && !_close)
@@ -181,22 +183,28 @@ namespace UnRarDotNet
{
throw new NotSupportedException();
}
public event PasswordRequiredHandler PasswordRequired;
public event ExtractionProgressHandler ExtractionProgress;
private Unrar _unrar;
private string _fileName;
private Thread _workThread;
private bool _close, _rewind, _eof;
private byte[] _buffer;
private Exception _ex;
int _offset, _length;
long? _size;
long? _seek_to;
long _pos;
string _path;
private void unrar_PasswordRequired(object sender, PasswordRequiredEventArgs e)
private void Go()
{
e.Password = "PARS";
e.ContinueOperation = true;
if (_workThread != null) return;
_workThread = new Thread(Decompress);
_workThread.Priority = ThreadPriority.BelowNormal;
_workThread.IsBackground = true;
_workThread.Start(null);
}
private void unrar_DataAvailable(object sender, DataAvailableEventArgs e)
@@ -227,7 +235,10 @@ namespace UnRarDotNet
private void Decompress(object o)
{
//try
_unrar.DataAvailable += new DataAvailableHandler(unrar_DataAvailable);
_unrar.PasswordRequired += PasswordRequired;
_unrar.ExtractionProgress += ExtractionProgress;
try
{
do
{
@@ -264,9 +275,10 @@ namespace UnRarDotNet
}
} while (true);
}
//catch (StopExtractionException)
//{
//}
catch (Exception ex)
{
_ex = ex;
}
lock (this)
{
_close = true;