diff --git a/Bwg.Scsi/Command.cs b/Bwg.Scsi/Command.cs
index a2556d2..4126724 100644
--- a/Bwg.Scsi/Command.cs
+++ b/Bwg.Scsi/Command.cs
@@ -29,7 +29,7 @@ using System.Diagnostics;
namespace Bwg.Scsi
{
- public class Command : IDisposable
+ class Command : IDisposable
{
[DllImport("ntdll.dll")]
internal static extern void RtlZeroMemory(IntPtr dest, int size);
diff --git a/Bwg.Scsi/Defs.cs b/Bwg.Scsi/Defs.cs
index b5965f1..93471e7 100644
--- a/Bwg.Scsi/Defs.cs
+++ b/Bwg.Scsi/Defs.cs
@@ -23,7 +23,7 @@
namespace Bwg.Scsi
{
- public enum ScsiCommandCode
+ enum ScsiCommandCode
{
TestUnitReady = 0x00,
RequestSense = 0x03,
diff --git a/Bwg.Scsi/Device.cs b/Bwg.Scsi/Device.cs
index 64320c7..2ee0b38 100644
--- a/Bwg.Scsi/Device.cs
+++ b/Bwg.Scsi/Device.cs
@@ -939,7 +939,7 @@ namespace Bwg.Scsi
}
#endregion
- public CommandStatus SendCommand(Command cmd)
+ private CommandStatus SendCommand(Command cmd)
{
return (m_ossize == 32) ? SendCommand32(cmd) : SendCommand64(cmd);
}
@@ -2131,29 +2131,51 @@ namespace Bwg.Scsi
return CommandStatus.Success;
}
+ ///
+ ///
+ ///
public enum SubChannelMode
{
+ ///
None,
- QOnly, /// + 16 bytes
- RWMode /// + 96 bytes
+ /// + 16 bytes
+ QOnly,
+ /// + 96 bytes
+ RWMode
};
+ ///
+ ///
+ ///
public enum C2ErrorMode
{
+ ///
None,
- Mode294, /// +294 bytes
- Mode296, /// +296 bytes
+ /// +294 bytes
+ Mode294,
+ /// +296 bytes
+ Mode296,
};
+ ///
+ ///
+ ///
public enum MainChannelSelection
{
+ ///
+ ///
+ ///
UserData,
+ ///
+ ///
+ ///
F8h
};
///
///
///
+ /// main channel mode
/// subchannel mode
/// C2 errors report mode
/// expected sector type
@@ -2309,6 +2331,7 @@ namespace Bwg.Scsi
///
///
/// the subchannel mode
+ /// timeout (in seconds)
///
public CommandStatus ReadSubChannel(byte mode, uint sector, uint length, ref byte[] data, int timeout)
{
diff --git a/CUERipper/CUERipper.csproj b/CUERipper/CUERipper.csproj
index 78b75f8..cd4e8fc 100644
--- a/CUERipper/CUERipper.csproj
+++ b/CUERipper/CUERipper.csproj
@@ -73,6 +73,7 @@
+
@@ -111,6 +112,7 @@
True
Resources.resx
+
SettingsSingleFileGenerator
@@ -143,6 +145,10 @@
{8CF07381-BEA2-4AFC-B3DD-9B2F21C65A3A}
CUETools.Ripper.SCSI
+
+ {5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}
+ Freedb
+
{74C2036B-2C9B-4FC8-B7BD-AE81A8DCE533}
MusicBrainz
diff --git a/CUERipper/Properties/Settings.Designer.cs b/CUERipper/Properties/Settings.Designer.cs
index e4cc54b..dfc388c 100644
--- a/CUERipper/Properties/Settings.Designer.cs
+++ b/CUERipper/Properties/Settings.Designer.cs
@@ -8,23 +8,31 @@
//
//------------------------------------------------------------------------------
-namespace CUERipper.Properties
-{
-
-
- [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "8.0.0.0")]
- internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
- {
-
- private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
-
- public static Settings Default
- {
- get
- {
- return defaultInstance;
- }
- }
- }
+namespace CUERipper.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "8.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("freedb.org")]
+ public string MAIN_FREEDB_SITEADDRESS {
+ get {
+ return ((string)(this["MAIN_FREEDB_SITEADDRESS"]));
+ }
+ set {
+ this["MAIN_FREEDB_SITEADDRESS"] = value;
+ }
+ }
+ }
}
diff --git a/CUERipper/Properties/Settings.settings b/CUERipper/Properties/Settings.settings
index abf36c5..fb5513a 100644
--- a/CUERipper/Properties/Settings.settings
+++ b/CUERipper/Properties/Settings.settings
@@ -1,7 +1,9 @@
-
-
-
-
-
-
+
+
+
+
+ freedb.org
+
+
+
\ No newline at end of file
diff --git a/CUERipper/frmCUERipper.cs b/CUERipper/frmCUERipper.cs
index ceb6289..3afb8f7 100644
--- a/CUERipper/frmCUERipper.cs
+++ b/CUERipper/frmCUERipper.cs
@@ -8,12 +8,14 @@ using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;
+using System.Configuration;
using CUETools.AccurateRip;
using CUETools.CDImage;
using CUETools.Codecs;
using CUETools.Processor;
using CUETools.Ripper.SCSI;
using MusicBrainz;
+using Freedb;
namespace CUERipper
{
@@ -228,6 +230,35 @@ namespace CUERipper
});
}
+ private CUESheet CreateCUESheet(CDDriveReader audioSource, Release release, CDEntry cdEntry)
+ {
+ CUESheet cueSheet = new CUESheet(_config);
+ cueSheet.OpenCD(audioSource);
+ General.SetCUELine(cueSheet.Attributes, "REM", "DISCID", AccurateRipVerify.CalculateCDDBId(audioSource.TOC), false);
+ General.SetCUELine(cueSheet.Attributes, "REM", "COMMENT", CDDriveReader.RipperVersion(), true);
+ if (release != null)
+ cueSheet.FillFromMusicBrainz(release);
+ else if (cdEntry != null)
+ {
+ cueSheet.Artist = cdEntry.Artist;
+ cueSheet.Title = cdEntry.Title;
+ General.SetCUELine(cueSheet.Attributes, "REM", "DATE", cdEntry.Year, false);
+ General.SetCUELine(cueSheet.Attributes, "REM", "GENRE", cdEntry.Genre, true);
+ for (int i = 0; i < audioSource.TOC.AudioTracks; i++)
+ cueSheet.Tracks[i].Title = cdEntry.Tracks[i].Title;
+ }
+ else
+ {
+ cueSheet.Artist = "Unknown Artist";
+ cueSheet.Title = "Unknown Title";
+ for (int i = 0; i < audioSource.TOC.AudioTracks; i++)
+ cueSheet.Tracks[i].Title = string.Format("Track {0:00}", i + 1);
+ }
+ cueSheet.AccurateRip = AccurateRipMode.VerifyAndConvert;
+ cueSheet.ArVerify.ContactAccurateRip(AccurateRipVerify.CalculateAccurateRipId(audioSource.TOC));
+ return cueSheet;
+ }
+
private void Lookup(object o)
{
CDDriveReader audioSource = (CDDriveReader)o;
@@ -242,11 +273,7 @@ namespace CUERipper
{
release.GetEvents();
release.GetTracks();
- CUESheet cueSheet = new CUESheet(_config);
- cueSheet.OpenCD(audioSource);
- cueSheet.FillFromMusicBrainz(release);
- cueSheet.AccurateRip = AccurateRipMode.VerifyAndConvert;
- cueSheet.ArVerify.ContactAccurateRip(AccurateRipVerify.CalculateAccurateRipId(audioSource.TOC));
+ CUESheet cueSheet = CreateCUESheet(audioSource, release, null);
this.BeginInvoke((MethodInvoker)delegate()
{
comboRelease.Items.Add(cueSheet);
@@ -257,20 +284,63 @@ namespace CUERipper
{
}
MusicBrainzService.XmlRequest -= new EventHandler(MusicBrainz_LookupProgress);
+
+
+ FreedbHelper m_freedb = new FreedbHelper();
+
+ m_freedb.UserName = "gchudov";
+ m_freedb.Hostname = "gmail.com";
+ m_freedb.ClientName = "CUERipper";
+ m_freedb.Version = "1.0";
+ m_freedb.SetDefaultSiteAddress(Properties.Settings.Default.MAIN_FREEDB_SITEADDRESS);
+
+ QueryResult queryResult;
+ QueryResultCollection coll;
+ string code = string.Empty;
+ try
+ {
+ code = m_freedb.Query(AccurateRipVerify.CalculateCDDBQuery(audioSource.TOC), out queryResult, out coll);
+ if (code == FreedbHelper.ResponseCodes.CODE_200)
+ {
+ CDEntry cdEntry;
+ code = m_freedb.Read(queryResult, out cdEntry);
+ if (code == FreedbHelper.ResponseCodes.CODE_210)
+ {
+ CUESheet cueSheet = CreateCUESheet(audioSource, null, cdEntry);
+ this.BeginInvoke((MethodInvoker)delegate()
+ {
+ comboRelease.Items.Add(cueSheet);
+ });
+ }
+ }
+ else
+ if (code == FreedbHelper.ResponseCodes.CODE_210 ||
+ code == FreedbHelper.ResponseCodes.CODE_211 )
+ {
+ foreach (QueryResult qr in coll)
+ {
+ CDEntry cdEntry;
+ code = m_freedb.Read(qr, out cdEntry);
+ if (code == FreedbHelper.ResponseCodes.CODE_210)
+ {
+ CUESheet cueSheet = CreateCUESheet(audioSource, null, cdEntry);
+ this.BeginInvoke((MethodInvoker)delegate()
+ {
+ comboRelease.Items.Add(cueSheet);
+ });
+ }
+ }
+ }
+ }
+ catch (Exception)
+ {
+ }
+
this.BeginInvoke((MethodInvoker)delegate()
{
if (comboRelease.Items.Count == 0)
{
- CUESheet cueSheet = new CUESheet(_config);
- cueSheet.OpenCD(audioSource);
- General.SetCUELine(cueSheet.Attributes, "REM", "DISCID", AccurateRipVerify.CalculateCDDBId(audioSource.TOC), false);
- General.SetCUELine(cueSheet.Attributes, "REM", "COMMENT", CDDriveReader.RipperVersion(), true);
- cueSheet.Artist = "Unknown Artist";
- cueSheet.Title = "Unknown Title";
- cueSheet.AccurateRip = AccurateRipMode.VerifyAndConvert;
- cueSheet.ArVerify.ContactAccurateRip(AccurateRipVerify.CalculateAccurateRipId(audioSource.TOC));
- for (int i = 0; i < audioSource.TOC.AudioTracks; i++)
- cueSheet.Tracks[i].Title = string.Format("Track {0:00}", i + 1);
+ CUESheet cueSheet = CreateCUESheet(audioSource, null, null);
comboRelease.Items.Add(cueSheet);
}
});
@@ -332,7 +402,8 @@ namespace CUERipper
private void listTracks_AfterLabelEdit(object sender, LabelEditEventArgs e)
{
CUESheet cueSheet = (CUESheet)comboRelease.SelectedItem;
- cueSheet.Tracks[e.Item].Title = e.Label;
+ if (e.Label != null)
+ cueSheet.Tracks[e.Item].Title = e.Label;
}
private void editToolStripMenuItem_Click(object sender, EventArgs e)
diff --git a/CUETools.AccurateRip/AccurateRip.cs b/CUETools.AccurateRip/AccurateRip.cs
index 5bd046d..7014e7f 100644
--- a/CUETools.AccurateRip/AccurateRip.cs
+++ b/CUETools.AccurateRip/AccurateRip.cs
@@ -491,6 +491,16 @@ namespace CUETools.AccurateRip
return false;
}
+ public static string CalculateCDDBQuery(CDImageLayout toc)
+ {
+ StringBuilder query = new StringBuilder(CalculateCDDBId(toc));
+ query.AppendFormat("+{0}", toc.TrackCount);
+ for (int iTrack = 1; iTrack <= toc.TrackCount; iTrack++)
+ query.AppendFormat("+{0}", toc[iTrack].Start + 150);
+ query.AppendFormat("+{0}", toc.Length / 75 - toc[1].Start / 75);
+ return query.ToString();
+ }
+
public static string CalculateCDDBId(CDImageLayout toc)
{
uint cddbDiscId = 0;
diff --git a/CUETools.Processor/Processor.cs b/CUETools.Processor/Processor.cs
index 4f360b3..b6afcc8 100644
--- a/CUETools.Processor/Processor.cs
+++ b/CUETools.Processor/Processor.cs
@@ -516,8 +516,6 @@ namespace CUETools.Processor
public void FillFromMusicBrainz(Release release)
{
- General.SetCUELine(_attributes, "REM", "DISCID", AccurateRipVerify.CalculateCDDBId(_toc), false);
- General.SetCUELine(_attributes, "REM", "COMMENT", CDDriveReader.RipperVersion(), true);
if (release.GetEvents().Count > 0)
General.SetCUELine(_attributes, "REM", "DATE", release.GetEvents()[0].Date.Substring(0, 4), false);
Artist = release.GetArtist();
diff --git a/CUETools/CUETools.sln b/CUETools/CUETools.sln
index f60425b..c5ddd3f 100644
--- a/CUETools/CUETools.sln
+++ b/CUETools/CUETools.sln
@@ -75,6 +75,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MusicBrainz", "..\MusicBrai
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CUERipper", "..\CUERipper\CUERipper.csproj", "{39B43BBB-BAFC-4D85-9BEA-3BCB7EFED89C}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Freedb", "..\Freedb\Freedb.csproj", "{5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -370,6 +372,17 @@ Global
{39B43BBB-BAFC-4D85-9BEA-3BCB7EFED89C}.Release|x64.Build.0 = Release|x64
{39B43BBB-BAFC-4D85-9BEA-3BCB7EFED89C}.Release|x86.ActiveCfg = Release|x86
{39B43BBB-BAFC-4D85-9BEA-3BCB7EFED89C}.Release|x86.Build.0 = Release|x86
+ {5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Debug|x64.ActiveCfg = Debug|x64
+ {5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Debug|x64.Build.0 = Debug|x64
+ {5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Debug|x86.Build.0 = Debug|Any CPU
+ {5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Release|x64.ActiveCfg = Release|x64
+ {5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Release|x64.Build.0 = Release|x64
+ {5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Freedb/AssemblyInfo.cs b/Freedb/AssemblyInfo.cs
new file mode 100644
index 0000000..7a15472
--- /dev/null
+++ b/Freedb/AssemblyInfo.cs
@@ -0,0 +1,58 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.0.1")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing.
+//
+// Notes:
+// (*) If no key is specified, the assembly is not signed.
+// (*) KeyName refers to a key that has been installed in the Crypto Service
+// Provider (CSP) on your machine. KeyFile refers to a file which contains
+// a key.
+// (*) If the KeyFile and the KeyName values are both specified, the
+// following processing occurs:
+// (1) If the KeyName can be found in the CSP, that key is used.
+// (2) If the KeyName does not exist and the KeyFile does exist, the key
+// in the KeyFile is installed into the CSP and used.
+// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+// When specifying the KeyFile, the location of the KeyFile should be
+// relative to the project output directory which is
+// %Project Directory%\obj\. For example, if your KeyFile is
+// located in the project directory, you would specify the AssemblyKeyFile
+// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+// documentation for more information on this.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyKeyName("")]
diff --git a/Freedb/CDEntry.cs b/Freedb/CDEntry.cs
new file mode 100644
index 0000000..7e420dc
--- /dev/null
+++ b/Freedb/CDEntry.cs
@@ -0,0 +1,385 @@
+#region COPYRIGHT (c) 2004 by Brian Weeres
+/* Copyright (c) 2004 by Brian Weeres
+ *
+ * Email: bweeres@protegra.com; bweeres@hotmail.com
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * If you modify it then please indicate so.
+ *
+ * The software is provided "AS IS" and there are no warranties or implied warranties.
+ * In no event shall Brian Weeres and/or Protegra Technology Group be liable for any special,
+ * direct, indirect, or consequential damages or any damages whatsoever resulting for any reason
+ * out of the use or performance of this software
+ *
+ */
+#endregion
+using System;
+using System.Collections.Specialized;
+using System.Diagnostics;
+using System.Text;
+
+namespace Freedb
+{
+ ///
+ /// Summary description for CDEntry.
+ ///
+ public class CDEntry
+ {
+
+
+
+ #region Private Member Variables
+ private string m_Discid;
+ private string m_Artist;
+ private string m_Title;
+ private string m_Year;
+ private string m_Genre;
+ private TrackCollection m_Tracks = new TrackCollection(); // 0 based - first track is at 0 last track is at numtracks - 1
+ private string m_ExtendedData;
+ private string m_PlayOrder;
+
+ ///
+ /// Property NumberOfTracks (int)
+ ///
+
+
+
+
+ #endregion
+
+ #region Public Member Variables
+ ///
+ /// Property Discid (string)
+ ///
+ public string Discid
+ {
+ get
+ {
+ return this.m_Discid;
+ }
+ set
+ {
+ this.m_Discid = value;
+ }
+ }
+
+ ///
+ /// Property Artist (string)
+ ///
+ public string Artist
+ {
+ get
+ {
+ return this.m_Artist;
+ }
+ set
+ {
+ this.m_Artist = value;
+ }
+ }
+
+ ///
+ /// Property Title (string)
+ ///
+ public string Title
+ {
+ get
+ {
+ return this.m_Title;
+ }
+ set
+ {
+ this.m_Title = value;
+ }
+ }
+
+ ///
+ /// Property Year (string)
+ ///
+ public string Year
+ {
+ get
+ {
+ return this.m_Year;
+ }
+ set
+ {
+ this.m_Year = value;
+ }
+ }
+
+ ///
+ /// Property Genre (string)
+ ///
+ public string Genre
+ {
+ get
+ {
+ return this.m_Genre;
+ }
+ set
+ {
+ this.m_Genre = value;
+ }
+ }
+
+
+ ///
+ /// Property Tracks (StringCollection)
+ ///
+ public TrackCollection Tracks
+ {
+ get
+ {
+ return this.m_Tracks;
+ }
+ set
+ {
+ this.m_Tracks = value;
+ }
+ }
+
+
+ ///
+ /// Property ExtendedData (string)
+ ///
+ public string ExtendedData
+ {
+ get
+ {
+ return this.m_ExtendedData;
+ }
+ set
+ {
+ this.m_ExtendedData = value;
+ }
+ }
+
+
+
+
+ ///
+ /// Property PlayOrder (string)
+ ///
+ public string PlayOrder
+ {
+ get
+ {
+ return this.m_PlayOrder;
+ }
+ set
+ {
+ this.m_PlayOrder = value;
+ }
+ }
+
+ public int NumberOfTracks
+ {
+ get
+ {
+ return m_Tracks.Count;
+ }
+ }
+
+ #endregion
+
+
+
+ public CDEntry(StringCollection data)
+ {
+ if (!Parse(data))
+ {
+ throw new Exception("Unable to Parse CDEntry.");
+ }
+ }
+
+
+ private bool Parse(StringCollection data)
+ {
+ foreach (string line in data)
+ {
+
+ // check for comment
+
+ if (line[0] == '#')
+ continue;
+
+ int index = line.IndexOf('=');
+ if (index == -1) // couldn't find equal sign have no clue what the data is
+ continue;
+ string field = line.Substring(0,index);
+ index++; // move it past the equal sign
+
+ switch (field)
+ {
+ case "DISCID":
+ {
+ this.m_Discid = line.Substring(index);
+ continue;
+ }
+
+ case "DTITLE": // artist / title
+ {
+ this.m_Artist += line.Substring(index);
+ continue;
+ }
+
+ case "DYEAR":
+ {
+ this.m_Year = line.Substring(index);
+ continue;
+ }
+
+ case "DGENRE":
+ {
+ this.m_Genre += line.Substring(index);
+ continue;
+ }
+
+ case "EXTD":
+ {
+ // may be more than one - just concatenate them
+ this.m_ExtendedData += line.Substring(index);
+ continue;
+ }
+
+ case "PLAYORDER":
+ {
+ this.m_PlayOrder += line.Substring(index);
+ continue;
+ }
+
+
+ default:
+
+ //get track info or extended track info
+ if (field.StartsWith("TTITLE"))
+ {
+ int trackNumber = -1;
+ // Parse could throw an exception
+ try
+ {
+ trackNumber = int.Parse(field.Substring("TTITLE".Length));
+ }
+
+ catch (Exception ex)
+ {
+ Debug.WriteLine("Failed to parse track Number. Reason: " + ex.Message);
+ continue;
+ }
+
+ //may need to concatenate track info
+ if (trackNumber < m_Tracks.Count )
+ m_Tracks[trackNumber].Title += line.Substring(index);
+ else
+ {
+ Track track = new Track(line.Substring(index));
+ this.m_Tracks.Add(track);
+ }
+ continue;
+ }
+ else if (field.StartsWith("EXTT"))
+ {
+ int trackNumber = -1;
+ // Parse could throw an exception
+ try
+ {
+ trackNumber = int.Parse(field.Substring("EXTT".Length));
+ }
+
+ catch (Exception ex)
+ {
+ Debug.WriteLine("Failed to parse track Number. Reason: " + ex.Message);
+ continue;
+ }
+
+ if (trackNumber < 0 || trackNumber > m_Tracks.Count -1)
+ continue;
+
+ m_Tracks[trackNumber].ExtendedData += line.Substring(index);
+
+
+
+ }
+
+
+
+
+ continue;
+
+ } //end of switch
+
+ }
+
+
+ //split the title and artist from DTITLE;
+ // see if we have a slash
+ int slash = this.m_Artist.IndexOf(" / ");
+ if (slash == -1)
+ {
+ this.m_Title= m_Artist;
+ }
+ else
+ {
+ string titleArtist = m_Artist;
+ this.m_Artist = titleArtist.Substring(0,slash);
+ slash +=3; // move past " / "
+ this.m_Title = titleArtist.Substring(slash );
+ }
+
+
+ return true;
+
+
+ }
+
+ public override string ToString()
+ {
+ StringBuilder builder = new StringBuilder();
+ builder.Append("Title: ");
+ builder.Append(this.m_Title);
+ builder.Append("\n");
+ builder.Append("Artist: ");
+ builder.Append(this.m_Artist);
+ builder.Append("\n");
+ builder.Append("Discid: ");
+ builder.Append(this.m_Discid);
+ builder.Append("\n");
+ builder.Append("Genre: ");
+ builder.Append(this.m_Genre);
+ builder.Append("\n");
+ builder.Append("Year: ");
+ builder.Append(this.m_Year);
+ builder.Append("\n");
+ builder.Append("Tracks:");
+ foreach (Track track in this.m_Tracks)
+ {
+ builder.Append("\n");
+ builder.Append(track.Title);
+ }
+
+ return builder.ToString();
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+}
diff --git a/Freedb/Freedb.csproj b/Freedb/Freedb.csproj
new file mode 100644
index 0000000..18f70b0
--- /dev/null
+++ b/Freedb/Freedb.csproj
@@ -0,0 +1,154 @@
+
+
+ Local
+ 8.0.50727
+ 2.0
+ {5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}
+ Debug
+ AnyCPU
+
+
+
+
+ Freedb
+
+
+ JScript
+ Grid
+ IE50
+ false
+ Library
+ Freedb
+ OnBuildSuccess
+
+
+
+
+
+
+
+
+ ..\bin\win32\Debug\
+ false
+ 285212672
+ false
+
+
+ DEBUG;TRACE
+
+
+ true
+ 4096
+ false
+
+
+ false
+ false
+ false
+ false
+ 4
+ full
+ prompt
+
+
+ ..\bin\win32\Release\
+ false
+ 285212672
+ false
+
+
+ TRACE
+
+
+ false
+ 4096
+ false
+
+
+ true
+ false
+ false
+ false
+ 4
+ none
+ prompt
+
+
+ true
+ ..\bin\x64\Debug\
+ DEBUG;TRACE
+ 285212672
+ full
+ x64
+ C:\Program Files (x86)\Microsoft Visual Studio 8\Team Tools\Static Analysis Tools\FxCop\\rules
+ true
+ GlobalSuppressions.cs
+ prompt
+
+
+ ..\bin\x64\Release\
+ TRACE
+ 285212672
+ true
+
+
+ x64
+ C:\Program Files (x86)\Microsoft Visual Studio 8\Team Tools\Static Analysis Tools\FxCop\\rules
+ true
+ GlobalSuppressions.cs
+ prompt
+
+
+
+ System
+
+
+ System.Data
+
+
+ System.Drawing
+
+
+ System.Windows.Forms
+
+
+ System.XML
+
+
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Freedb/FreedbHelper.cs b/Freedb/FreedbHelper.cs
new file mode 100644
index 0000000..02b0ccd
--- /dev/null
+++ b/Freedb/FreedbHelper.cs
@@ -0,0 +1,685 @@
+#region COPYRIGHT (c) 2004 by Brian Weeres
+/* Copyright (c) 2004 by Brian Weeres
+ *
+ * Email: bweeres@protegra.com; bweeres@hotmail.com
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * If you modify it then please indicate so.
+ *
+ * The software is provided "AS IS" and there are no warranties or implied warranties.
+ * In no event shall Brian Weeres and/or Protegra Technology Group be liable for any special,
+ * direct, indirect, or consequential damages or any damages whatsoever resulting for any reason
+ * out of the use or performance of this software
+ *
+ */
+#endregion
+using System;
+using System.Text;
+using System.Net;
+using System.IO;
+using System.Collections.Specialized;
+using System.Diagnostics;
+
+namespace Freedb
+{
+ ///
+ /// Summary description for FreedbHelper.
+ ///
+ public class FreedbHelper
+ {
+ public const string MAIN_FREEDB_ADDRESS = "freedb.freedb.org";
+ public const string DEFAULT_ADDITIONAL_URL_INFO = "/~cddb/cddb.cgi";
+ private Site m_mainSite = new Site(MAIN_FREEDB_ADDRESS,"http",DEFAULT_ADDITIONAL_URL_INFO);
+ private string m_UserName;
+ private string m_Hostname;
+ private string m_ClientName;
+ private string m_Version;
+ private string m_ProtocolLevel = "6"; // default to level 6 support
+ private Site m_CurrentSite = null;
+
+
+ #region Constants for Freedb commands
+ public class Commands
+ {
+ public const string CMD_HELLO = "hello";
+ public const string CMD_READ = "cddb+read";
+ public const string CMD_QUERY = "cddb+query";
+ public const string CMD_SITES = "sites";
+ public const string CMD_PROTO = "proto";
+ public const string CMD_CATEGORIES = "cddb+lscat";
+ public const string CMD = "cmd="; // will never use without the equals so put it here
+ public const string CMD_TERMINATOR = ".";
+ }
+ #endregion
+
+ #region Constants for Freedb ResponseCodes
+ public class ResponseCodes
+ {
+ public const string CODE_210 = "210"; // Okay // or in a query multiple exact matches
+ public const string CODE_401 = "401"; // sites: no site information available
+ public const string CODE_402 = "402"; // Server Error
+
+ public const string CODE_500 = "500"; // Invalid command, invalid parameters, etc.
+ //query codes
+ public const string CODE_200 = "200"; // Exact match
+ public const string CODE_211 = "211"; // InExact matches found - list follows
+ public const string CODE_202 = "202"; // No match
+ public const string CODE_403 = "403"; // Database entry is corrupt
+ public const string CODE_409 = "409"; // No Handshake
+
+ // our own code
+ public const string CODE_INVALID = "-1"; // Invalid code
+ }
+ #endregion
+
+
+ #region Public Properties
+ ///
+ /// Property Version (string)
+ ///
+ public string Version
+ {
+ get
+ {
+ return this.m_Version;
+ }
+ set
+ {
+ this.m_Version = value;
+ }
+ }
+
+
+
+
+
+
+ ///
+ /// Property MainSite(string)
+ ///
+ public Site MainSite
+ {
+ get
+ {
+ return this.m_mainSite ;
+ }
+ }
+
+ ///
+ /// Property ClientName (string)
+ ///
+ public string ClientName
+ {
+ get
+ {
+ return this.m_ClientName;
+ }
+ set
+ {
+ this.m_ClientName = value;
+ }
+ }
+
+ ///
+ /// Property Hostname (string)
+ ///
+ public string Hostname
+ {
+ get
+ {
+ return this.m_Hostname;
+ }
+ set
+ {
+ this.m_Hostname = value;
+ }
+ }
+
+ ///
+ /// Property UserName (string)
+ ///
+ public string UserName
+ {
+ get
+ {
+ return this.m_UserName;
+ }
+ set
+ {
+ this.m_UserName = value;
+ }
+ }
+
+ ///
+ /// Property ProtocolLevel (string)
+ ///
+ public string ProtocolLevel
+ {
+ get
+ {
+ return this.m_ProtocolLevel;
+ }
+ set
+ {
+ this.m_ProtocolLevel = value;
+ }
+ }
+
+ ///
+ /// Property CurrentSite (Site)
+ ///
+ public Site CurrentSite
+ {
+ get
+ {
+ return this.m_CurrentSite;
+ }
+ set
+ {
+ this.m_CurrentSite = value;
+ }
+ }
+
+
+
+
+ public FreedbHelper()
+ {
+ m_ProtocolLevel = "6"; // default it
+ }
+
+
+
+ ///
+ /// Retrieve all Freedb servers from the main server site
+ ///
+ /// SiteCollection that is populated with the site information
+ /// Response Code
+ public string GetSites(out SiteCollection sites)
+ {
+ return GetSites(Site.PROTOCOLS.ALL, out sites);
+ }
+
+ #endregion
+
+
+ ///
+ /// Get the Freedb sites
+ ///
+ ///
+ /// SiteCollection that is populated with the site information
+ /// Response Code
+ ///
+ public string GetSites(string protocol, out SiteCollection sites)
+ {
+ if (protocol != Site.PROTOCOLS.CDDBP && protocol != Site.PROTOCOLS.HTTP)
+ protocol = Site.PROTOCOLS.ALL;
+
+ StringCollection coll;
+
+ try
+ {
+ coll= Call(Commands.CMD_SITES,m_mainSite.GetUrl());
+ }
+
+ catch (Exception ex)
+ {
+ Debug.WriteLine("Error retrieving Sites." + ex.Message);
+ Exception newEx = new Exception("FreedbHelper.GetSites: Error retrieving Sites.",ex);
+ throw newEx;
+ }
+
+ sites = null;
+
+ // check if results came back
+ if (coll.Count < 0)
+ {
+ string msg = "No results returned from sites request.";
+ Exception ex = new Exception(msg,null);
+ throw ex;
+ }
+
+ string code = GetCode(coll[0]);
+ if (code == ResponseCodes.CODE_INVALID)
+ {
+ string msg = "Unable to process results Sites Request. Returned Data: " + coll[0];
+ Exception ex = new Exception(msg,null);
+ throw ex;
+ }
+
+ switch (code)
+ {
+ case ResponseCodes.CODE_500:
+ return ResponseCodes.CODE_500;
+
+ case ResponseCodes.CODE_401:
+ return ResponseCodes.CODE_401;
+
+ case ResponseCodes.CODE_210:
+ {
+ coll.RemoveAt(0);
+ sites = new SiteCollection();
+ foreach (String line in coll)
+ {
+ Debug.WriteLine("line: " + line);
+ Site site = new Site(line);
+ if (protocol == Site.PROTOCOLS.ALL)
+ sites.Add(new Site(line));
+ else if (site.Protocol == protocol)
+ sites.Add(new Site(line));
+ }
+
+ return ResponseCodes.CODE_210;
+ }
+
+ default:
+ return ResponseCodes.CODE_500;
+ }
+
+ }
+
+
+ ///
+ /// Read Entry from the database.
+ ///
+ /// A QueryResult object that is created by performing a query
+ /// out parameter - CDEntry object
+ ///
+ public string Read(QueryResult qr, out CDEntry cdEntry)
+ {
+ Debug.Assert(qr != null);
+ cdEntry = null;
+
+ StringCollection coll = null;
+ StringBuilder builder = new StringBuilder(FreedbHelper.Commands.CMD_READ);
+ builder.Append("+");
+ builder.Append(qr.Category);
+ builder.Append("+");
+ builder.Append(qr.Discid);
+
+ //make call
+ try
+ {
+ coll = Call(builder.ToString());
+ }
+
+ catch (Exception ex)
+ {
+ string msg = "Error performing cddb read.";
+ Exception newex = new Exception(msg,ex);
+ throw newex ;
+ }
+
+ // check if results came back
+ if (coll.Count < 0)
+ {
+ string msg = "No results returned from cddb read.";
+ Exception ex = new Exception(msg,null);
+ throw ex;
+ }
+
+
+ string code = GetCode(coll[0]);
+ if (code == ResponseCodes.CODE_INVALID)
+ {
+ string msg = "Unable to process results for cddb read. Returned Data: " + coll[0];
+ Exception ex = new Exception(msg,null);
+ throw ex;
+ }
+
+
+ switch (code)
+ {
+ case ResponseCodes.CODE_500:
+ return ResponseCodes.CODE_500;
+
+ case ResponseCodes.CODE_401: // entry not found
+ case ResponseCodes.CODE_402: // server error
+ case ResponseCodes.CODE_403: // Database entry is corrupt
+ case ResponseCodes.CODE_409: // No handshake
+ return code;
+
+ case ResponseCodes.CODE_210: // good
+ {
+ coll.RemoveAt(0); // remove the 210
+ cdEntry = new CDEntry(coll);
+ return ResponseCodes.CODE_210;
+ }
+ default:
+ return ResponseCodes.CODE_500;
+ }
+ }
+
+
+ ///
+ /// Query the freedb server to see if there is information on this cd
+ ///
+ ///
+ ///
+ ///
+ ///
+ public string Query(string querystring, out QueryResult queryResult, out QueryResultCollection queryResultsColl)
+ {
+ queryResult = null;
+ queryResultsColl = null;
+ StringCollection coll = null;
+
+ StringBuilder builder = new StringBuilder(FreedbHelper.Commands.CMD_QUERY);
+ builder.Append("+");
+ builder.Append(querystring);
+
+ //make call
+ try
+ {
+ coll = Call(builder.ToString());
+ }
+
+ catch (Exception ex)
+ {
+ string msg = "Unable to perform cddb query.";
+ Exception newex = new Exception(msg,ex);
+ throw newex ;
+ }
+
+ // check if results came back
+ if (coll.Count < 0)
+ {
+ string msg = "No results returned from cddb query.";
+ Exception ex = new Exception(msg,null);
+ throw ex;
+ }
+
+ string code = GetCode(coll[0]);
+ if (code == ResponseCodes.CODE_INVALID)
+ {
+ string msg = "Unable to process results returned for query: Data returned: " + coll[0];
+ Exception ex = new Exception (msg,null);
+ throw ex;
+ }
+
+
+ switch (code)
+ {
+ case ResponseCodes.CODE_500:
+ return ResponseCodes.CODE_500;
+
+ // Multiple results were returned
+ // Put them into a queryResultCollection object
+ case ResponseCodes.CODE_211:
+ case ResponseCodes.CODE_210:
+ {
+ queryResultsColl = new QueryResultCollection();
+ //remove the 210 or 211
+ coll.RemoveAt(0);
+ foreach (string line in coll)
+ {
+ QueryResult result = new QueryResult(line,true);
+ queryResultsColl.Add(result);
+ }
+
+ return ResponseCodes.CODE_211;
+ }
+
+
+ // exact match
+ case ResponseCodes.CODE_200:
+ {
+ queryResult = new QueryResult(coll[0]);
+ return ResponseCodes.CODE_200;
+ }
+
+
+ //not found
+ case ResponseCodes.CODE_202:
+ return ResponseCodes.CODE_202;
+
+ //Database entry is corrupt
+ case ResponseCodes.CODE_403:
+ return ResponseCodes.CODE_403;
+
+ //no handshake
+ case ResponseCodes.CODE_409:
+ return ResponseCodes.CODE_409;
+
+ default:
+ return ResponseCodes.CODE_500;
+
+ } // end of switch
+
+
+ }
+
+
+ ///
+ /// Retrieve the categories
+ ///
+ ///
+ ///
+ public string GetCategories(out StringCollection strings)
+ {
+
+ StringCollection coll;
+ strings = null;
+
+ try
+ {
+ coll = Call(FreedbHelper.Commands.CMD_CATEGORIES);
+ }
+
+ catch (Exception ex)
+ {
+ string msg = "Unable to retrieve Categories.";
+ Exception newex = new Exception(msg,ex);
+ throw newex;
+ }
+
+ // check if results came back
+ if (coll.Count < 0)
+ {
+ string msg = "No results returned from categories request.";
+ Exception ex = new Exception(msg,null);
+ throw ex;
+ }
+
+ string code = GetCode(coll[0]);
+ if (code == ResponseCodes.CODE_INVALID)
+ {
+ string msg = "Unable to retrieve Categories. Data Returned: " + coll[0];
+ Exception ex = new Exception(msg,null);
+ throw ex;
+ }
+
+ switch (code)
+ {
+ case ResponseCodes.CODE_500:
+ return ResponseCodes.CODE_500;
+
+ case ResponseCodes.CODE_210:
+ {
+ strings = coll;
+ coll.RemoveAt(0);
+ return ResponseCodes.CODE_210;
+ }
+
+ default:
+ {
+ string msg = "Unknown code returned from GetCategories: " + coll[0];
+ Exception ex = new Exception(msg,null);
+ throw ex;
+ }
+
+
+ }
+
+ }
+
+
+ ///
+ /// Call the Freedb server using the specified command and the current site
+ /// If the current site is null use the default server
+ ///
+ /// The command to be exectued
+ /// StringCollection
+ private StringCollection Call(string command)
+ {
+ if (m_CurrentSite != null)
+ return Call(command,m_CurrentSite.GetUrl());
+ else
+ return Call(command,m_mainSite.GetUrl());
+ }
+
+ ///
+ /// Call the Freedb server using the specified command and the specified url
+ /// The command should not include the cmd= and hello and proto parameters.
+ /// They will be added automatically
+ ///
+ /// The command to be exectued
+ /// The Freedb server to use
+ /// StringCollection
+ private StringCollection Call(string commandIn, string url)
+ {
+ StreamReader reader = null;
+ HttpWebResponse response = null;
+ StringCollection coll = new StringCollection();
+
+ try
+ {
+ //create our HttpWebRequest which we use to call the freedb server
+ HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
+ req.ContentType = "text/plain";
+ // we are using th POST method of calling the http server. We could have also used the GET method
+ req.Method="POST";
+ //add the hello and proto commands to the request
+ string command = BuildCommand(Commands.CMD + commandIn);
+ //using Unicode
+ byte[] byteArray = Encoding.UTF8.GetBytes(command);
+ //get our request stream
+ Stream newStream= req.GetRequestStream();
+ //write our command data to it
+ newStream.Write(byteArray,0,byteArray.Length);
+ newStream.Close();
+ //Make the call. Note this is a synchronous call
+ response = (HttpWebResponse) req.GetResponse();
+ //put the results into a StreamReader
+ reader = new StreamReader(response.GetResponseStream(),System.Text.Encoding.UTF8);
+ // add each line to the StringCollection until we get the terminator
+ string line;
+ while ((line = reader.ReadLine()) != null)
+ {
+ if (line.StartsWith(Commands.CMD_TERMINATOR))
+ break;
+ else
+ coll.Add(line);
+ }
+ }
+
+ catch (Exception ex)
+ {
+ throw ex;
+ }
+
+ finally
+ {
+ if (response != null)
+ response.Close();
+ if (reader != null)
+ reader.Close();
+ }
+
+ return coll;
+ }
+
+
+
+
+
+ ///
+ /// Given a specific command add on the hello and proto which are requied for an http call
+ ///
+ ///
+ ///
+ private string BuildCommand(string command)
+ {
+ StringBuilder builder = new StringBuilder(command);
+ builder.Append("&");
+ builder.Append(Hello());
+ builder.Append("&");
+ builder.Append(Proto());
+ return builder.ToString();
+ }
+
+ ///
+ /// Build the hello part of the command
+ ///
+ ///
+ public string Hello()
+ {
+ StringBuilder builder = new StringBuilder(Commands.CMD_HELLO);
+ builder.Append("=");
+ builder.Append(m_UserName);
+ builder.Append("+");
+ builder.Append(this.m_Hostname);
+ builder.Append("+");
+ builder.Append(this.ClientName);
+ builder.Append("+");
+ builder.Append(this.m_Version);
+ return builder.ToString();
+ }
+
+ ///
+ /// Build the Proto part of the command
+ ///
+ ///
+ public string Proto()
+ {
+ StringBuilder builder = new StringBuilder(Commands.CMD_PROTO);
+ builder.Append("=");
+ builder.Append(m_ProtocolLevel );
+ return builder.ToString();
+ }
+
+
+ ///
+ /// given the first line of a result set return the CDDB code
+ ///
+ ///
+ ///
+ private string GetCode(string firstLine)
+ {
+ firstLine = firstLine.Trim();
+
+ //find first white space after start
+ int index = firstLine.IndexOf(' ');
+ if (index != -1)
+ firstLine = firstLine.Substring(0,index);
+ else
+ {
+ return ResponseCodes.CODE_INVALID;
+ }
+
+ return firstLine;
+ }
+
+
+
+ ///
+ /// If a different default site address is preferred over "freedb.freedb.org"
+ /// set it here
+ /// NOTE: Only set the ip address
+ ///
+ ///
+ public void SetDefaultSiteAddress(string siteAddress)
+ {
+ //sanity check on the url
+ if (siteAddress.IndexOf("http") != -1 ||
+ siteAddress.IndexOf("cgi") != -1)
+ throw new Exception("Invalid Site Address specified");
+
+ this.m_mainSite.SiteAddress = siteAddress;
+ }
+
+ }
+}
diff --git a/Freedb/QueryResult.cs b/Freedb/QueryResult.cs
new file mode 100644
index 0000000..94f6e8f
--- /dev/null
+++ b/Freedb/QueryResult.cs
@@ -0,0 +1,213 @@
+#region COPYRIGHT (c) 2004 by Brian Weeres
+/* Copyright (c) 2004 by Brian Weeres
+ *
+ * Email: bweeres@protegra.com; bweeres@hotmail.com
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * If you modify it then please indicate so.
+ *
+ * The software is provided "AS IS" and there are no warranties or implied warranties.
+ * In no event shall Brian Weeres and/or Protegra Technology Group be liable for any special,
+ * direct, indirect, or consequential damages or any damages whatsoever resulting for any reason
+ * out of the use or performance of this software
+ *
+ */
+#endregion
+using System;
+
+namespace Freedb
+{
+ ///
+ /// Summary description for QueryResult.
+ ///
+ public class QueryResult
+ {
+ private string m_ResponseCode;
+ private string m_Category;
+ private string m_Discid;
+ private string m_Artist;
+ private string m_Title;
+
+
+ #region Public Properties
+ ///
+ /// Property ResponseCode (string)
+ ///
+ public string ResponseCode
+ {
+ get
+ {
+ return this.m_ResponseCode;
+ }
+ set
+ {
+ this.m_ResponseCode = value;
+ }
+ }
+
+
+ ///
+ /// Property Category (string)
+ ///
+ public string Category
+ {
+ get
+ {
+ return this.m_Category;
+ }
+ set
+ {
+ this.m_Category = value;
+ }
+ }
+
+ ///
+ /// Property Discid (string)
+ ///
+ public string Discid
+ {
+ get
+ {
+ return this.m_Discid;
+ }
+ set
+ {
+ this.m_Discid = value;
+ }
+ }
+
+ ///
+ /// Property Artist (string)
+ ///
+ public string Artist
+ {
+ get
+ {
+ return this.m_Artist;
+ }
+ set
+ {
+ this.m_Artist = value;
+ }
+ }
+
+ ///
+ /// Property Title (string)
+ ///
+ public string Title
+ {
+ get
+ {
+ return this.m_Title;
+ }
+ set
+ {
+ this.m_Title = value;
+ }
+ }
+
+
+ #endregion
+
+ public QueryResult(string queryResult)
+ {
+ if (!Parse(queryResult,false))
+ {
+ throw new Exception("Unable to Parse QueryResult. Input: " + queryResult);
+ }
+
+ }
+
+ ///
+ /// The parsing for a queryresult returned as part of a number of matches is slightly different
+ /// There is no response code
+ ///
+ ///
+ /// true if the result is part of multi-match which means it will not contain a response code
+ public QueryResult(string queryResult, bool multiMatchInput)
+ {
+ if (!Parse(queryResult,multiMatchInput))
+ {
+ throw new Exception("Unable to Parse QueryResult. Input: " + queryResult);
+ }
+
+ }
+
+ ///
+ /// Parse the query result line from the cddb server
+ ///
+ ///
+ public bool Parse(string queryResult,bool match)
+ {
+
+ queryResult.Trim();
+ int secondIndex =0;
+
+ // get first white space
+ int index = queryResult.IndexOf(' ');
+ //if we are parsing a matched queryresult there is no responsecode so skip it
+ if (!match)
+ {
+ m_ResponseCode = queryResult.Substring(0,index);
+ index++;
+ secondIndex = queryResult.IndexOf(' ',index);
+ }
+ else
+ {
+ secondIndex = index;
+ index=0;
+ }
+
+ m_Category = queryResult.Substring(index,secondIndex-index);
+ index = secondIndex;
+ index++;
+ secondIndex = queryResult.IndexOf(' ',index);
+ m_Discid = queryResult.Substring(index,secondIndex-index);
+ index = secondIndex;
+ index++;
+ secondIndex = queryResult.IndexOf('/',index);
+ m_Artist = queryResult.Substring(index,secondIndex-index-1); // -1 because there is a space at the end of artist
+ index = secondIndex;
+ index+=2; //skip past / and space
+ m_Title = queryResult.Substring(index);
+ return true;
+ }
+
+// public bool Parse(string queryResult)
+// {
+// queryResult.Trim();
+// string [] values = queryResult.Split(' ');
+// if (values.Length <6)
+// return false;
+// this.m_ResponseCode = values[0];
+// m_Category = values[1];
+// m_Discid = values[2];
+//
+// // now we need to look for a slash
+// bool artist = true;
+// for (int i = 3; i < values.Length;i++)
+// {
+// if (values[i] == "/")
+// {
+// artist = false;
+// continue;
+// }
+// if (artist)
+// this.m_Artist += values[i];
+// else
+// this.m_Title += values[i];
+//
+// }
+// return true;
+// }
+
+ public override string ToString()
+ {
+ return this.m_Artist + ", " + this.m_Title;
+ }
+
+ }
+}
diff --git a/Freedb/QueryResultCollection.cs b/Freedb/QueryResultCollection.cs
new file mode 100644
index 0000000..c597f0d
--- /dev/null
+++ b/Freedb/QueryResultCollection.cs
@@ -0,0 +1,2378 @@
+#region COPYRIGHT (c) 2004 by Brian Weeres
+/* Copyright (c) 2004 by Brian Weeres
+ *
+ * Email: bweeres@protegra.com; bweeres@hotmail.com
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * If you modify it then please indicate so.
+ *
+ * The software is provided "AS IS" and there are no warranties or implied warranties.
+ * In no event shall Brian Weeres and/or Protegra Technology Group be liable for any special,
+ * direct, indirect, or consequential damages or any damages whatsoever resulting for any reason
+ * out of the use or performance of this software
+ *
+ */
+#endregion
+using System;
+using System.Collections;
+using Freedb;
+
+namespace Freedb
+{
+ #region Interface IQueryResultCollection
+
+ ///
+ /// Defines size, enumerators, and synchronization methods for strongly
+ /// typed collections of elements.
+ ///
+ ///
+ /// IQueryResultCollection provides an
+ /// that is strongly typed for elements.
+ ///
+
+ public interface IQueryResultCollection
+ {
+ #region Properties
+ #region Count
+
+ ///
+ /// Gets the number of elements contained in the
+ /// .
+ ///
+ /// The number of elements contained in the
+ /// .
+ /// Please refer to for details.
+
+ int Count { get; }
+
+ #endregion
+ #region IsSynchronized
+
+ ///
+ /// Gets a value indicating whether access to the
+ /// is synchronized (thread-safe).
+ ///
+ /// true if access to the is
+ /// synchronized (thread-safe); otherwise, false. The default is false.
+ /// Please refer to for details.
+
+ bool IsSynchronized { get; }
+
+ #endregion
+ #region SyncRoot
+
+ ///
+ /// Gets an object that can be used to synchronize access
+ /// to the .
+ ///
+ /// An object that can be used to synchronize access
+ /// to the .
+ /// Please refer to for details.
+
+ object SyncRoot { get; }
+
+ #endregion
+ #endregion
+ #region Methods
+ #region CopyTo
+
+ ///
+ /// Copies the entire to a one-dimensional
+ /// of elements, starting at the specified index of the target array.
+ ///
+ /// The one-dimensional that is the destination of the
+ /// elements copied from the .
+ /// The Array must have zero-based indexing.
+ /// The zero-based index in
+ /// at which copying begins.
+ ///
+ /// is a null reference.
+ ///
+ /// is less than zero.
+ ///
+ /// is equal to or greater than the length of .
+ /// -or-
+ /// The number of elements in the source is greater
+ /// than the available space from to the end of the destination
+ /// .
+ /// Please refer to for details.
+
+ void CopyTo(QueryResult[] array, int arrayIndex);
+
+ #endregion
+ #region GetEnumerator
+
+ ///
+ /// Returns an that can
+ /// iterate through the .
+ ///
+ /// An
+ /// for the entire .
+ /// Please refer to for details.
+
+ IQueryResultEnumerator GetEnumerator();
+
+ #endregion
+ #endregion
+ }
+
+ #endregion
+ #region Interface IQueryResultList
+
+ ///
+ /// Represents a strongly typed collection of
+ /// objects that can be individually accessed by index.
+ ///
+ ///
+ /// IQueryResultList provides an
+ /// that is strongly typed for elements.
+ ///
+
+ public interface
+ IQueryResultList: IQueryResultCollection
+ {
+ #region Properties
+ #region IsFixedSize
+
+ ///
+ /// Gets a value indicating whether the has a fixed size.
+ ///
+ /// true if the has a fixed size;
+ /// otherwise, false. The default is false.
+ /// Please refer to for details.
+
+ bool IsFixedSize { get; }
+
+ #endregion
+ #region IsReadOnly
+
+ ///
+ /// Gets a value indicating whether the is read-only.
+ ///
+ /// true if the is read-only;
+ /// otherwise, false. The default is false.
+ /// Please refer to for details.
+
+ bool IsReadOnly { get; }
+
+ #endregion
+ #region Item
+
+ ///
+ /// Gets or sets the element at the specified index.
+ ///
+ /// The zero-based index of the
+ /// element to get or set.
+ ///
+ /// The element at the specified .
+ ///
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is equal to or greater than
+ /// .
+ ///
+ ///
+ /// The property is set and the is read-only.
+ /// Please refer to for details.
+
+ QueryResult this[int index] { get; set; }
+
+ #endregion
+ #endregion
+ #region Methods
+ #region Add
+
+ ///
+ /// Adds a to the end
+ /// of the .
+ ///
+ /// The object
+ /// to be added to the end of the .
+ /// This argument can be a null reference.
+ ///
+ /// The index at which
+ /// the has been added.
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The IQueryResultList has a fixed size.
+ /// Please refer to for details.
+
+ int Add(QueryResult value);
+
+ #endregion
+ #region Clear
+
+ ///
+ /// Removes all elements from the .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The IQueryResultList has a fixed size.
+ /// Please refer to for details.
+
+ void Clear();
+
+ #endregion
+ #region Contains
+
+ ///
+ /// Determines whether the
+ /// contains the specified element.
+ ///
+ /// The object
+ /// to locate in the .
+ /// This argument can be a null reference.
+ ///
+ /// true if is found in the
+ /// ; otherwise, false.
+ /// Please refer to for details.
+
+ bool Contains(QueryResult value);
+
+ #endregion
+ #region IndexOf
+
+ ///
+ /// Returns the zero-based index of the first occurrence of the specified
+ /// in the .
+ ///
+ /// The object
+ /// to locate in the .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// The zero-based index of the first occurrence of
+ /// in the , if found; otherwise, -1.
+ ///
+ /// Please refer to for details.
+
+ int IndexOf(QueryResult value);
+
+ #endregion
+ #region Insert
+
+ ///
+ /// Inserts a element into the
+ /// at the specified index.
+ ///
+ /// The zero-based index at which
+ /// should be inserted.
+ /// The object
+ /// to insert into the .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is greater than
+ /// .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The IQueryResultList has a fixed size.
+ /// Please refer to for details.
+
+ void Insert(int index, QueryResult value);
+
+ #endregion
+ #region Remove
+
+ ///
+ /// Removes the first occurrence of the specified
+ /// from the .
+ ///
+ /// The object
+ /// to remove from the .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The IQueryResultList has a fixed size.
+ /// Please refer to for details.
+
+ void Remove(QueryResult value);
+
+ #endregion
+ #region RemoveAt
+
+ ///
+ /// Removes the element at the specified index of the
+ /// .
+ ///
+ /// The zero-based index of the element to remove.
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is equal to or greater than
+ /// .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The IQueryResultList has a fixed size.
+ /// Please refer to for details.
+
+ void RemoveAt(int index);
+
+ #endregion
+ #endregion
+ }
+
+ #endregion
+ #region Interface IQueryResultEnumerator
+
+ ///
+ /// Supports type-safe iteration over a collection that
+ /// contains elements.
+ ///
+ ///
+ /// IQueryResultEnumerator provides an
+ /// that is strongly typed for elements.
+ ///
+
+ public interface IQueryResultEnumerator
+ {
+ #region Properties
+ #region Current
+
+ ///
+ /// Gets the current element in the collection.
+ ///
+ /// The current element in the collection.
+ /// The enumerator is positioned
+ /// before the first element of the collection or after the last element.
+ /// -or-
+ /// The collection was modified after the enumerator was created.
+ /// Please refer to for details, but note
+ /// that Current fails if the collection was modified since the last successful
+ /// call to or .
+
+ QueryResult Current { get; }
+
+ #endregion
+ #endregion
+ #region Methods
+ #region MoveNext
+
+ ///
+ /// Advances the enumerator to the next element of the collection.
+ ///
+ /// true if the enumerator was successfully advanced to the next element;
+ /// false if the enumerator has passed the end of the collection.
+ ///
+ /// The collection was modified after the enumerator was created.
+ /// Please refer to for details.
+
+ bool MoveNext();
+
+ #endregion
+ #region Reset
+
+ ///
+ /// Sets the enumerator to its initial position,
+ /// which is before the first element in the collection.
+ ///
+ ///
+ /// The collection was modified after the enumerator was created.
+ /// Please refer to for details.
+
+ void Reset();
+
+ #endregion
+ #endregion
+ }
+
+ #endregion
+ #region Class QueryResultCollection
+
+ ///
+ /// Implements a strongly typed collection of elements.
+ ///
+ ///
+ /// QueryResultCollection provides an
+ /// that is strongly typed for elements.
+ ///
+
+ [Serializable]
+ public class QueryResultCollection:
+ IQueryResultList, IList, ICloneable
+ {
+ #region Private Fields
+
+ private const int _defaultCapacity = 16;
+
+ private QueryResult[] _array = null;
+ private int _count = 0;
+
+ [NonSerialized]
+ private int _version = 0;
+
+ #endregion
+ #region Private Constructors
+
+ // helper type to identify private ctor
+ private enum Tag { Default }
+
+ private QueryResultCollection(Tag tag) { }
+
+ #endregion
+ #region Public Constructors
+ #region QueryResultCollection()
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// Initializes a new instance of the class
+ /// that is empty and has the default initial capacity.
+ ///
+ /// Please refer to for details.
+
+ public QueryResultCollection()
+ {
+ this._array = new QueryResult[_defaultCapacity];
+ }
+
+ #endregion
+ #region QueryResultCollection(Int32)
+
+ ///
+ /// Initializes a new instance of the class
+ /// that is empty and has the specified initial capacity.
+ ///
+ /// The number of elements that the new
+ /// is initially capable of storing.
+ ///
+ /// is less than zero.
+ /// Please refer to for details.
+
+ public QueryResultCollection(int capacity)
+ {
+ if (capacity < 0)
+ throw new ArgumentOutOfRangeException("capacity",
+ capacity, "Argument cannot be negative.");
+
+ this._array = new QueryResult[capacity];
+ }
+
+ #endregion
+ #region QueryResultCollection(QueryResultCollection)
+
+ ///
+ /// Initializes a new instance of the class
+ /// that contains elements copied from the specified collection and
+ /// that has the same initial capacity as the number of elements copied.
+ ///
+ /// The
+ /// whose elements are copied to the new collection.
+ ///
+ /// is a null reference.
+ /// Please refer to for details.
+
+ public QueryResultCollection(QueryResultCollection collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException("collection");
+
+ this._array = new QueryResult[collection.Count];
+ AddRange(collection);
+ }
+
+ #endregion
+ #region QueryResultCollection(QueryResult[])
+
+ ///
+ /// Initializes a new instance of the class
+ /// that contains elements copied from the specified
+ /// array and that has the same initial capacity as the number of elements copied.
+ ///
+ /// An of
+ /// elements that are copied to the new collection.
+ ///
+ /// is a null reference.
+ /// Please refer to for details.
+
+ public QueryResultCollection(QueryResult[] array)
+ {
+ if (array == null)
+ throw new ArgumentNullException("array");
+
+ this._array = new QueryResult[array.Length];
+ AddRange(array);
+ }
+
+ #endregion
+ #endregion
+ #region Protected Properties
+ #region InnerArray
+
+ ///
+ /// Gets the list of elements contained in the instance.
+ ///
+ ///
+ /// A one-dimensional with zero-based indexing that contains all
+ /// elements in the .
+ ///
+ ///
+ /// Use InnerArray to access the element array of a
+ /// instance that might be a read-only or synchronized wrapper. This is necessary because
+ /// the element array field of wrapper classes is always a null reference.
+ ///
+
+ protected virtual QueryResult[] InnerArray
+ {
+ get { return this._array; }
+ }
+
+ #endregion
+ #endregion
+ #region Public Properties
+ #region Capacity
+
+ ///
+ /// Gets or sets the capacity of the .
+ ///
+ /// The number of elements that the
+ /// can contain.
+ ///
+ /// Capacity is set to a value that is less than .
+ /// Please refer to for details.
+
+ public virtual int Capacity
+ {
+ get { return this._array.Length; }
+ set
+ {
+ if (value == this._array.Length) return;
+
+ if (value < this._count)
+ throw new ArgumentOutOfRangeException("Capacity",
+ value, "Value cannot be less than Count.");
+
+ if (value == 0)
+ {
+ this._array = new QueryResult[_defaultCapacity];
+ return;
+ }
+
+ QueryResult[] newArray = new QueryResult[value];
+ Array.Copy(this._array, newArray, this._count);
+ this._array = newArray;
+ }
+ }
+
+ #endregion
+ #region Count
+
+ ///
+ /// Gets the number of elements contained in the .
+ ///
+ ///
+ /// The number of elements contained in the .
+ ///
+ /// Please refer to for details.
+
+ public virtual int Count
+ {
+ get { return this._count; }
+ }
+
+ #endregion
+ #region IsFixedSize
+
+ ///
+ /// Gets a value indicating whether the has a fixed size.
+ ///
+ /// true if the has a fixed size;
+ /// otherwise, false. The default is false.
+ /// Please refer to for details.
+
+ public virtual bool IsFixedSize
+ {
+ get { return false; }
+ }
+
+ #endregion
+ #region IsReadOnly
+
+ ///
+ /// Gets a value indicating whether the is read-only.
+ ///
+ /// true if the is read-only;
+ /// otherwise, false. The default is false.
+ /// Please refer to for details.
+
+ public virtual bool IsReadOnly
+ {
+ get { return false; }
+ }
+
+ #endregion
+ #region IsSynchronized
+
+ ///
+ /// Gets a value indicating whether access to the
+ /// is synchronized (thread-safe).
+ ///
+ /// true if access to the is
+ /// synchronized (thread-safe); otherwise, false. The default is false.
+ /// Please refer to for details.
+
+ public virtual bool IsSynchronized
+ {
+ get { return false; }
+ }
+
+ #endregion
+ #region IsUnique
+
+ ///
+ /// Gets a value indicating whether the
+ /// ensures that all elements are unique.
+ ///
+ ///
+ /// true if the ensures that all
+ /// elements are unique; otherwise, false. The default is false.
+ ///
+ ///
+ /// IsUnique returns true exactly if the
+ /// is exposed through a wrapper.
+ /// Please refer to for details.
+ ///
+
+ public virtual bool IsUnique
+ {
+ get { return false; }
+ }
+
+ #endregion
+ #region Item: QueryResult
+
+ ///
+ /// Gets or sets the element at the specified index.
+ ///
+ /// The zero-based index of the
+ /// element to get or set.
+ ///
+ /// The element at the specified .
+ ///
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is equal to or greater than .
+ ///
+ ///
+ /// The property is set and the is read-only.
+ /// -or-
+ /// The property is set, the QueryResultCollection already contains the
+ /// specified element at a different index, and the QueryResultCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ public virtual QueryResult this[int index]
+ {
+ get
+ {
+ ValidateIndex(index);
+ return this._array[index];
+ }
+ set
+ {
+ ValidateIndex(index);
+ ++this._version;
+ this._array[index] = value;
+ }
+ }
+
+ #endregion
+ #region IList.Item: Object
+
+ ///
+ /// Gets or sets the element at the specified index.
+ ///
+ /// The zero-based index of the element to get or set.
+ ///
+ /// The element at the specified . When the property
+ /// is set, this value must be compatible with .
+ ///
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is equal to or greater than .
+ ///
+ /// The property is set to a value
+ /// that is not compatible with .
+ ///
+ /// The property is set and the is read-only.
+ /// -or-
+ /// The property is set, the QueryResultCollection already contains the
+ /// specified element at a different index, and the QueryResultCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ object IList.this[int index]
+ {
+ get { return this[index]; }
+ set { this[index] = (QueryResult) value; }
+ }
+
+ #endregion
+ #region SyncRoot
+
+ ///
+ /// Gets an object that can be used to synchronize
+ /// access to the .
+ ///
+ /// An object that can be used to synchronize
+ /// access to the .
+ ///
+ /// Please refer to for details.
+
+ public virtual object SyncRoot
+ {
+ get { return this; }
+ }
+
+ #endregion
+ #endregion
+ #region Public Methods
+ #region Add(QueryResult)
+
+ ///
+ /// Adds a to the end of the .
+ ///
+ /// The object
+ /// to be added to the end of the .
+ /// This argument can be a null reference.
+ ///
+ /// The index at which the
+ /// has been added.
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The QueryResultCollection has a fixed size.
+ /// -or-
+ /// The QueryResultCollection already contains the specified
+ /// , and the QueryResultCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ public virtual int Add(QueryResult value)
+ {
+ if (this._count == this._array.Length)
+ EnsureCapacity(this._count + 1);
+
+ ++this._version;
+ this._array[this._count] = value;
+ return this._count++;
+ }
+
+ #endregion
+ #region IList.Add(Object)
+
+ ///
+ /// Adds an to the end of the .
+ ///
+ ///
+ /// The object to be added to the end of the .
+ /// This argument must be compatible with .
+ /// This argument can be a null reference.
+ ///
+ /// The index at which the
+ /// has been added.
+ ///
+ /// is not compatible with .
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The QueryResultCollection has a fixed size.
+ /// -or-
+ /// The QueryResultCollection already contains the specified
+ /// , and the QueryResultCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ int IList.Add(object value)
+ {
+ return Add((QueryResult) value);
+ }
+
+ #endregion
+ #region AddRange(QueryResultCollection)
+
+ ///
+ /// Adds a range of elements to the end of the .
+ ///
+ ///
+ /// Adds the elements of another collection to the end of the .
+ ///
+ /// The whose elements
+ /// should be added to the end of the current collection.
+ ///
+ /// is a null reference.
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The QueryResultCollection has a fixed size.
+ /// -or-
+ /// The QueryResultCollection already contains one or more elements
+ /// in the specified , and the QueryResultCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ public virtual void AddRange(QueryResultCollection collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException("collection");
+
+ if (collection.Count == 0) return;
+ if (this._count + collection.Count > this._array.Length)
+ EnsureCapacity(this._count + collection.Count);
+
+ ++this._version;
+ Array.Copy(collection.InnerArray, 0,
+ this._array, this._count, collection.Count);
+ this._count += collection.Count;
+ }
+
+ #endregion
+ #region AddRange(QueryResult[])
+
+ ///
+ /// Adds the elements of a array
+ /// to the end of the .
+ ///
+ /// An of elements
+ /// that should be added to the end of the .
+ ///
+ /// is a null reference.
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The QueryResultCollection has a fixed size.
+ /// -or-
+ /// The QueryResultCollection already contains one or more elements
+ /// in the specified , and the QueryResultCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ public virtual void AddRange(QueryResult[] array)
+ {
+ if (array == null)
+ throw new ArgumentNullException("array");
+
+ if (array.Length == 0) return;
+ if (this._count + array.Length > this._array.Length)
+ EnsureCapacity(this._count + array.Length);
+
+ ++this._version;
+ Array.Copy(array, 0, this._array, this._count, array.Length);
+ this._count += array.Length;
+ }
+
+ #endregion
+ #region BinarySearch
+
+ ///
+ /// Searches the entire sorted for an
+ /// element using the default comparer
+ /// and returns the zero-based index of the element.
+ ///
+ /// The object
+ /// to locate in the .
+ /// This argument can be a null reference.
+ ///
+ /// The zero-based index of in the sorted
+ /// , if is found;
+ /// otherwise, a negative number, which is the bitwise complement of the index
+ /// of the next element that is larger than or, if there
+ /// is no larger element, the bitwise complement of .
+ ///
+ /// Neither nor the elements of the
+ /// implement the interface.
+ /// Please refer to for details.
+
+ public virtual int BinarySearch(QueryResult value)
+ {
+ return Array.BinarySearch(this._array, 0, this._count, value);
+ }
+
+ #endregion
+ #region Clear
+
+ ///
+ /// Removes all elements from the .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The QueryResultCollection has a fixed size.
+ /// Please refer to for details.
+
+ public virtual void Clear()
+ {
+ if (this._count == 0) return;
+
+ ++this._version;
+ Array.Clear(this._array, 0, this._count);
+ this._count = 0;
+ }
+
+ #endregion
+ #region Clone
+
+ ///
+ /// Creates a shallow copy of the .
+ ///
+ /// A shallow copy of the .
+ /// Please refer to for details.
+
+ public virtual object Clone()
+ {
+ QueryResultCollection collection = new QueryResultCollection(this._count);
+
+ Array.Copy(this._array, 0, collection._array, 0, this._count);
+ collection._count = this._count;
+ collection._version = this._version;
+
+ return collection;
+ }
+
+ #endregion
+ #region Contains(QueryResult)
+
+ ///
+ /// Determines whether the
+ /// contains the specified element.
+ ///
+ /// The object
+ /// to locate in the .
+ /// This argument can be a null reference.
+ ///
+ /// true if is found in the
+ /// ; otherwise, false.
+ /// Please refer to for details.
+
+ public bool Contains(QueryResult value)
+ {
+ return (IndexOf(value) >= 0);
+ }
+
+ #endregion
+ #region IList.Contains(Object)
+
+ ///
+ /// Determines whether the contains the specified element.
+ ///
+ /// The object to locate in the .
+ /// This argument must be compatible with .
+ /// This argument can be a null reference.
+ ///
+ /// true if is found in the
+ /// ; otherwise, false.
+ ///
+ /// is not compatible with .
+ /// Please refer to for details.
+
+ bool IList.Contains(object value)
+ {
+ return Contains((QueryResult) value);
+ }
+
+ #endregion
+ #region CopyTo(QueryResult[])
+
+ ///
+ /// Copies the or a portion of it to a one-dimensional array.
+ ///
+ ///
+ /// Copies the entire to a one-dimensional
+ /// of elements, starting at the beginning of the target array.
+ ///
+ /// The one-dimensional that is the destination of the
+ /// elements copied from the .
+ /// The Array must have zero-based indexing.
+ ///
+ /// is a null reference.
+ ///
+ /// The number of elements in the source is greater
+ /// than the available space in the destination .
+ /// Please refer to for details.
+
+ public virtual void CopyTo(QueryResult[] array)
+ {
+ CheckTargetArray(array, 0);
+ Array.Copy(this._array, array, this._count);
+ }
+
+ #endregion
+ #region CopyTo(QueryResult[], Int32)
+
+ ///
+ /// Copies the entire to a one-dimensional
+ /// of elements, starting at the specified index of the target array.
+ ///
+ /// The one-dimensional that is the destination of the
+ /// elements copied from the .
+ /// The Array must have zero-based indexing.
+ /// The zero-based index in
+ /// at which copying begins.
+ ///
+ /// is a null reference.
+ ///
+ /// is less than zero.
+ ///
+ /// is equal to or greater than the length of .
+ /// -or-
+ /// The number of elements in the source is greater than the
+ /// available space from to the end of the destination
+ /// .
+ /// Please refer to for details.
+
+ public virtual void CopyTo(QueryResult[] array, int arrayIndex)
+ {
+ CheckTargetArray(array, arrayIndex);
+ Array.Copy(this._array, 0, array, arrayIndex, this._count);
+ }
+
+ #endregion
+ #region ICollection.CopyTo(Array, Int32)
+
+ ///
+ /// Copies the entire to a one-dimensional ,
+ /// starting at the specified index of the target array.
+ ///
+ /// The one-dimensional that is the destination of the
+ /// elements copied from the .
+ /// The Array must have zero-based indexing.
+ /// The zero-based index in
+ /// at which copying begins.
+ ///
+ /// is a null reference.
+ ///
+ /// is less than zero.
+ ///
+ /// is multidimensional.
+ /// -or-
+ /// is equal to or greater than the length of .
+ /// -or-
+ /// The number of elements in the source is greater than the
+ /// available space from to the end of the destination
+ /// .
+ ///
+ /// The type cannot be cast automatically
+ /// to the type of the destination .
+ /// Please refer to for details.
+
+ void ICollection.CopyTo(Array array, int arrayIndex)
+ {
+ CopyTo((QueryResult[]) array, arrayIndex);
+ }
+
+ #endregion
+ #region GetEnumerator: IQueryResultEnumerator
+
+ ///
+ /// Returns an that can
+ /// iterate through the .
+ ///
+ /// An
+ /// for the entire .
+ /// Please refer to for details.
+
+ public virtual IQueryResultEnumerator GetEnumerator()
+ {
+ return new Enumerator(this);
+ }
+
+ #endregion
+ #region IEnumerable.GetEnumerator: IEnumerator
+
+ ///
+ /// Returns an that can
+ /// iterate through the .
+ ///
+ /// An
+ /// for the entire .
+ /// Please refer to for details.
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return (IEnumerator) GetEnumerator();
+ }
+
+ #endregion
+ #region IndexOf(QueryResult)
+
+ ///
+ /// Returns the zero-based index of the first occurrence of the specified
+ /// in the .
+ ///
+ /// The object
+ /// to locate in the .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// The zero-based index of the first occurrence of
+ /// in the , if found; otherwise, -1.
+ ///
+ /// Please refer to for details.
+
+ public virtual int IndexOf(QueryResult value)
+ {
+ return Array.IndexOf(this._array, value, 0, this._count);
+ }
+
+ #endregion
+ #region IList.IndexOf(Object)
+
+ ///
+ /// Returns the zero-based index of the first occurrence of the specified
+ /// in the .
+ ///
+ /// The object to locate in the .
+ /// This argument must be compatible with .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// The zero-based index of the first occurrence of
+ /// in the , if found; otherwise, -1.
+ ///
+ ///
+ /// is not compatible with .
+ /// Please refer to for details.
+
+ int IList.IndexOf(object value)
+ {
+ return IndexOf((QueryResult) value);
+ }
+
+ #endregion
+ #region Insert(Int32, QueryResult)
+
+ ///
+ /// Inserts a element into the
+ /// at the specified index.
+ ///
+ /// The zero-based index at which
+ /// should be inserted.
+ /// The object
+ /// to insert into the .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is greater than .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The QueryResultCollection has a fixed size.
+ /// -or-
+ /// The QueryResultCollection already contains the specified
+ /// , and the QueryResultCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ public virtual void Insert(int index, QueryResult value)
+ {
+ if (index < 0)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument cannot be negative.");
+
+ if (index > this._count)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument cannot exceed Count.");
+
+ if (this._count == this._array.Length)
+ EnsureCapacity(this._count + 1);
+
+ ++this._version;
+ if (index < this._count)
+ Array.Copy(this._array, index,
+ this._array, index + 1, this._count - index);
+
+ this._array[index] = value;
+ ++this._count;
+ }
+
+ #endregion
+ #region IList.Insert(Int32, Object)
+
+ ///
+ /// Inserts an element into the at the specified index.
+ ///
+ /// The zero-based index at which
+ /// should be inserted.
+ /// The object to insert into the .
+ /// This argument must be compatible with .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is greater than .
+ ///
+ ///
+ /// is not compatible with .
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The QueryResultCollection has a fixed size.
+ /// -or-
+ /// The QueryResultCollection already contains the specified
+ /// , and the QueryResultCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ void IList.Insert(int index, object value)
+ {
+ Insert(index, (QueryResult) value);
+ }
+
+ #endregion
+ #region ReadOnly
+
+ ///
+ /// Returns a read-only wrapper for the specified .
+ ///
+ /// The to wrap.
+ /// A read-only wrapper around .
+ ///
+ /// is a null reference.
+ /// Please refer to for details.
+
+ public static QueryResultCollection ReadOnly(QueryResultCollection collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException("collection");
+
+ return new ReadOnlyList(collection);
+ }
+
+ #endregion
+ #region Remove(QueryResult)
+
+ ///
+ /// Removes the first occurrence of the specified
+ /// from the .
+ ///
+ /// The object
+ /// to remove from the .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The QueryResultCollection has a fixed size.
+ /// Please refer to for details.
+
+ public virtual void Remove(QueryResult value)
+ {
+ int index = IndexOf(value);
+ if (index >= 0) RemoveAt(index);
+ }
+
+ #endregion
+ #region IList.Remove(Object)
+
+ ///
+ /// Removes the first occurrence of the specified
+ /// from the .
+ ///
+ /// The object to remove from the .
+ /// This argument must be compatible with .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// is not compatible with .
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The QueryResultCollection has a fixed size.
+ /// Please refer to for details.
+
+ void IList.Remove(object value)
+ {
+ Remove((QueryResult) value);
+ }
+
+ #endregion
+ #region RemoveAt
+
+ ///
+ /// Removes the element at the specified index of the .
+ ///
+ /// The zero-based index of the element to remove.
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is equal to or greater than .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The QueryResultCollection has a fixed size.
+ /// Please refer to for details.
+
+ public virtual void RemoveAt(int index)
+ {
+ ValidateIndex(index);
+
+ ++this._version;
+ if (index < --this._count)
+ Array.Copy(this._array, index + 1,
+ this._array, index, this._count - index);
+
+ this._array[this._count] = null;
+ }
+
+ #endregion
+ #region RemoveRange
+
+ ///
+ /// Removes the specified range of elements from the .
+ ///
+ /// The zero-based starting index of the range
+ /// of elements to remove.
+ /// The number of elements to remove.
+ ///
+ /// and do not denote a
+ /// valid range of elements in the .
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is less than zero.
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The QueryResultCollection has a fixed size.
+ /// Please refer to for details.
+
+ public virtual void RemoveRange(int index, int count)
+ {
+ if (index < 0)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument cannot be negative.");
+
+ if (count < 0)
+ throw new ArgumentOutOfRangeException("count",
+ count, "Argument cannot be negative.");
+
+ if (index + count > this._count)
+ throw new ArgumentException(
+ "Arguments denote invalid range of elements.");
+
+ if (count == 0) return;
+
+ ++this._version;
+ this._count -= count;
+
+ if (index < this._count)
+ Array.Copy(this._array, index + count,
+ this._array, index, this._count - index);
+
+ Array.Clear(this._array, this._count, count);
+ }
+
+ #endregion
+ #region Reverse()
+
+ ///
+ /// Reverses the order of the elements in the
+ /// or a portion of it.
+ ///
+ ///
+ /// Reverses the order of the elements in the entire .
+ ///
+ ///
+ /// The is read-only.
+ /// Please refer to for details.
+
+ public virtual void Reverse()
+ {
+ if (this._count <= 1) return;
+ ++this._version;
+ Array.Reverse(this._array, 0, this._count);
+ }
+
+ #endregion
+ #region Reverse(Int32, Int32)
+
+ ///
+ /// Reverses the order of the elements in the specified range.
+ ///
+ /// The zero-based starting index of the range
+ /// of elements to reverse.
+ /// The number of elements to reverse.
+ ///
+ /// and do not denote a
+ /// valid range of elements in the .
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is less than zero.
+ ///
+ ///
+ /// The is read-only.
+ /// Please refer to for details.
+
+ public virtual void Reverse(int index, int count)
+ {
+ if (index < 0)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument cannot be negative.");
+
+ if (count < 0)
+ throw new ArgumentOutOfRangeException("count",
+ count, "Argument cannot be negative.");
+
+ if (index + count > this._count)
+ throw new ArgumentException(
+ "Arguments denote invalid range of elements.");
+
+ if (count <= 1 || this._count <= 1) return;
+ ++this._version;
+ Array.Reverse(this._array, index, count);
+ }
+
+ #endregion
+ #region Sort()
+
+ ///
+ /// Sorts the elements in the or a portion of it.
+ ///
+ ///
+ /// Sorts the elements in the entire
+ /// using the implementation of each element.
+ ///
+ ///
+ /// The is read-only.
+ /// Please refer to for details.
+
+ public virtual void Sort()
+ {
+ if (this._count <= 1) return;
+ ++this._version;
+ Array.Sort(this._array, 0, this._count);
+ }
+
+ #endregion
+ #region Sort(IComparer)
+
+ ///
+ /// Sorts the elements in the entire
+ /// using the specified interface.
+ ///
+ ///
+ /// The implementation to use when comparing elements.
+ /// -or-
+ /// A null reference to use the implementation
+ /// of each element.
+ ///
+ /// The is read-only.
+ /// Please refer to for details.
+
+ public virtual void Sort(IComparer comparer)
+ {
+ if (this._count <= 1) return;
+ ++this._version;
+ Array.Sort(this._array, 0, this._count, comparer);
+ }
+
+ #endregion
+ #region Sort(Int32, Int32, IComparer)
+
+ ///
+ /// Sorts the elements in the specified range
+ /// using the specified interface.
+ ///
+ /// The zero-based starting index of the range
+ /// of elements to sort.
+ /// The number of elements to sort.
+ ///
+ /// The implementation to use when comparing elements.
+ /// -or-
+ /// A null reference to use the implementation
+ /// of each element.
+ ///
+ /// and do not denote a
+ /// valid range of elements in the .
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is less than zero.
+ ///
+ ///
+ /// The is read-only.
+ /// Please refer to for details.
+
+ public virtual void Sort(int index, int count, IComparer comparer)
+ {
+ if (index < 0)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument cannot be negative.");
+
+ if (count < 0)
+ throw new ArgumentOutOfRangeException("count",
+ count, "Argument cannot be negative.");
+
+ if (index + count > this._count)
+ throw new ArgumentException(
+ "Arguments denote invalid range of elements.");
+
+ if (count <= 1 || this._count <= 1) return;
+ ++this._version;
+ Array.Sort(this._array, index, count, comparer);
+ }
+
+ #endregion
+ #region Synchronized
+
+ ///
+ /// Returns a synchronized (thread-safe) wrapper
+ /// for the specified .
+ ///
+ /// The to synchronize.
+ ///
+ /// A synchronized (thread-safe) wrapper around .
+ ///
+ ///
+ /// is a null reference.
+ /// Please refer to for details.
+
+ public static QueryResultCollection Synchronized(QueryResultCollection collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException("collection");
+
+ return new SyncList(collection);
+ }
+
+ #endregion
+ #region ToArray
+
+ ///
+ /// Copies the elements of the to a new
+ /// of elements.
+ ///
+ /// A one-dimensional of
+ /// elements containing copies of the elements of the .
+ /// Please refer to for details.
+
+ public virtual QueryResult[] ToArray()
+ {
+ QueryResult[] array = new QueryResult[this._count];
+ Array.Copy(this._array, array, this._count);
+ return array;
+ }
+
+ #endregion
+ #region TrimToSize
+
+ ///
+ /// Sets the capacity to the actual number of elements in the .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The QueryResultCollection has a fixed size.
+ /// Please refer to for details.
+
+ public virtual void TrimToSize()
+ {
+ Capacity = this._count;
+ }
+
+ #endregion
+ #region Unique
+
+ ///
+ /// Returns a wrapper for the specified
+ /// ensuring that all elements are unique.
+ ///
+ /// The to wrap.
+ ///
+ /// A wrapper around ensuring that all elements are unique.
+ ///
+ ///
+ /// contains duplicate elements.
+ ///
+ /// is a null reference.
+ ///
+ /// The Unique wrapper provides a set-like collection by ensuring
+ /// that all elements in the are unique.
+ ///
+ /// Unique raises an if the specified
+ /// contains any duplicate elements. The returned
+ /// wrapper raises a whenever the user attempts
+ /// to add an element that is already contained in the QueryResultCollection.
+ ///
+ /// Note: The Unique wrapper reflects any changes made
+ /// to the underlying , including the possible
+ /// creation of duplicate elements. The uniqueness of all elements is therefore
+ /// no longer assured if the underlying collection is manipulated directly.
+ ///
+
+ public static QueryResultCollection Unique(QueryResultCollection collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException("collection");
+
+ for (int i = collection.Count - 1; i > 0; i--)
+ if (collection.IndexOf(collection[i]) < i)
+ throw new ArgumentException("collection",
+ "Argument cannot contain duplicate elements.");
+
+ return new UniqueList(collection);
+ }
+
+ #endregion
+ #endregion
+ #region Private Methods
+ #region CheckEnumIndex
+
+ private void CheckEnumIndex(int index)
+ {
+ if (index < 0 || index >= this._count)
+ throw new InvalidOperationException(
+ "Enumerator is not on a collection element.");
+ }
+
+ #endregion
+ #region CheckEnumVersion
+
+ private void CheckEnumVersion(int version)
+ {
+ if (version != this._version)
+ throw new InvalidOperationException(
+ "Enumerator invalidated by modification to collection.");
+ }
+
+ #endregion
+ #region CheckTargetArray
+
+ private void CheckTargetArray(Array array, int arrayIndex)
+ {
+ if (array == null)
+ throw new ArgumentNullException("array");
+ if (array.Rank > 1)
+ throw new ArgumentException(
+ "Argument cannot be multidimensional.", "array");
+
+ if (arrayIndex < 0)
+ throw new ArgumentOutOfRangeException("arrayIndex",
+ arrayIndex, "Argument cannot be negative.");
+ if (arrayIndex >= array.Length)
+ throw new ArgumentException(
+ "Argument must be less than array length.", "arrayIndex");
+
+ if (this._count > array.Length - arrayIndex)
+ throw new ArgumentException(
+ "Argument section must be large enough for collection.", "array");
+ }
+
+ #endregion
+ #region EnsureCapacity
+
+ private void EnsureCapacity(int minimum)
+ {
+ int newCapacity = (this._array.Length == 0 ?
+ _defaultCapacity : this._array.Length * 2);
+
+ if (newCapacity < minimum) newCapacity = minimum;
+ Capacity = newCapacity;
+ }
+
+ #endregion
+ #region ValidateIndex
+
+ private void ValidateIndex(int index)
+ {
+ if (index < 0)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument cannot be negative.");
+
+ if (index >= this._count)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument must be less than Count.");
+ }
+
+ #endregion
+ #endregion
+ #region Class Enumerator
+
+ [Serializable]
+ private sealed class Enumerator:
+ IQueryResultEnumerator, IEnumerator
+ {
+ #region Private Fields
+
+ private readonly QueryResultCollection _collection;
+ private readonly int _version;
+ private int _index;
+
+ #endregion
+ #region Internal Constructors
+
+ internal Enumerator(QueryResultCollection collection)
+ {
+ this._collection = collection;
+ this._version = collection._version;
+ this._index = -1;
+ }
+
+ #endregion
+ #region Public Properties
+
+ public QueryResult Current
+ {
+ get
+ {
+ this._collection.CheckEnumIndex(this._index);
+ this._collection.CheckEnumVersion(this._version);
+ return this._collection[this._index];
+ }
+ }
+
+ object IEnumerator.Current
+ {
+ get { return Current; }
+ }
+
+ #endregion
+ #region Public Methods
+
+ public bool MoveNext()
+ {
+ this._collection.CheckEnumVersion(this._version);
+ return (++this._index < this._collection.Count);
+ }
+
+ public void Reset()
+ {
+ this._collection.CheckEnumVersion(this._version);
+ this._index = -1;
+ }
+
+ #endregion
+ }
+
+ #endregion
+ #region Class ReadOnlyList
+
+ [Serializable]
+ private sealed class ReadOnlyList: QueryResultCollection
+ {
+ #region Private Fields
+
+ private QueryResultCollection _collection;
+
+ #endregion
+ #region Internal Constructors
+
+ internal ReadOnlyList(QueryResultCollection collection):
+ base(Tag.Default)
+ {
+ this._collection = collection;
+ }
+
+ #endregion
+ #region Protected Properties
+
+ protected override QueryResult[] InnerArray
+ {
+ get { return this._collection.InnerArray; }
+ }
+
+ #endregion
+ #region Public Properties
+
+ public override int Capacity
+ {
+ get { return this._collection.Capacity; }
+ set
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified."); }
+ }
+
+ public override int Count
+ {
+ get { return this._collection.Count; }
+ }
+
+ public override bool IsFixedSize
+ {
+ get { return true; }
+ }
+
+ public override bool IsReadOnly
+ {
+ get { return true; }
+ }
+
+ public override bool IsSynchronized
+ {
+ get { return this._collection.IsSynchronized; }
+ }
+
+ public override bool IsUnique
+ {
+ get { return this._collection.IsUnique; }
+ }
+
+ public override QueryResult this[int index]
+ {
+ get { return this._collection[index]; }
+ set
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified."); }
+ }
+
+ public override object SyncRoot
+ {
+ get { return this._collection.SyncRoot; }
+ }
+
+ #endregion
+ #region Public Methods
+
+ public override int Add(QueryResult value)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void AddRange(QueryResultCollection collection)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void AddRange(QueryResult[] array)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override int BinarySearch(QueryResult value)
+ {
+ return this._collection.BinarySearch(value);
+ }
+
+ public override void Clear()
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override object Clone()
+ {
+ return new ReadOnlyList((QueryResultCollection) this._collection.Clone());
+ }
+
+ public override void CopyTo(QueryResult[] array)
+ {
+ this._collection.CopyTo(array);
+ }
+
+ public override void CopyTo(QueryResult[] array, int arrayIndex)
+ {
+ this._collection.CopyTo(array, arrayIndex);
+ }
+
+ public override IQueryResultEnumerator GetEnumerator()
+ {
+ return this._collection.GetEnumerator();
+ }
+
+ public override int IndexOf(QueryResult value)
+ {
+ return this._collection.IndexOf(value);
+ }
+
+ public override void Insert(int index, QueryResult value)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void Remove(QueryResult value)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void RemoveAt(int index)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void RemoveRange(int index, int count)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void Reverse()
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void Reverse(int index, int count)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void Sort()
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void Sort(IComparer comparer)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void Sort(int index, int count, IComparer comparer)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override QueryResult[] ToArray()
+ {
+ return this._collection.ToArray();
+ }
+
+ public override void TrimToSize()
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ #endregion
+ }
+
+ #endregion
+ #region Class SyncList
+
+ [Serializable]
+ private sealed class SyncList: QueryResultCollection
+ {
+ #region Private Fields
+
+ private QueryResultCollection _collection;
+ private object _root;
+
+ #endregion
+ #region Internal Constructors
+
+ internal SyncList(QueryResultCollection collection):
+ base(Tag.Default)
+ {
+
+ this._root = collection.SyncRoot;
+ this._collection = collection;
+ }
+
+ #endregion
+ #region Protected Properties
+
+ protected override QueryResult[] InnerArray
+ {
+ get { lock (this._root) return this._collection.InnerArray; }
+ }
+
+ #endregion
+ #region Public Properties
+
+ public override int Capacity
+ {
+ get { lock (this._root) return this._collection.Capacity; }
+ set { lock (this._root) this._collection.Capacity = value; }
+ }
+
+ public override int Count
+ {
+ get { lock (this._root) return this._collection.Count; }
+ }
+
+ public override bool IsFixedSize
+ {
+ get { return this._collection.IsFixedSize; }
+ }
+
+ public override bool IsReadOnly
+ {
+ get { return this._collection.IsReadOnly; }
+ }
+
+ public override bool IsSynchronized
+ {
+ get { return true; }
+ }
+
+ public override bool IsUnique
+ {
+ get { return this._collection.IsUnique; }
+ }
+
+ public override QueryResult this[int index]
+ {
+ get { lock (this._root) return this._collection[index]; }
+ set { lock (this._root) this._collection[index] = value; }
+ }
+
+ public override object SyncRoot
+ {
+ get { return this._root; }
+ }
+
+ #endregion
+ #region Public Methods
+
+ public override int Add(QueryResult value)
+ {
+ lock (this._root) return this._collection.Add(value);
+ }
+
+ public override void AddRange(QueryResultCollection collection)
+ {
+ lock (this._root) this._collection.AddRange(collection);
+ }
+
+ public override void AddRange(QueryResult[] array)
+ {
+ lock (this._root) this._collection.AddRange(array);
+ }
+
+ public override int BinarySearch(QueryResult value)
+ {
+ lock (this._root) return this._collection.BinarySearch(value);
+ }
+
+ public override void Clear()
+ {
+ lock (this._root) this._collection.Clear();
+ }
+
+ public override object Clone()
+ {
+ lock (this._root)
+ return new SyncList((QueryResultCollection) this._collection.Clone());
+ }
+
+ public override void CopyTo(QueryResult[] array)
+ {
+ lock (this._root) this._collection.CopyTo(array);
+ }
+
+ public override void CopyTo(QueryResult[] array, int arrayIndex)
+ {
+ lock (this._root) this._collection.CopyTo(array, arrayIndex);
+ }
+
+ public override IQueryResultEnumerator GetEnumerator()
+ {
+ lock (this._root) return this._collection.GetEnumerator();
+ }
+
+ public override int IndexOf(QueryResult value)
+ {
+ lock (this._root) return this._collection.IndexOf(value);
+ }
+
+ public override void Insert(int index, QueryResult value)
+ {
+ lock (this._root) this._collection.Insert(index, value);
+ }
+
+ public override void Remove(QueryResult value)
+ {
+ lock (this._root) this._collection.Remove(value);
+ }
+
+ public override void RemoveAt(int index)
+ {
+ lock (this._root) this._collection.RemoveAt(index);
+ }
+
+ public override void RemoveRange(int index, int count)
+ {
+ lock (this._root) this._collection.RemoveRange(index, count);
+ }
+
+ public override void Reverse()
+ {
+ lock (this._root) this._collection.Reverse();
+ }
+
+ public override void Reverse(int index, int count)
+ {
+ lock (this._root) this._collection.Reverse(index, count);
+ }
+
+ public override void Sort()
+ {
+ lock (this._root) this._collection.Sort();
+ }
+
+ public override void Sort(IComparer comparer)
+ {
+ lock (this._root) this._collection.Sort(comparer);
+ }
+
+ public override void Sort(int index, int count, IComparer comparer)
+ {
+ lock (this._root) this._collection.Sort(index, count, comparer);
+ }
+
+ public override QueryResult[] ToArray()
+ {
+ lock (this._root) return this._collection.ToArray();
+ }
+
+ public override void TrimToSize()
+ {
+ lock (this._root) this._collection.TrimToSize();
+ }
+
+ #endregion
+ }
+
+ #endregion
+ #region Class UniqueList
+
+ [Serializable]
+ private sealed class UniqueList: QueryResultCollection
+ {
+ #region Private Fields
+
+ private QueryResultCollection _collection;
+
+ #endregion
+ #region Internal Constructors
+
+ internal UniqueList(QueryResultCollection collection):
+ base(Tag.Default)
+ {
+ this._collection = collection;
+ }
+
+ #endregion
+ #region Protected Properties
+
+ protected override QueryResult[] InnerArray
+ {
+ get { return this._collection.InnerArray; }
+ }
+
+ #endregion
+ #region Public Properties
+
+ public override int Capacity
+ {
+ get { return this._collection.Capacity; }
+ set { this._collection.Capacity = value; }
+ }
+
+ public override int Count
+ {
+ get { return this._collection.Count; }
+ }
+
+ public override bool IsFixedSize
+ {
+ get { return this._collection.IsFixedSize; }
+ }
+
+ public override bool IsReadOnly
+ {
+ get { return this._collection.IsReadOnly; }
+ }
+
+ public override bool IsSynchronized
+ {
+ get { return this._collection.IsSynchronized; }
+ }
+
+ public override bool IsUnique
+ {
+ get { return true; }
+ }
+
+ public override QueryResult this[int index]
+ {
+ get { return this._collection[index]; }
+ set
+ {
+ CheckUnique(index, value);
+ this._collection[index] = value;
+ }
+ }
+
+ public override object SyncRoot
+ {
+ get { return this._collection.SyncRoot; }
+ }
+
+ #endregion
+ #region Public Methods
+
+ public override int Add(QueryResult value)
+ {
+ CheckUnique(value);
+ return this._collection.Add(value);
+ }
+
+ public override void AddRange(QueryResultCollection collection)
+ {
+ foreach (QueryResult value in collection)
+ CheckUnique(value);
+
+ this._collection.AddRange(collection);
+ }
+
+ public override void AddRange(QueryResult[] array)
+ {
+ foreach (QueryResult value in array)
+ CheckUnique(value);
+
+ this._collection.AddRange(array);
+ }
+
+ public override int BinarySearch(QueryResult value)
+ {
+ return this._collection.BinarySearch(value);
+ }
+
+ public override void Clear()
+ {
+ this._collection.Clear();
+ }
+
+ public override object Clone()
+ {
+ return new UniqueList((QueryResultCollection) this._collection.Clone());
+ }
+
+ public override void CopyTo(QueryResult[] array)
+ {
+ this._collection.CopyTo(array);
+ }
+
+ public override void CopyTo(QueryResult[] array, int arrayIndex)
+ {
+ this._collection.CopyTo(array, arrayIndex);
+ }
+
+ public override IQueryResultEnumerator GetEnumerator()
+ {
+ return this._collection.GetEnumerator();
+ }
+
+ public override int IndexOf(QueryResult value)
+ {
+ return this._collection.IndexOf(value);
+ }
+
+ public override void Insert(int index, QueryResult value)
+ {
+ CheckUnique(value);
+ this._collection.Insert(index, value);
+ }
+
+ public override void Remove(QueryResult value)
+ {
+ this._collection.Remove(value);
+ }
+
+ public override void RemoveAt(int index)
+ {
+ this._collection.RemoveAt(index);
+ }
+
+ public override void RemoveRange(int index, int count)
+ {
+ this._collection.RemoveRange(index, count);
+ }
+
+ public override void Reverse()
+ {
+ this._collection.Reverse();
+ }
+
+ public override void Reverse(int index, int count)
+ {
+ this._collection.Reverse(index, count);
+ }
+
+ public override void Sort()
+ {
+ this._collection.Sort();
+ }
+
+ public override void Sort(IComparer comparer)
+ {
+ this._collection.Sort(comparer);
+ }
+
+ public override void Sort(int index, int count, IComparer comparer)
+ {
+ this._collection.Sort(index, count, comparer);
+ }
+
+ public override QueryResult[] ToArray()
+ {
+ return this._collection.ToArray();
+ }
+
+ public override void TrimToSize()
+ {
+ this._collection.TrimToSize();
+ }
+
+ #endregion
+ #region Private Methods
+
+ private void CheckUnique(QueryResult value)
+ {
+ if (IndexOf(value) >= 0)
+ throw new NotSupportedException(
+ "Unique collections cannot contain duplicate elements.");
+ }
+
+ private void CheckUnique(int index, QueryResult value)
+ {
+ int existing = IndexOf(value);
+ if (existing >= 0 && existing != index)
+ throw new NotSupportedException(
+ "Unique collections cannot contain duplicate elements.");
+ }
+
+ #endregion
+ }
+
+ #endregion
+ }
+
+ #endregion
+}
diff --git a/Freedb/Site.cs b/Freedb/Site.cs
new file mode 100644
index 0000000..7b2b137
--- /dev/null
+++ b/Freedb/Site.cs
@@ -0,0 +1,237 @@
+#region COPYRIGHT (c) 2004 by Brian Weeres
+/* Copyright (c) 2004 by Brian Weeres
+ *
+ * Email: bweeres@protegra.com; bweeres@hotmail.com
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * If you modify it then please indicate so.
+ *
+ * The software is provided "AS IS" and there are no warranties or implied warranties.
+ * In no event shall Brian Weeres and/or Protegra Technology Group be liable for any special,
+ * direct, indirect, or consequential damages or any damages whatsoever resulting for any reason
+ * out of the use or performance of this software
+ *
+ */
+#endregion
+using System;
+
+namespace Freedb
+{
+ ///
+ /// Summary description for Site.
+ ///
+ public class Site
+ {
+ private string m_SiteAddress;
+ private string m_Protocol;
+ private string m_AdditionalAddressInfo;
+ private string m_Port;
+ private string m_Latitude;
+ private string m_Longitude;
+ private string m_Description;
+
+
+ public class PROTOCOLS
+ {
+ public const string HTTP = "http";
+ public const string CDDBP = "cddbp";
+ public const string ALL = "all";
+ }
+
+
+ ///
+ /// Property AdditionalAddressInfo (string)
+ /// Any additional addressing information needed to access the server.
+ /// For example, for HTTP protocol servers, this would be the path to the CCDB server CGI script.
+ /// This field will be "-" if no additional addressing information is needed.
+ ///
+ public string AdditionalAddressInfo
+ {
+ get
+ {
+ return this.m_AdditionalAddressInfo;
+ }
+ set
+ {
+ this.m_AdditionalAddressInfo = value;
+ }
+ }
+
+
+ #region Public Properties
+
+ ///
+ /// Property Site (string) - Internet address of the remote site
+ ///
+ public string SiteAddress
+ {
+ get
+ {
+ return this.m_SiteAddress;
+ }
+ set
+ {
+ this.m_SiteAddress = value;
+ }
+ }
+
+ ///
+ /// Property Protocol (string)
+ /// The transfer protocol used to access the site
+ ///
+ public string Protocol
+ {
+ get
+ {
+ return this.m_Protocol;
+ }
+ set
+ {
+ this.m_Protocol = value;
+ }
+ }
+
+ ///
+ /// Property Port (string)- The port at which the server resides on that site.
+ ///
+ public string Port
+ {
+ get
+ {
+ return this.m_Port;
+ }
+ set
+ {
+ this.m_Port = value;
+ }
+ }
+
+
+
+ ///
+ /// Property Description (string)
+ /// A short description of the geographical location of the site.
+ ///
+ public string Description
+ {
+ get
+ {
+ return this.m_Description;
+ }
+ set
+ {
+ this.m_Description = value;
+ }
+ }
+
+
+ ///
+ /// Property Latitude (string)
+ /// The latitude of the server site. The format is as follows:
+ /// CDDD.MM
+ /// Where "C" is the compass direction (N, S), "DDD" is the
+ /// degrees, and "MM" is the minutes.
+ ///
+ public string Latitude
+ {
+ get
+ {
+ return this.m_Latitude;
+ }
+ set
+ {
+ this.m_Latitude = value;
+ }
+ }
+
+ ///
+ /// Property Longitude (string)
+ /// The longitude of the server site. Format is as above, except
+ /// the compass direction must be one of (E, W).
+ ///
+ public string Longitude
+ {
+ get
+ {
+ return this.m_Longitude;
+ }
+ set
+ {
+ this.m_Longitude = value;
+ }
+ }
+
+
+ #endregion
+
+
+ public Site(string siteFromCDDB)
+ {
+ if (!Parse(siteFromCDDB))
+ {
+ throw new Exception("Unable to Parse Site. Input: " + siteFromCDDB);
+ }
+ }
+
+
+ ///
+ /// Builds a site from an address, protocol and addition info
+ ///
+ ///
+ ///
+ ///
+ public Site(string siteAddress, string protocol, string additionAddressInfo)
+ {
+ m_SiteAddress = siteAddress;
+ m_Protocol = protocol;
+ m_AdditionalAddressInfo = additionAddressInfo;
+ }
+
+
+
+ public bool Parse(string siteAsString)
+ {
+ siteAsString.Trim();
+ string [] values = siteAsString.Split(' ');
+ if (values.Length <5)
+ return false;
+ m_SiteAddress = values[0];
+ this.m_Protocol = values[1];
+ m_Port = values[2];
+ if (values[3].Trim() != "-")
+ m_AdditionalAddressInfo = values[3];
+ m_Latitude = values[4];
+ m_Longitude = values[5];
+
+ // description could be split over many because it could have spaces
+ for (int i= 6; i < values.Length;i++)
+ {
+ m_Description += values[i];
+ m_Description += " ";
+
+ }
+ m_Description.Trim();
+ return true;
+ }
+
+ public string GetUrl()
+ {
+
+ if (this.m_Protocol == Site.PROTOCOLS.HTTP)
+ return "http://" + this.m_SiteAddress + this.m_AdditionalAddressInfo;
+ else
+ return this.m_SiteAddress;
+ }
+
+ public override string ToString()
+ {
+ return m_SiteAddress + ", " + this.m_Description;
+ }
+
+
+
+ }
+}
diff --git a/Freedb/SiteCollection.cs b/Freedb/SiteCollection.cs
new file mode 100644
index 0000000..f2115b0
--- /dev/null
+++ b/Freedb/SiteCollection.cs
@@ -0,0 +1,2378 @@
+#region COPYRIGHT (c) 2004 by Brian Weeres
+/* Copyright (c) 2004 by Brian Weeres
+ *
+ * Email: bweeres@protegra.com; bweeres@hotmail.com
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * If you modify it then please indicate so.
+ *
+ * The software is provided "AS IS" and there are no warranties or implied warranties.
+ * In no event shall Brian Weeres and/or Protegra Technology Group be liable for any special,
+ * direct, indirect, or consequential damages or any damages whatsoever resulting for any reason
+ * out of the use or performance of this software
+ *
+ */
+#endregion
+using System;
+using System.Collections;
+using Freedb;
+
+namespace Freedb
+{
+ #region Interface ISiteCollection
+
+ ///
+ /// Defines size, enumerators, and synchronization methods for strongly
+ /// typed collections of elements.
+ ///
+ ///
+ /// ISiteCollection provides an
+ /// that is strongly typed for elements.
+ ///
+
+ public interface ISiteCollection
+ {
+ #region Properties
+ #region Count
+
+ ///
+ /// Gets the number of elements contained in the
+ /// .
+ ///
+ /// The number of elements contained in the
+ /// .
+ /// Please refer to for details.
+
+ int Count { get; }
+
+ #endregion
+ #region IsSynchronized
+
+ ///
+ /// Gets a value indicating whether access to the
+ /// is synchronized (thread-safe).
+ ///
+ /// true if access to the is
+ /// synchronized (thread-safe); otherwise, false. The default is false.
+ /// Please refer to for details.
+
+ bool IsSynchronized { get; }
+
+ #endregion
+ #region SyncRoot
+
+ ///
+ /// Gets an object that can be used to synchronize access
+ /// to the .
+ ///
+ /// An object that can be used to synchronize access
+ /// to the .
+ /// Please refer to for details.
+
+ object SyncRoot { get; }
+
+ #endregion
+ #endregion
+ #region Methods
+ #region CopyTo
+
+ ///
+ /// Copies the entire to a one-dimensional
+ /// of elements, starting at the specified index of the target array.
+ ///
+ /// The one-dimensional that is the destination of the
+ /// elements copied from the .
+ /// The Array must have zero-based indexing.
+ /// The zero-based index in
+ /// at which copying begins.
+ ///
+ /// is a null reference.
+ ///
+ /// is less than zero.
+ ///
+ /// is equal to or greater than the length of .
+ /// -or-
+ /// The number of elements in the source is greater
+ /// than the available space from to the end of the destination
+ /// .
+ /// Please refer to for details.
+
+ void CopyTo(Site[] array, int arrayIndex);
+
+ #endregion
+ #region GetEnumerator
+
+ ///
+ /// Returns an that can
+ /// iterate through the .
+ ///
+ /// An
+ /// for the entire .
+ /// Please refer to for details.
+
+ ISiteEnumerator GetEnumerator();
+
+ #endregion
+ #endregion
+ }
+
+ #endregion
+ #region Interface ISiteList
+
+ ///
+ /// Represents a strongly typed collection of
+ /// objects that can be individually accessed by index.
+ ///
+ ///
+ /// ISiteList provides an
+ /// that is strongly typed for elements.
+ ///
+
+ public interface
+ ISiteList: ISiteCollection
+ {
+ #region Properties
+ #region IsFixedSize
+
+ ///
+ /// Gets a value indicating whether the has a fixed size.
+ ///
+ /// true if the has a fixed size;
+ /// otherwise, false. The default is false.
+ /// Please refer to for details.
+
+ bool IsFixedSize { get; }
+
+ #endregion
+ #region IsReadOnly
+
+ ///
+ /// Gets a value indicating whether the is read-only.
+ ///
+ /// true if the is read-only;
+ /// otherwise, false. The default is false.
+ /// Please refer to for details.
+
+ bool IsReadOnly { get; }
+
+ #endregion
+ #region Item
+
+ ///
+ /// Gets or sets the element at the specified index.
+ ///
+ /// The zero-based index of the
+ /// element to get or set.
+ ///
+ /// The element at the specified .
+ ///
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is equal to or greater than
+ /// .
+ ///
+ ///
+ /// The property is set and the is read-only.
+ /// Please refer to for details.
+
+ Site this[int index] { get; set; }
+
+ #endregion
+ #endregion
+ #region Methods
+ #region Add
+
+ ///
+ /// Adds a to the end
+ /// of the .
+ ///
+ /// The object
+ /// to be added to the end of the .
+ /// This argument can be a null reference.
+ ///
+ /// The index at which
+ /// the has been added.
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The ISiteList has a fixed size.
+ /// Please refer to for details.
+
+ int Add(Site value);
+
+ #endregion
+ #region Clear
+
+ ///
+ /// Removes all elements from the .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The ISiteList has a fixed size.
+ /// Please refer to for details.
+
+ void Clear();
+
+ #endregion
+ #region Contains
+
+ ///
+ /// Determines whether the
+ /// contains the specified element.
+ ///
+ /// The object
+ /// to locate in the .
+ /// This argument can be a null reference.
+ ///
+ /// true if is found in the
+ /// ; otherwise, false.
+ /// Please refer to for details.
+
+ bool Contains(Site value);
+
+ #endregion
+ #region IndexOf
+
+ ///
+ /// Returns the zero-based index of the first occurrence of the specified
+ /// in the .
+ ///
+ /// The object
+ /// to locate in the .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// The zero-based index of the first occurrence of
+ /// in the , if found; otherwise, -1.
+ ///
+ /// Please refer to for details.
+
+ int IndexOf(Site value);
+
+ #endregion
+ #region Insert
+
+ ///
+ /// Inserts a element into the
+ /// at the specified index.
+ ///
+ /// The zero-based index at which
+ /// should be inserted.
+ /// The object
+ /// to insert into the .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is greater than
+ /// .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The ISiteList has a fixed size.
+ /// Please refer to for details.
+
+ void Insert(int index, Site value);
+
+ #endregion
+ #region Remove
+
+ ///
+ /// Removes the first occurrence of the specified
+ /// from the .
+ ///
+ /// The object
+ /// to remove from the .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The ISiteList has a fixed size.
+ /// Please refer to for details.
+
+ void Remove(Site value);
+
+ #endregion
+ #region RemoveAt
+
+ ///
+ /// Removes the element at the specified index of the
+ /// .
+ ///
+ /// The zero-based index of the element to remove.
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is equal to or greater than
+ /// .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The ISiteList has a fixed size.
+ /// Please refer to for details.
+
+ void RemoveAt(int index);
+
+ #endregion
+ #endregion
+ }
+
+ #endregion
+ #region Interface ISiteEnumerator
+
+ ///
+ /// Supports type-safe iteration over a collection that
+ /// contains elements.
+ ///
+ ///
+ /// ISiteEnumerator provides an
+ /// that is strongly typed for elements.
+ ///
+
+ public interface ISiteEnumerator
+ {
+ #region Properties
+ #region Current
+
+ ///
+ /// Gets the current element in the collection.
+ ///
+ /// The current element in the collection.
+ /// The enumerator is positioned
+ /// before the first element of the collection or after the last element.
+ /// -or-
+ /// The collection was modified after the enumerator was created.
+ /// Please refer to for details, but note
+ /// that Current fails if the collection was modified since the last successful
+ /// call to or .
+
+ Site Current { get; }
+
+ #endregion
+ #endregion
+ #region Methods
+ #region MoveNext
+
+ ///
+ /// Advances the enumerator to the next element of the collection.
+ ///
+ /// true if the enumerator was successfully advanced to the next element;
+ /// false if the enumerator has passed the end of the collection.
+ ///
+ /// The collection was modified after the enumerator was created.
+ /// Please refer to for details.
+
+ bool MoveNext();
+
+ #endregion
+ #region Reset
+
+ ///
+ /// Sets the enumerator to its initial position,
+ /// which is before the first element in the collection.
+ ///
+ ///
+ /// The collection was modified after the enumerator was created.
+ /// Please refer to for details.
+
+ void Reset();
+
+ #endregion
+ #endregion
+ }
+
+ #endregion
+ #region Class SiteCollection
+
+ ///
+ /// Implements a strongly typed collection of elements.
+ ///
+ ///
+ /// SiteCollection provides an
+ /// that is strongly typed for elements.
+ ///
+
+ [Serializable]
+ public class SiteCollection:
+ ISiteList, IList, ICloneable
+ {
+ #region Private Fields
+
+ private const int _defaultCapacity = 16;
+
+ private Site[] _array = null;
+ private int _count = 0;
+
+ [NonSerialized]
+ private int _version = 0;
+
+ #endregion
+ #region Private Constructors
+
+ // helper type to identify private ctor
+ private enum Tag { Default }
+
+ private SiteCollection(Tag tag) { }
+
+ #endregion
+ #region Public Constructors
+ #region SiteCollection()
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// Initializes a new instance of the class
+ /// that is empty and has the default initial capacity.
+ ///
+ /// Please refer to for details.
+
+ public SiteCollection()
+ {
+ this._array = new Site[_defaultCapacity];
+ }
+
+ #endregion
+ #region SiteCollection(Int32)
+
+ ///
+ /// Initializes a new instance of the class
+ /// that is empty and has the specified initial capacity.
+ ///
+ /// The number of elements that the new
+ /// is initially capable of storing.
+ ///
+ /// is less than zero.
+ /// Please refer to for details.
+
+ public SiteCollection(int capacity)
+ {
+ if (capacity < 0)
+ throw new ArgumentOutOfRangeException("capacity",
+ capacity, "Argument cannot be negative.");
+
+ this._array = new Site[capacity];
+ }
+
+ #endregion
+ #region SiteCollection(SiteCollection)
+
+ ///
+ /// Initializes a new instance of the class
+ /// that contains elements copied from the specified collection and
+ /// that has the same initial capacity as the number of elements copied.
+ ///
+ /// The
+ /// whose elements are copied to the new collection.
+ ///
+ /// is a null reference.
+ /// Please refer to for details.
+
+ public SiteCollection(SiteCollection collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException("collection");
+
+ this._array = new Site[collection.Count];
+ AddRange(collection);
+ }
+
+ #endregion
+ #region SiteCollection(Site[])
+
+ ///
+ /// Initializes a new instance of the class
+ /// that contains elements copied from the specified
+ /// array and that has the same initial capacity as the number of elements copied.
+ ///
+ /// An of
+ /// elements that are copied to the new collection.
+ ///
+ /// is a null reference.
+ /// Please refer to for details.
+
+ public SiteCollection(Site[] array)
+ {
+ if (array == null)
+ throw new ArgumentNullException("array");
+
+ this._array = new Site[array.Length];
+ AddRange(array);
+ }
+
+ #endregion
+ #endregion
+ #region Protected Properties
+ #region InnerArray
+
+ ///
+ /// Gets the list of elements contained in the instance.
+ ///
+ ///
+ /// A one-dimensional with zero-based indexing that contains all
+ /// elements in the .
+ ///
+ ///
+ /// Use InnerArray to access the element array of a
+ /// instance that might be a read-only or synchronized wrapper. This is necessary because
+ /// the element array field of wrapper classes is always a null reference.
+ ///
+
+ protected virtual Site[] InnerArray
+ {
+ get { return this._array; }
+ }
+
+ #endregion
+ #endregion
+ #region Public Properties
+ #region Capacity
+
+ ///
+ /// Gets or sets the capacity of the .
+ ///
+ /// The number of elements that the
+ /// can contain.
+ ///
+ /// Capacity is set to a value that is less than .
+ /// Please refer to for details.
+
+ public virtual int Capacity
+ {
+ get { return this._array.Length; }
+ set
+ {
+ if (value == this._array.Length) return;
+
+ if (value < this._count)
+ throw new ArgumentOutOfRangeException("Capacity",
+ value, "Value cannot be less than Count.");
+
+ if (value == 0)
+ {
+ this._array = new Site[_defaultCapacity];
+ return;
+ }
+
+ Site[] newArray = new Site[value];
+ Array.Copy(this._array, newArray, this._count);
+ this._array = newArray;
+ }
+ }
+
+ #endregion
+ #region Count
+
+ ///
+ /// Gets the number of elements contained in the .
+ ///
+ ///
+ /// The number of elements contained in the .
+ ///
+ /// Please refer to for details.
+
+ public virtual int Count
+ {
+ get { return this._count; }
+ }
+
+ #endregion
+ #region IsFixedSize
+
+ ///
+ /// Gets a value indicating whether the has a fixed size.
+ ///
+ /// true if the has a fixed size;
+ /// otherwise, false. The default is false.
+ /// Please refer to for details.
+
+ public virtual bool IsFixedSize
+ {
+ get { return false; }
+ }
+
+ #endregion
+ #region IsReadOnly
+
+ ///
+ /// Gets a value indicating whether the is read-only.
+ ///
+ /// true if the is read-only;
+ /// otherwise, false. The default is false.
+ /// Please refer to for details.
+
+ public virtual bool IsReadOnly
+ {
+ get { return false; }
+ }
+
+ #endregion
+ #region IsSynchronized
+
+ ///
+ /// Gets a value indicating whether access to the
+ /// is synchronized (thread-safe).
+ ///
+ /// true if access to the is
+ /// synchronized (thread-safe); otherwise, false. The default is false.
+ /// Please refer to for details.
+
+ public virtual bool IsSynchronized
+ {
+ get { return false; }
+ }
+
+ #endregion
+ #region IsUnique
+
+ ///
+ /// Gets a value indicating whether the
+ /// ensures that all elements are unique.
+ ///
+ ///
+ /// true if the ensures that all
+ /// elements are unique; otherwise, false. The default is false.
+ ///
+ ///
+ /// IsUnique returns true exactly if the
+ /// is exposed through a wrapper.
+ /// Please refer to for details.
+ ///
+
+ public virtual bool IsUnique
+ {
+ get { return false; }
+ }
+
+ #endregion
+ #region Item: Site
+
+ ///
+ /// Gets or sets the element at the specified index.
+ ///
+ /// The zero-based index of the
+ /// element to get or set.
+ ///
+ /// The element at the specified .
+ ///
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is equal to or greater than .
+ ///
+ ///
+ /// The property is set and the is read-only.
+ /// -or-
+ /// The property is set, the SiteCollection already contains the
+ /// specified element at a different index, and the SiteCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ public virtual Site this[int index]
+ {
+ get
+ {
+ ValidateIndex(index);
+ return this._array[index];
+ }
+ set
+ {
+ ValidateIndex(index);
+ ++this._version;
+ this._array[index] = value;
+ }
+ }
+
+ #endregion
+ #region IList.Item: Object
+
+ ///
+ /// Gets or sets the element at the specified index.
+ ///
+ /// The zero-based index of the element to get or set.
+ ///
+ /// The element at the specified . When the property
+ /// is set, this value must be compatible with .
+ ///
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is equal to or greater than .
+ ///
+ /// The property is set to a value
+ /// that is not compatible with .
+ ///
+ /// The property is set and the is read-only.
+ /// -or-
+ /// The property is set, the SiteCollection already contains the
+ /// specified element at a different index, and the SiteCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ object IList.this[int index]
+ {
+ get { return this[index]; }
+ set { this[index] = (Site) value; }
+ }
+
+ #endregion
+ #region SyncRoot
+
+ ///
+ /// Gets an object that can be used to synchronize
+ /// access to the .
+ ///
+ /// An object that can be used to synchronize
+ /// access to the .
+ ///
+ /// Please refer to for details.
+
+ public virtual object SyncRoot
+ {
+ get { return this; }
+ }
+
+ #endregion
+ #endregion
+ #region Public Methods
+ #region Add(Site)
+
+ ///
+ /// Adds a to the end of the .
+ ///
+ /// The object
+ /// to be added to the end of the .
+ /// This argument can be a null reference.
+ ///
+ /// The index at which the
+ /// has been added.
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The SiteCollection has a fixed size.
+ /// -or-
+ /// The SiteCollection already contains the specified
+ /// , and the SiteCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ public virtual int Add(Site value)
+ {
+ if (this._count == this._array.Length)
+ EnsureCapacity(this._count + 1);
+
+ ++this._version;
+ this._array[this._count] = value;
+ return this._count++;
+ }
+
+ #endregion
+ #region IList.Add(Object)
+
+ ///
+ /// Adds an to the end of the .
+ ///
+ ///
+ /// The object to be added to the end of the .
+ /// This argument must be compatible with .
+ /// This argument can be a null reference.
+ ///
+ /// The index at which the
+ /// has been added.
+ ///
+ /// is not compatible with .
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The SiteCollection has a fixed size.
+ /// -or-
+ /// The SiteCollection already contains the specified
+ /// , and the SiteCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ int IList.Add(object value)
+ {
+ return Add((Site) value);
+ }
+
+ #endregion
+ #region AddRange(SiteCollection)
+
+ ///
+ /// Adds a range of elements to the end of the .
+ ///
+ ///
+ /// Adds the elements of another collection to the end of the .
+ ///
+ /// The whose elements
+ /// should be added to the end of the current collection.
+ ///
+ /// is a null reference.
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The SiteCollection has a fixed size.
+ /// -or-
+ /// The SiteCollection already contains one or more elements
+ /// in the specified , and the SiteCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ public virtual void AddRange(SiteCollection collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException("collection");
+
+ if (collection.Count == 0) return;
+ if (this._count + collection.Count > this._array.Length)
+ EnsureCapacity(this._count + collection.Count);
+
+ ++this._version;
+ Array.Copy(collection.InnerArray, 0,
+ this._array, this._count, collection.Count);
+ this._count += collection.Count;
+ }
+
+ #endregion
+ #region AddRange(Site[])
+
+ ///
+ /// Adds the elements of a array
+ /// to the end of the .
+ ///
+ /// An of elements
+ /// that should be added to the end of the .
+ ///
+ /// is a null reference.
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The SiteCollection has a fixed size.
+ /// -or-
+ /// The SiteCollection already contains one or more elements
+ /// in the specified , and the SiteCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ public virtual void AddRange(Site[] array)
+ {
+ if (array == null)
+ throw new ArgumentNullException("array");
+
+ if (array.Length == 0) return;
+ if (this._count + array.Length > this._array.Length)
+ EnsureCapacity(this._count + array.Length);
+
+ ++this._version;
+ Array.Copy(array, 0, this._array, this._count, array.Length);
+ this._count += array.Length;
+ }
+
+ #endregion
+ #region BinarySearch
+
+ ///
+ /// Searches the entire sorted for an
+ /// element using the default comparer
+ /// and returns the zero-based index of the element.
+ ///
+ /// The object
+ /// to locate in the .
+ /// This argument can be a null reference.
+ ///
+ /// The zero-based index of in the sorted
+ /// , if is found;
+ /// otherwise, a negative number, which is the bitwise complement of the index
+ /// of the next element that is larger than or, if there
+ /// is no larger element, the bitwise complement of .
+ ///
+ /// Neither nor the elements of the
+ /// implement the interface.
+ /// Please refer to for details.
+
+ public virtual int BinarySearch(Site value)
+ {
+ return Array.BinarySearch(this._array, 0, this._count, value);
+ }
+
+ #endregion
+ #region Clear
+
+ ///
+ /// Removes all elements from the .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The SiteCollection has a fixed size.
+ /// Please refer to for details.
+
+ public virtual void Clear()
+ {
+ if (this._count == 0) return;
+
+ ++this._version;
+ Array.Clear(this._array, 0, this._count);
+ this._count = 0;
+ }
+
+ #endregion
+ #region Clone
+
+ ///
+ /// Creates a shallow copy of the .
+ ///
+ /// A shallow copy of the .
+ /// Please refer to for details.
+
+ public virtual object Clone()
+ {
+ SiteCollection collection = new SiteCollection(this._count);
+
+ Array.Copy(this._array, 0, collection._array, 0, this._count);
+ collection._count = this._count;
+ collection._version = this._version;
+
+ return collection;
+ }
+
+ #endregion
+ #region Contains(Site)
+
+ ///
+ /// Determines whether the
+ /// contains the specified element.
+ ///
+ /// The object
+ /// to locate in the .
+ /// This argument can be a null reference.
+ ///
+ /// true if is found in the
+ /// ; otherwise, false.
+ /// Please refer to for details.
+
+ public bool Contains(Site value)
+ {
+ return (IndexOf(value) >= 0);
+ }
+
+ #endregion
+ #region IList.Contains(Object)
+
+ ///
+ /// Determines whether the contains the specified element.
+ ///
+ /// The object to locate in the .
+ /// This argument must be compatible with .
+ /// This argument can be a null reference.
+ ///
+ /// true if is found in the
+ /// ; otherwise, false.
+ ///
+ /// is not compatible with .
+ /// Please refer to for details.
+
+ bool IList.Contains(object value)
+ {
+ return Contains((Site) value);
+ }
+
+ #endregion
+ #region CopyTo(Site[])
+
+ ///
+ /// Copies the or a portion of it to a one-dimensional array.
+ ///
+ ///
+ /// Copies the entire to a one-dimensional
+ /// of elements, starting at the beginning of the target array.
+ ///
+ /// The one-dimensional that is the destination of the
+ /// elements copied from the .
+ /// The Array must have zero-based indexing.
+ ///
+ /// is a null reference.
+ ///
+ /// The number of elements in the source is greater
+ /// than the available space in the destination .
+ /// Please refer to for details.
+
+ public virtual void CopyTo(Site[] array)
+ {
+ CheckTargetArray(array, 0);
+ Array.Copy(this._array, array, this._count);
+ }
+
+ #endregion
+ #region CopyTo(Site[], Int32)
+
+ ///
+ /// Copies the entire to a one-dimensional
+ /// of elements, starting at the specified index of the target array.
+ ///
+ /// The one-dimensional that is the destination of the
+ /// elements copied from the .
+ /// The Array must have zero-based indexing.
+ /// The zero-based index in
+ /// at which copying begins.
+ ///
+ /// is a null reference.
+ ///
+ /// is less than zero.
+ ///
+ /// is equal to or greater than the length of .
+ /// -or-
+ /// The number of elements in the source is greater than the
+ /// available space from to the end of the destination
+ /// .
+ /// Please refer to for details.
+
+ public virtual void CopyTo(Site[] array, int arrayIndex)
+ {
+ CheckTargetArray(array, arrayIndex);
+ Array.Copy(this._array, 0, array, arrayIndex, this._count);
+ }
+
+ #endregion
+ #region ICollection.CopyTo(Array, Int32)
+
+ ///
+ /// Copies the entire to a one-dimensional ,
+ /// starting at the specified index of the target array.
+ ///
+ /// The one-dimensional that is the destination of the
+ /// elements copied from the .
+ /// The Array must have zero-based indexing.
+ /// The zero-based index in
+ /// at which copying begins.
+ ///
+ /// is a null reference.
+ ///
+ /// is less than zero.
+ ///
+ /// is multidimensional.
+ /// -or-
+ /// is equal to or greater than the length of .
+ /// -or-
+ /// The number of elements in the source is greater than the
+ /// available space from to the end of the destination
+ /// .
+ ///
+ /// The type cannot be cast automatically
+ /// to the type of the destination .
+ /// Please refer to for details.
+
+ void ICollection.CopyTo(Array array, int arrayIndex)
+ {
+ CopyTo((Site[]) array, arrayIndex);
+ }
+
+ #endregion
+ #region GetEnumerator: ISiteEnumerator
+
+ ///
+ /// Returns an that can
+ /// iterate through the .
+ ///
+ /// An
+ /// for the entire .
+ /// Please refer to for details.
+
+ public virtual ISiteEnumerator GetEnumerator()
+ {
+ return new Enumerator(this);
+ }
+
+ #endregion
+ #region IEnumerable.GetEnumerator: IEnumerator
+
+ ///
+ /// Returns an that can
+ /// iterate through the .
+ ///
+ /// An
+ /// for the entire .
+ /// Please refer to for details.
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return (IEnumerator) GetEnumerator();
+ }
+
+ #endregion
+ #region IndexOf(Site)
+
+ ///
+ /// Returns the zero-based index of the first occurrence of the specified
+ /// in the .
+ ///
+ /// The object
+ /// to locate in the .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// The zero-based index of the first occurrence of
+ /// in the , if found; otherwise, -1.
+ ///
+ /// Please refer to for details.
+
+ public virtual int IndexOf(Site value)
+ {
+ return Array.IndexOf(this._array, value, 0, this._count);
+ }
+
+ #endregion
+ #region IList.IndexOf(Object)
+
+ ///
+ /// Returns the zero-based index of the first occurrence of the specified
+ /// in the .
+ ///
+ /// The object to locate in the .
+ /// This argument must be compatible with .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// The zero-based index of the first occurrence of
+ /// in the , if found; otherwise, -1.
+ ///
+ ///
+ /// is not compatible with .
+ /// Please refer to for details.
+
+ int IList.IndexOf(object value)
+ {
+ return IndexOf((Site) value);
+ }
+
+ #endregion
+ #region Insert(Int32, Site)
+
+ ///
+ /// Inserts a element into the
+ /// at the specified index.
+ ///
+ /// The zero-based index at which
+ /// should be inserted.
+ /// The object
+ /// to insert into the .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is greater than .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The SiteCollection has a fixed size.
+ /// -or-
+ /// The SiteCollection already contains the specified
+ /// , and the SiteCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ public virtual void Insert(int index, Site value)
+ {
+ if (index < 0)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument cannot be negative.");
+
+ if (index > this._count)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument cannot exceed Count.");
+
+ if (this._count == this._array.Length)
+ EnsureCapacity(this._count + 1);
+
+ ++this._version;
+ if (index < this._count)
+ Array.Copy(this._array, index,
+ this._array, index + 1, this._count - index);
+
+ this._array[index] = value;
+ ++this._count;
+ }
+
+ #endregion
+ #region IList.Insert(Int32, Object)
+
+ ///
+ /// Inserts an element into the at the specified index.
+ ///
+ /// The zero-based index at which
+ /// should be inserted.
+ /// The object to insert into the .
+ /// This argument must be compatible with .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is greater than .
+ ///
+ ///
+ /// is not compatible with .
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The SiteCollection has a fixed size.
+ /// -or-
+ /// The SiteCollection already contains the specified
+ /// , and the SiteCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ void IList.Insert(int index, object value)
+ {
+ Insert(index, (Site) value);
+ }
+
+ #endregion
+ #region ReadOnly
+
+ ///
+ /// Returns a read-only wrapper for the specified .
+ ///
+ /// The to wrap.
+ /// A read-only wrapper around .
+ ///
+ /// is a null reference.
+ /// Please refer to for details.
+
+ public static SiteCollection ReadOnly(SiteCollection collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException("collection");
+
+ return new ReadOnlyList(collection);
+ }
+
+ #endregion
+ #region Remove(Site)
+
+ ///
+ /// Removes the first occurrence of the specified
+ /// from the .
+ ///
+ /// The object
+ /// to remove from the .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The SiteCollection has a fixed size.
+ /// Please refer to for details.
+
+ public virtual void Remove(Site value)
+ {
+ int index = IndexOf(value);
+ if (index >= 0) RemoveAt(index);
+ }
+
+ #endregion
+ #region IList.Remove(Object)
+
+ ///
+ /// Removes the first occurrence of the specified
+ /// from the .
+ ///
+ /// The object to remove from the .
+ /// This argument must be compatible with .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// is not compatible with .
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The SiteCollection has a fixed size.
+ /// Please refer to for details.
+
+ void IList.Remove(object value)
+ {
+ Remove((Site) value);
+ }
+
+ #endregion
+ #region RemoveAt
+
+ ///
+ /// Removes the element at the specified index of the .
+ ///
+ /// The zero-based index of the element to remove.
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is equal to or greater than .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The SiteCollection has a fixed size.
+ /// Please refer to for details.
+
+ public virtual void RemoveAt(int index)
+ {
+ ValidateIndex(index);
+
+ ++this._version;
+ if (index < --this._count)
+ Array.Copy(this._array, index + 1,
+ this._array, index, this._count - index);
+
+ this._array[this._count] = null;
+ }
+
+ #endregion
+ #region RemoveRange
+
+ ///
+ /// Removes the specified range of elements from the .
+ ///
+ /// The zero-based starting index of the range
+ /// of elements to remove.
+ /// The number of elements to remove.
+ ///
+ /// and do not denote a
+ /// valid range of elements in the .
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is less than zero.
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The SiteCollection has a fixed size.
+ /// Please refer to for details.
+
+ public virtual void RemoveRange(int index, int count)
+ {
+ if (index < 0)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument cannot be negative.");
+
+ if (count < 0)
+ throw new ArgumentOutOfRangeException("count",
+ count, "Argument cannot be negative.");
+
+ if (index + count > this._count)
+ throw new ArgumentException(
+ "Arguments denote invalid range of elements.");
+
+ if (count == 0) return;
+
+ ++this._version;
+ this._count -= count;
+
+ if (index < this._count)
+ Array.Copy(this._array, index + count,
+ this._array, index, this._count - index);
+
+ Array.Clear(this._array, this._count, count);
+ }
+
+ #endregion
+ #region Reverse()
+
+ ///
+ /// Reverses the order of the elements in the
+ /// or a portion of it.
+ ///
+ ///
+ /// Reverses the order of the elements in the entire .
+ ///
+ ///
+ /// The is read-only.
+ /// Please refer to for details.
+
+ public virtual void Reverse()
+ {
+ if (this._count <= 1) return;
+ ++this._version;
+ Array.Reverse(this._array, 0, this._count);
+ }
+
+ #endregion
+ #region Reverse(Int32, Int32)
+
+ ///
+ /// Reverses the order of the elements in the specified range.
+ ///
+ /// The zero-based starting index of the range
+ /// of elements to reverse.
+ /// The number of elements to reverse.
+ ///
+ /// and do not denote a
+ /// valid range of elements in the .
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is less than zero.
+ ///
+ ///
+ /// The is read-only.
+ /// Please refer to for details.
+
+ public virtual void Reverse(int index, int count)
+ {
+ if (index < 0)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument cannot be negative.");
+
+ if (count < 0)
+ throw new ArgumentOutOfRangeException("count",
+ count, "Argument cannot be negative.");
+
+ if (index + count > this._count)
+ throw new ArgumentException(
+ "Arguments denote invalid range of elements.");
+
+ if (count <= 1 || this._count <= 1) return;
+ ++this._version;
+ Array.Reverse(this._array, index, count);
+ }
+
+ #endregion
+ #region Sort()
+
+ ///
+ /// Sorts the elements in the or a portion of it.
+ ///
+ ///
+ /// Sorts the elements in the entire
+ /// using the implementation of each element.
+ ///
+ ///
+ /// The is read-only.
+ /// Please refer to for details.
+
+ public virtual void Sort()
+ {
+ if (this._count <= 1) return;
+ ++this._version;
+ Array.Sort(this._array, 0, this._count);
+ }
+
+ #endregion
+ #region Sort(IComparer)
+
+ ///
+ /// Sorts the elements in the entire
+ /// using the specified interface.
+ ///
+ ///
+ /// The implementation to use when comparing elements.
+ /// -or-
+ /// A null reference to use the implementation
+ /// of each element.
+ ///
+ /// The is read-only.
+ /// Please refer to for details.
+
+ public virtual void Sort(IComparer comparer)
+ {
+ if (this._count <= 1) return;
+ ++this._version;
+ Array.Sort(this._array, 0, this._count, comparer);
+ }
+
+ #endregion
+ #region Sort(Int32, Int32, IComparer)
+
+ ///
+ /// Sorts the elements in the specified range
+ /// using the specified interface.
+ ///
+ /// The zero-based starting index of the range
+ /// of elements to sort.
+ /// The number of elements to sort.
+ ///
+ /// The implementation to use when comparing elements.
+ /// -or-
+ /// A null reference to use the implementation
+ /// of each element.
+ ///
+ /// and do not denote a
+ /// valid range of elements in the .
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is less than zero.
+ ///
+ ///
+ /// The is read-only.
+ /// Please refer to for details.
+
+ public virtual void Sort(int index, int count, IComparer comparer)
+ {
+ if (index < 0)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument cannot be negative.");
+
+ if (count < 0)
+ throw new ArgumentOutOfRangeException("count",
+ count, "Argument cannot be negative.");
+
+ if (index + count > this._count)
+ throw new ArgumentException(
+ "Arguments denote invalid range of elements.");
+
+ if (count <= 1 || this._count <= 1) return;
+ ++this._version;
+ Array.Sort(this._array, index, count, comparer);
+ }
+
+ #endregion
+ #region Synchronized
+
+ ///
+ /// Returns a synchronized (thread-safe) wrapper
+ /// for the specified .
+ ///
+ /// The to synchronize.
+ ///
+ /// A synchronized (thread-safe) wrapper around .
+ ///
+ ///
+ /// is a null reference.
+ /// Please refer to for details.
+
+ public static SiteCollection Synchronized(SiteCollection collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException("collection");
+
+ return new SyncList(collection);
+ }
+
+ #endregion
+ #region ToArray
+
+ ///
+ /// Copies the elements of the to a new
+ /// of elements.
+ ///
+ /// A one-dimensional of
+ /// elements containing copies of the elements of the .
+ /// Please refer to for details.
+
+ public virtual Site[] ToArray()
+ {
+ Site[] array = new Site[this._count];
+ Array.Copy(this._array, array, this._count);
+ return array;
+ }
+
+ #endregion
+ #region TrimToSize
+
+ ///
+ /// Sets the capacity to the actual number of elements in the .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The SiteCollection has a fixed size.
+ /// Please refer to for details.
+
+ public virtual void TrimToSize()
+ {
+ Capacity = this._count;
+ }
+
+ #endregion
+ #region Unique
+
+ ///
+ /// Returns a wrapper for the specified
+ /// ensuring that all elements are unique.
+ ///
+ /// The to wrap.
+ ///
+ /// A wrapper around ensuring that all elements are unique.
+ ///
+ ///
+ /// contains duplicate elements.
+ ///
+ /// is a null reference.
+ ///
+ /// The Unique wrapper provides a set-like collection by ensuring
+ /// that all elements in the are unique.
+ ///
+ /// Unique raises an if the specified
+ /// contains any duplicate elements. The returned
+ /// wrapper raises a whenever the user attempts
+ /// to add an element that is already contained in the SiteCollection.
+ ///
+ /// Note: The Unique wrapper reflects any changes made
+ /// to the underlying , including the possible
+ /// creation of duplicate elements. The uniqueness of all elements is therefore
+ /// no longer assured if the underlying collection is manipulated directly.
+ ///
+
+ public static SiteCollection Unique(SiteCollection collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException("collection");
+
+ for (int i = collection.Count - 1; i > 0; i--)
+ if (collection.IndexOf(collection[i]) < i)
+ throw new ArgumentException("collection",
+ "Argument cannot contain duplicate elements.");
+
+ return new UniqueList(collection);
+ }
+
+ #endregion
+ #endregion
+ #region Private Methods
+ #region CheckEnumIndex
+
+ private void CheckEnumIndex(int index)
+ {
+ if (index < 0 || index >= this._count)
+ throw new InvalidOperationException(
+ "Enumerator is not on a collection element.");
+ }
+
+ #endregion
+ #region CheckEnumVersion
+
+ private void CheckEnumVersion(int version)
+ {
+ if (version != this._version)
+ throw new InvalidOperationException(
+ "Enumerator invalidated by modification to collection.");
+ }
+
+ #endregion
+ #region CheckTargetArray
+
+ private void CheckTargetArray(Array array, int arrayIndex)
+ {
+ if (array == null)
+ throw new ArgumentNullException("array");
+ if (array.Rank > 1)
+ throw new ArgumentException(
+ "Argument cannot be multidimensional.", "array");
+
+ if (arrayIndex < 0)
+ throw new ArgumentOutOfRangeException("arrayIndex",
+ arrayIndex, "Argument cannot be negative.");
+ if (arrayIndex >= array.Length)
+ throw new ArgumentException(
+ "Argument must be less than array length.", "arrayIndex");
+
+ if (this._count > array.Length - arrayIndex)
+ throw new ArgumentException(
+ "Argument section must be large enough for collection.", "array");
+ }
+
+ #endregion
+ #region EnsureCapacity
+
+ private void EnsureCapacity(int minimum)
+ {
+ int newCapacity = (this._array.Length == 0 ?
+ _defaultCapacity : this._array.Length * 2);
+
+ if (newCapacity < minimum) newCapacity = minimum;
+ Capacity = newCapacity;
+ }
+
+ #endregion
+ #region ValidateIndex
+
+ private void ValidateIndex(int index)
+ {
+ if (index < 0)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument cannot be negative.");
+
+ if (index >= this._count)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument must be less than Count.");
+ }
+
+ #endregion
+ #endregion
+ #region Class Enumerator
+
+ [Serializable]
+ private sealed class Enumerator:
+ ISiteEnumerator, IEnumerator
+ {
+ #region Private Fields
+
+ private readonly SiteCollection _collection;
+ private readonly int _version;
+ private int _index;
+
+ #endregion
+ #region Internal Constructors
+
+ internal Enumerator(SiteCollection collection)
+ {
+ this._collection = collection;
+ this._version = collection._version;
+ this._index = -1;
+ }
+
+ #endregion
+ #region Public Properties
+
+ public Site Current
+ {
+ get
+ {
+ this._collection.CheckEnumIndex(this._index);
+ this._collection.CheckEnumVersion(this._version);
+ return this._collection[this._index];
+ }
+ }
+
+ object IEnumerator.Current
+ {
+ get { return Current; }
+ }
+
+ #endregion
+ #region Public Methods
+
+ public bool MoveNext()
+ {
+ this._collection.CheckEnumVersion(this._version);
+ return (++this._index < this._collection.Count);
+ }
+
+ public void Reset()
+ {
+ this._collection.CheckEnumVersion(this._version);
+ this._index = -1;
+ }
+
+ #endregion
+ }
+
+ #endregion
+ #region Class ReadOnlyList
+
+ [Serializable]
+ private sealed class ReadOnlyList: SiteCollection
+ {
+ #region Private Fields
+
+ private SiteCollection _collection;
+
+ #endregion
+ #region Internal Constructors
+
+ internal ReadOnlyList(SiteCollection collection):
+ base(Tag.Default)
+ {
+ this._collection = collection;
+ }
+
+ #endregion
+ #region Protected Properties
+
+ protected override Site[] InnerArray
+ {
+ get { return this._collection.InnerArray; }
+ }
+
+ #endregion
+ #region Public Properties
+
+ public override int Capacity
+ {
+ get { return this._collection.Capacity; }
+ set
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified."); }
+ }
+
+ public override int Count
+ {
+ get { return this._collection.Count; }
+ }
+
+ public override bool IsFixedSize
+ {
+ get { return true; }
+ }
+
+ public override bool IsReadOnly
+ {
+ get { return true; }
+ }
+
+ public override bool IsSynchronized
+ {
+ get { return this._collection.IsSynchronized; }
+ }
+
+ public override bool IsUnique
+ {
+ get { return this._collection.IsUnique; }
+ }
+
+ public override Site this[int index]
+ {
+ get { return this._collection[index]; }
+ set
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified."); }
+ }
+
+ public override object SyncRoot
+ {
+ get { return this._collection.SyncRoot; }
+ }
+
+ #endregion
+ #region Public Methods
+
+ public override int Add(Site value)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void AddRange(SiteCollection collection)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void AddRange(Site[] array)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override int BinarySearch(Site value)
+ {
+ return this._collection.BinarySearch(value);
+ }
+
+ public override void Clear()
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override object Clone()
+ {
+ return new ReadOnlyList((SiteCollection) this._collection.Clone());
+ }
+
+ public override void CopyTo(Site[] array)
+ {
+ this._collection.CopyTo(array);
+ }
+
+ public override void CopyTo(Site[] array, int arrayIndex)
+ {
+ this._collection.CopyTo(array, arrayIndex);
+ }
+
+ public override ISiteEnumerator GetEnumerator()
+ {
+ return this._collection.GetEnumerator();
+ }
+
+ public override int IndexOf(Site value)
+ {
+ return this._collection.IndexOf(value);
+ }
+
+ public override void Insert(int index, Site value)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void Remove(Site value)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void RemoveAt(int index)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void RemoveRange(int index, int count)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void Reverse()
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void Reverse(int index, int count)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void Sort()
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void Sort(IComparer comparer)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void Sort(int index, int count, IComparer comparer)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override Site[] ToArray()
+ {
+ return this._collection.ToArray();
+ }
+
+ public override void TrimToSize()
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ #endregion
+ }
+
+ #endregion
+ #region Class SyncList
+
+ [Serializable]
+ private sealed class SyncList: SiteCollection
+ {
+ #region Private Fields
+
+ private SiteCollection _collection;
+ private object _root;
+
+ #endregion
+ #region Internal Constructors
+
+ internal SyncList(SiteCollection collection):
+ base(Tag.Default)
+ {
+
+ this._root = collection.SyncRoot;
+ this._collection = collection;
+ }
+
+ #endregion
+ #region Protected Properties
+
+ protected override Site[] InnerArray
+ {
+ get { lock (this._root) return this._collection.InnerArray; }
+ }
+
+ #endregion
+ #region Public Properties
+
+ public override int Capacity
+ {
+ get { lock (this._root) return this._collection.Capacity; }
+ set { lock (this._root) this._collection.Capacity = value; }
+ }
+
+ public override int Count
+ {
+ get { lock (this._root) return this._collection.Count; }
+ }
+
+ public override bool IsFixedSize
+ {
+ get { return this._collection.IsFixedSize; }
+ }
+
+ public override bool IsReadOnly
+ {
+ get { return this._collection.IsReadOnly; }
+ }
+
+ public override bool IsSynchronized
+ {
+ get { return true; }
+ }
+
+ public override bool IsUnique
+ {
+ get { return this._collection.IsUnique; }
+ }
+
+ public override Site this[int index]
+ {
+ get { lock (this._root) return this._collection[index]; }
+ set { lock (this._root) this._collection[index] = value; }
+ }
+
+ public override object SyncRoot
+ {
+ get { return this._root; }
+ }
+
+ #endregion
+ #region Public Methods
+
+ public override int Add(Site value)
+ {
+ lock (this._root) return this._collection.Add(value);
+ }
+
+ public override void AddRange(SiteCollection collection)
+ {
+ lock (this._root) this._collection.AddRange(collection);
+ }
+
+ public override void AddRange(Site[] array)
+ {
+ lock (this._root) this._collection.AddRange(array);
+ }
+
+ public override int BinarySearch(Site value)
+ {
+ lock (this._root) return this._collection.BinarySearch(value);
+ }
+
+ public override void Clear()
+ {
+ lock (this._root) this._collection.Clear();
+ }
+
+ public override object Clone()
+ {
+ lock (this._root)
+ return new SyncList((SiteCollection) this._collection.Clone());
+ }
+
+ public override void CopyTo(Site[] array)
+ {
+ lock (this._root) this._collection.CopyTo(array);
+ }
+
+ public override void CopyTo(Site[] array, int arrayIndex)
+ {
+ lock (this._root) this._collection.CopyTo(array, arrayIndex);
+ }
+
+ public override ISiteEnumerator GetEnumerator()
+ {
+ lock (this._root) return this._collection.GetEnumerator();
+ }
+
+ public override int IndexOf(Site value)
+ {
+ lock (this._root) return this._collection.IndexOf(value);
+ }
+
+ public override void Insert(int index, Site value)
+ {
+ lock (this._root) this._collection.Insert(index, value);
+ }
+
+ public override void Remove(Site value)
+ {
+ lock (this._root) this._collection.Remove(value);
+ }
+
+ public override void RemoveAt(int index)
+ {
+ lock (this._root) this._collection.RemoveAt(index);
+ }
+
+ public override void RemoveRange(int index, int count)
+ {
+ lock (this._root) this._collection.RemoveRange(index, count);
+ }
+
+ public override void Reverse()
+ {
+ lock (this._root) this._collection.Reverse();
+ }
+
+ public override void Reverse(int index, int count)
+ {
+ lock (this._root) this._collection.Reverse(index, count);
+ }
+
+ public override void Sort()
+ {
+ lock (this._root) this._collection.Sort();
+ }
+
+ public override void Sort(IComparer comparer)
+ {
+ lock (this._root) this._collection.Sort(comparer);
+ }
+
+ public override void Sort(int index, int count, IComparer comparer)
+ {
+ lock (this._root) this._collection.Sort(index, count, comparer);
+ }
+
+ public override Site[] ToArray()
+ {
+ lock (this._root) return this._collection.ToArray();
+ }
+
+ public override void TrimToSize()
+ {
+ lock (this._root) this._collection.TrimToSize();
+ }
+
+ #endregion
+ }
+
+ #endregion
+ #region Class UniqueList
+
+ [Serializable]
+ private sealed class UniqueList: SiteCollection
+ {
+ #region Private Fields
+
+ private SiteCollection _collection;
+
+ #endregion
+ #region Internal Constructors
+
+ internal UniqueList(SiteCollection collection):
+ base(Tag.Default)
+ {
+ this._collection = collection;
+ }
+
+ #endregion
+ #region Protected Properties
+
+ protected override Site[] InnerArray
+ {
+ get { return this._collection.InnerArray; }
+ }
+
+ #endregion
+ #region Public Properties
+
+ public override int Capacity
+ {
+ get { return this._collection.Capacity; }
+ set { this._collection.Capacity = value; }
+ }
+
+ public override int Count
+ {
+ get { return this._collection.Count; }
+ }
+
+ public override bool IsFixedSize
+ {
+ get { return this._collection.IsFixedSize; }
+ }
+
+ public override bool IsReadOnly
+ {
+ get { return this._collection.IsReadOnly; }
+ }
+
+ public override bool IsSynchronized
+ {
+ get { return this._collection.IsSynchronized; }
+ }
+
+ public override bool IsUnique
+ {
+ get { return true; }
+ }
+
+ public override Site this[int index]
+ {
+ get { return this._collection[index]; }
+ set
+ {
+ CheckUnique(index, value);
+ this._collection[index] = value;
+ }
+ }
+
+ public override object SyncRoot
+ {
+ get { return this._collection.SyncRoot; }
+ }
+
+ #endregion
+ #region Public Methods
+
+ public override int Add(Site value)
+ {
+ CheckUnique(value);
+ return this._collection.Add(value);
+ }
+
+ public override void AddRange(SiteCollection collection)
+ {
+ foreach (Site value in collection)
+ CheckUnique(value);
+
+ this._collection.AddRange(collection);
+ }
+
+ public override void AddRange(Site[] array)
+ {
+ foreach (Site value in array)
+ CheckUnique(value);
+
+ this._collection.AddRange(array);
+ }
+
+ public override int BinarySearch(Site value)
+ {
+ return this._collection.BinarySearch(value);
+ }
+
+ public override void Clear()
+ {
+ this._collection.Clear();
+ }
+
+ public override object Clone()
+ {
+ return new UniqueList((SiteCollection) this._collection.Clone());
+ }
+
+ public override void CopyTo(Site[] array)
+ {
+ this._collection.CopyTo(array);
+ }
+
+ public override void CopyTo(Site[] array, int arrayIndex)
+ {
+ this._collection.CopyTo(array, arrayIndex);
+ }
+
+ public override ISiteEnumerator GetEnumerator()
+ {
+ return this._collection.GetEnumerator();
+ }
+
+ public override int IndexOf(Site value)
+ {
+ return this._collection.IndexOf(value);
+ }
+
+ public override void Insert(int index, Site value)
+ {
+ CheckUnique(value);
+ this._collection.Insert(index, value);
+ }
+
+ public override void Remove(Site value)
+ {
+ this._collection.Remove(value);
+ }
+
+ public override void RemoveAt(int index)
+ {
+ this._collection.RemoveAt(index);
+ }
+
+ public override void RemoveRange(int index, int count)
+ {
+ this._collection.RemoveRange(index, count);
+ }
+
+ public override void Reverse()
+ {
+ this._collection.Reverse();
+ }
+
+ public override void Reverse(int index, int count)
+ {
+ this._collection.Reverse(index, count);
+ }
+
+ public override void Sort()
+ {
+ this._collection.Sort();
+ }
+
+ public override void Sort(IComparer comparer)
+ {
+ this._collection.Sort(comparer);
+ }
+
+ public override void Sort(int index, int count, IComparer comparer)
+ {
+ this._collection.Sort(index, count, comparer);
+ }
+
+ public override Site[] ToArray()
+ {
+ return this._collection.ToArray();
+ }
+
+ public override void TrimToSize()
+ {
+ this._collection.TrimToSize();
+ }
+
+ #endregion
+ #region Private Methods
+
+ private void CheckUnique(Site value)
+ {
+ if (IndexOf(value) >= 0)
+ throw new NotSupportedException(
+ "Unique collections cannot contain duplicate elements.");
+ }
+
+ private void CheckUnique(int index, Site value)
+ {
+ int existing = IndexOf(value);
+ if (existing >= 0 && existing != index)
+ throw new NotSupportedException(
+ "Unique collections cannot contain duplicate elements.");
+ }
+
+ #endregion
+ }
+
+ #endregion
+ }
+
+ #endregion
+}
diff --git a/Freedb/Track.cs b/Freedb/Track.cs
new file mode 100644
index 0000000..b013f79
--- /dev/null
+++ b/Freedb/Track.cs
@@ -0,0 +1,99 @@
+#region COPYRIGHT (c) 2004 by Brian Weeres
+/* Copyright (c) 2004 by Brian Weeres
+ *
+ * Email: bweeres@protegra.com; bweeres@hotmail.com
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * If you modify it then please indicate so.
+ *
+ * The software is provided "AS IS" and there are no warranties or implied warranties.
+ * In no event shall Brian Weeres and/or Protegra Technology Group be liable for any special,
+ * direct, indirect, or consequential damages or any damages whatsoever resulting for any reason
+ * out of the use or performance of this software
+ *
+ */
+#endregion
+using System;
+
+namespace Freedb
+{
+ ///
+ /// Summary description for Track.
+ ///
+ public class Track
+ {
+
+ private string m_Title;
+ private string m_ExtendedData;
+
+ #region Public Properties
+ ///
+ /// Property ExtendedData (string)
+ ///
+ public string ExtendedData
+ {
+ get
+ {
+ return this.m_ExtendedData;
+ }
+ set
+ {
+ this.m_ExtendedData = value;
+ }
+ }
+
+ ///
+ /// Property Title (string)
+ ///
+ public string Title
+ {
+ get
+ {
+ return this.m_Title;
+ }
+ set
+ {
+ this.m_Title = value;
+ }
+ }
+ #endregion
+
+
+
+
+
+ ///
+ /// Create an instance of a Track
+ ///
+ ///
+ public Track()
+ {
+ }
+
+
+ ///
+ /// Create an instance of a Track passing in a title
+ ///
+ ///
+ public Track(string title)
+ {
+ m_Title = title;
+ }
+
+ ///
+ /// Create an instance of a Track passing in a title and extended data
+ ///
+ ///
+ public Track(string title, string extendedData)
+ {
+ m_Title = title;
+ m_ExtendedData = extendedData;
+ }
+
+
+
+ }
+}
diff --git a/Freedb/TrackCollection.cs b/Freedb/TrackCollection.cs
new file mode 100644
index 0000000..5ed38d4
--- /dev/null
+++ b/Freedb/TrackCollection.cs
@@ -0,0 +1,2378 @@
+#region COPYRIGHT (c) 2004 by Brian Weeres
+/* Copyright (c) 2004 by Brian Weeres
+ *
+ * Email: bweeres@protegra.com; bweeres@hotmail.com
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * If you modify it then please indicate so.
+ *
+ * The software is provided "AS IS" and there are no warranties or implied warranties.
+ * In no event shall Brian Weeres and/or Protegra Technology Group be liable for any special,
+ * direct, indirect, or consequential damages or any damages whatsoever resulting for any reason
+ * out of the use or performance of this software
+ *
+ */
+#endregion
+using System;
+using System.Collections;
+using Freedb;
+
+namespace Freedb
+{
+ #region Interface ITrackCollection
+
+ ///
+ /// Defines size, enumerators, and synchronization methods for strongly
+ /// typed collections of elements.
+ ///
+ ///
+ /// ITrackCollection provides an
+ /// that is strongly typed for elements.
+ ///
+
+ public interface ITrackCollection
+ {
+ #region Properties
+ #region Count
+
+ ///
+ /// Gets the number of elements contained in the
+ /// .
+ ///
+ /// The number of elements contained in the
+ /// .
+ /// Please refer to for details.
+
+ int Count { get; }
+
+ #endregion
+ #region IsSynchronized
+
+ ///
+ /// Gets a value indicating whether access to the
+ /// is synchronized (thread-safe).
+ ///
+ /// true if access to the is
+ /// synchronized (thread-safe); otherwise, false. The default is false.
+ /// Please refer to for details.
+
+ bool IsSynchronized { get; }
+
+ #endregion
+ #region SyncRoot
+
+ ///
+ /// Gets an object that can be used to synchronize access
+ /// to the .
+ ///
+ /// An object that can be used to synchronize access
+ /// to the .
+ /// Please refer to for details.
+
+ object SyncRoot { get; }
+
+ #endregion
+ #endregion
+ #region Methods
+ #region CopyTo
+
+ ///
+ /// Copies the entire to a one-dimensional
+ /// of elements, starting at the specified index of the target array.
+ ///
+ /// The one-dimensional that is the destination of the
+ /// elements copied from the .
+ /// The Array must have zero-based indexing.
+ /// The zero-based index in
+ /// at which copying begins.
+ ///
+ /// is a null reference.
+ ///
+ /// is less than zero.
+ ///
+ /// is equal to or greater than the length of .
+ /// -or-
+ /// The number of elements in the source is greater
+ /// than the available space from to the end of the destination
+ /// .
+ /// Please refer to for details.
+
+ void CopyTo(Track[] array, int arrayIndex);
+
+ #endregion
+ #region GetEnumerator
+
+ ///
+ /// Returns an that can
+ /// iterate through the .
+ ///
+ /// An
+ /// for the entire .
+ /// Please refer to for details.
+
+ ITrackEnumerator GetEnumerator();
+
+ #endregion
+ #endregion
+ }
+
+ #endregion
+ #region Interface ITrackList
+
+ ///
+ /// Represents a strongly typed collection of
+ /// objects that can be individually accessed by index.
+ ///
+ ///
+ /// ITrackList provides an
+ /// that is strongly typed for elements.
+ ///
+
+ public interface
+ ITrackList: ITrackCollection
+ {
+ #region Properties
+ #region IsFixedSize
+
+ ///
+ /// Gets a value indicating whether the has a fixed size.
+ ///
+ /// true if the has a fixed size;
+ /// otherwise, false. The default is false.
+ /// Please refer to for details.
+
+ bool IsFixedSize { get; }
+
+ #endregion
+ #region IsReadOnly
+
+ ///
+ /// Gets a value indicating whether the is read-only.
+ ///
+ /// true if the is read-only;
+ /// otherwise, false. The default is false.
+ /// Please refer to for details.
+
+ bool IsReadOnly { get; }
+
+ #endregion
+ #region Item
+
+ ///
+ /// Gets or sets the element at the specified index.
+ ///
+ /// The zero-based index of the
+ /// element to get or set.
+ ///
+ /// The element at the specified .
+ ///
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is equal to or greater than
+ /// .
+ ///
+ ///
+ /// The property is set and the is read-only.
+ /// Please refer to for details.
+
+ Track this[int index] { get; set; }
+
+ #endregion
+ #endregion
+ #region Methods
+ #region Add
+
+ ///
+ /// Adds a to the end
+ /// of the .
+ ///
+ /// The object
+ /// to be added to the end of the .
+ /// This argument can be a null reference.
+ ///
+ /// The index at which
+ /// the has been added.
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The ITrackList has a fixed size.
+ /// Please refer to for details.
+
+ int Add(Track value);
+
+ #endregion
+ #region Clear
+
+ ///
+ /// Removes all elements from the .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The ITrackList has a fixed size.
+ /// Please refer to for details.
+
+ void Clear();
+
+ #endregion
+ #region Contains
+
+ ///
+ /// Determines whether the
+ /// contains the specified element.
+ ///
+ /// The object
+ /// to locate in the .
+ /// This argument can be a null reference.
+ ///
+ /// true if is found in the
+ /// ; otherwise, false.
+ /// Please refer to for details.
+
+ bool Contains(Track value);
+
+ #endregion
+ #region IndexOf
+
+ ///
+ /// Returns the zero-based index of the first occurrence of the specified
+ /// in the .
+ ///
+ /// The object
+ /// to locate in the .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// The zero-based index of the first occurrence of
+ /// in the , if found; otherwise, -1.
+ ///
+ /// Please refer to for details.
+
+ int IndexOf(Track value);
+
+ #endregion
+ #region Insert
+
+ ///
+ /// Inserts a element into the
+ /// at the specified index.
+ ///
+ /// The zero-based index at which
+ /// should be inserted.
+ /// The object
+ /// to insert into the .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is greater than
+ /// .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The ITrackList has a fixed size.
+ /// Please refer to for details.
+
+ void Insert(int index, Track value);
+
+ #endregion
+ #region Remove
+
+ ///
+ /// Removes the first occurrence of the specified
+ /// from the .
+ ///
+ /// The object
+ /// to remove from the .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The ITrackList has a fixed size.
+ /// Please refer to for details.
+
+ void Remove(Track value);
+
+ #endregion
+ #region RemoveAt
+
+ ///
+ /// Removes the element at the specified index of the
+ /// .
+ ///
+ /// The zero-based index of the element to remove.
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is equal to or greater than
+ /// .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The ITrackList has a fixed size.
+ /// Please refer to for details.
+
+ void RemoveAt(int index);
+
+ #endregion
+ #endregion
+ }
+
+ #endregion
+ #region Interface ITrackEnumerator
+
+ ///
+ /// Supports type-safe iteration over a collection that
+ /// contains elements.
+ ///
+ ///
+ /// ITrackEnumerator provides an
+ /// that is strongly typed for elements.
+ ///
+
+ public interface ITrackEnumerator
+ {
+ #region Properties
+ #region Current
+
+ ///
+ /// Gets the current element in the collection.
+ ///
+ /// The current element in the collection.
+ /// The enumerator is positioned
+ /// before the first element of the collection or after the last element.
+ /// -or-
+ /// The collection was modified after the enumerator was created.
+ /// Please refer to for details, but note
+ /// that Current fails if the collection was modified since the last successful
+ /// call to or .
+
+ Track Current { get; }
+
+ #endregion
+ #endregion
+ #region Methods
+ #region MoveNext
+
+ ///
+ /// Advances the enumerator to the next element of the collection.
+ ///
+ /// true if the enumerator was successfully advanced to the next element;
+ /// false if the enumerator has passed the end of the collection.
+ ///
+ /// The collection was modified after the enumerator was created.
+ /// Please refer to for details.
+
+ bool MoveNext();
+
+ #endregion
+ #region Reset
+
+ ///
+ /// Sets the enumerator to its initial position,
+ /// which is before the first element in the collection.
+ ///
+ ///
+ /// The collection was modified after the enumerator was created.
+ /// Please refer to for details.
+
+ void Reset();
+
+ #endregion
+ #endregion
+ }
+
+ #endregion
+ #region Class TrackCollection
+
+ ///
+ /// Implements a strongly typed collection of elements.
+ ///
+ ///
+ /// TrackCollection provides an
+ /// that is strongly typed for elements.
+ ///
+
+ [Serializable]
+ public class TrackCollection:
+ ITrackList, IList, ICloneable
+ {
+ #region Private Fields
+
+ private const int _defaultCapacity = 16;
+
+ private Track[] _array = null;
+ private int _count = 0;
+
+ [NonSerialized]
+ private int _version = 0;
+
+ #endregion
+ #region Private Constructors
+
+ // helper type to identify private ctor
+ private enum Tag { Default }
+
+ private TrackCollection(Tag tag) { }
+
+ #endregion
+ #region Public Constructors
+ #region TrackCollection()
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// Initializes a new instance of the class
+ /// that is empty and has the default initial capacity.
+ ///
+ /// Please refer to for details.
+
+ public TrackCollection()
+ {
+ this._array = new Track[_defaultCapacity];
+ }
+
+ #endregion
+ #region TrackCollection(Int32)
+
+ ///
+ /// Initializes a new instance of the class
+ /// that is empty and has the specified initial capacity.
+ ///
+ /// The number of elements that the new
+ /// is initially capable of storing.
+ ///
+ /// is less than zero.
+ /// Please refer to for details.
+
+ public TrackCollection(int capacity)
+ {
+ if (capacity < 0)
+ throw new ArgumentOutOfRangeException("capacity",
+ capacity, "Argument cannot be negative.");
+
+ this._array = new Track[capacity];
+ }
+
+ #endregion
+ #region TrackCollection(TrackCollection)
+
+ ///
+ /// Initializes a new instance of the class
+ /// that contains elements copied from the specified collection and
+ /// that has the same initial capacity as the number of elements copied.
+ ///
+ /// The
+ /// whose elements are copied to the new collection.
+ ///
+ /// is a null reference.
+ /// Please refer to for details.
+
+ public TrackCollection(TrackCollection collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException("collection");
+
+ this._array = new Track[collection.Count];
+ AddRange(collection);
+ }
+
+ #endregion
+ #region TrackCollection(Track[])
+
+ ///
+ /// Initializes a new instance of the class
+ /// that contains elements copied from the specified
+ /// array and that has the same initial capacity as the number of elements copied.
+ ///
+ /// An of
+ /// elements that are copied to the new collection.
+ ///
+ /// is a null reference.
+ /// Please refer to for details.
+
+ public TrackCollection(Track[] array)
+ {
+ if (array == null)
+ throw new ArgumentNullException("array");
+
+ this._array = new Track[array.Length];
+ AddRange(array);
+ }
+
+ #endregion
+ #endregion
+ #region Protected Properties
+ #region InnerArray
+
+ ///
+ /// Gets the list of elements contained in the instance.
+ ///
+ ///
+ /// A one-dimensional with zero-based indexing that contains all
+ /// elements in the .
+ ///
+ ///
+ /// Use InnerArray to access the element array of a
+ /// instance that might be a read-only or synchronized wrapper. This is necessary because
+ /// the element array field of wrapper classes is always a null reference.
+ ///
+
+ protected virtual Track[] InnerArray
+ {
+ get { return this._array; }
+ }
+
+ #endregion
+ #endregion
+ #region Public Properties
+ #region Capacity
+
+ ///
+ /// Gets or sets the capacity of the .
+ ///
+ /// The number of elements that the
+ /// can contain.
+ ///
+ /// Capacity is set to a value that is less than .
+ /// Please refer to for details.
+
+ public virtual int Capacity
+ {
+ get { return this._array.Length; }
+ set
+ {
+ if (value == this._array.Length) return;
+
+ if (value < this._count)
+ throw new ArgumentOutOfRangeException("Capacity",
+ value, "Value cannot be less than Count.");
+
+ if (value == 0)
+ {
+ this._array = new Track[_defaultCapacity];
+ return;
+ }
+
+ Track[] newArray = new Track[value];
+ Array.Copy(this._array, newArray, this._count);
+ this._array = newArray;
+ }
+ }
+
+ #endregion
+ #region Count
+
+ ///
+ /// Gets the number of elements contained in the .
+ ///
+ ///
+ /// The number of elements contained in the .
+ ///
+ /// Please refer to for details.
+
+ public virtual int Count
+ {
+ get { return this._count; }
+ }
+
+ #endregion
+ #region IsFixedSize
+
+ ///
+ /// Gets a value indicating whether the has a fixed size.
+ ///
+ /// true if the has a fixed size;
+ /// otherwise, false. The default is false.
+ /// Please refer to for details.
+
+ public virtual bool IsFixedSize
+ {
+ get { return false; }
+ }
+
+ #endregion
+ #region IsReadOnly
+
+ ///
+ /// Gets a value indicating whether the is read-only.
+ ///
+ /// true if the is read-only;
+ /// otherwise, false. The default is false.
+ /// Please refer to for details.
+
+ public virtual bool IsReadOnly
+ {
+ get { return false; }
+ }
+
+ #endregion
+ #region IsSynchronized
+
+ ///
+ /// Gets a value indicating whether access to the
+ /// is synchronized (thread-safe).
+ ///
+ /// true if access to the is
+ /// synchronized (thread-safe); otherwise, false. The default is false.
+ /// Please refer to for details.
+
+ public virtual bool IsSynchronized
+ {
+ get { return false; }
+ }
+
+ #endregion
+ #region IsUnique
+
+ ///
+ /// Gets a value indicating whether the
+ /// ensures that all elements are unique.
+ ///
+ ///
+ /// true if the ensures that all
+ /// elements are unique; otherwise, false. The default is false.
+ ///
+ ///
+ /// IsUnique returns true exactly if the
+ /// is exposed through a wrapper.
+ /// Please refer to for details.
+ ///
+
+ public virtual bool IsUnique
+ {
+ get { return false; }
+ }
+
+ #endregion
+ #region Item: Track
+
+ ///
+ /// Gets or sets the element at the specified index.
+ ///
+ /// The zero-based index of the
+ /// element to get or set.
+ ///
+ /// The element at the specified .
+ ///
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is equal to or greater than .
+ ///
+ ///
+ /// The property is set and the is read-only.
+ /// -or-
+ /// The property is set, the TrackCollection already contains the
+ /// specified element at a different index, and the TrackCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ public virtual Track this[int index]
+ {
+ get
+ {
+ ValidateIndex(index);
+ return this._array[index];
+ }
+ set
+ {
+ ValidateIndex(index);
+ ++this._version;
+ this._array[index] = value;
+ }
+ }
+
+ #endregion
+ #region IList.Item: Object
+
+ ///
+ /// Gets or sets the element at the specified index.
+ ///
+ /// The zero-based index of the element to get or set.
+ ///
+ /// The element at the specified . When the property
+ /// is set, this value must be compatible with .
+ ///
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is equal to or greater than .
+ ///
+ /// The property is set to a value
+ /// that is not compatible with .
+ ///
+ /// The property is set and the is read-only.
+ /// -or-
+ /// The property is set, the TrackCollection already contains the
+ /// specified element at a different index, and the TrackCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ object IList.this[int index]
+ {
+ get { return this[index]; }
+ set { this[index] = (Track) value; }
+ }
+
+ #endregion
+ #region SyncRoot
+
+ ///
+ /// Gets an object that can be used to synchronize
+ /// access to the .
+ ///
+ /// An object that can be used to synchronize
+ /// access to the .
+ ///
+ /// Please refer to for details.
+
+ public virtual object SyncRoot
+ {
+ get { return this; }
+ }
+
+ #endregion
+ #endregion
+ #region Public Methods
+ #region Add(Track)
+
+ ///
+ /// Adds a to the end of the .
+ ///
+ /// The object
+ /// to be added to the end of the .
+ /// This argument can be a null reference.
+ ///
+ /// The index at which the
+ /// has been added.
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The TrackCollection has a fixed size.
+ /// -or-
+ /// The TrackCollection already contains the specified
+ /// , and the TrackCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ public virtual int Add(Track value)
+ {
+ if (this._count == this._array.Length)
+ EnsureCapacity(this._count + 1);
+
+ ++this._version;
+ this._array[this._count] = value;
+ return this._count++;
+ }
+
+ #endregion
+ #region IList.Add(Object)
+
+ ///
+ /// Adds an to the end of the .
+ ///
+ ///
+ /// The object to be added to the end of the .
+ /// This argument must be compatible with .
+ /// This argument can be a null reference.
+ ///
+ /// The index at which the
+ /// has been added.
+ ///
+ /// is not compatible with .
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The TrackCollection has a fixed size.
+ /// -or-
+ /// The TrackCollection already contains the specified
+ /// , and the TrackCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ int IList.Add(object value)
+ {
+ return Add((Track) value);
+ }
+
+ #endregion
+ #region AddRange(TrackCollection)
+
+ ///
+ /// Adds a range of elements to the end of the .
+ ///
+ ///
+ /// Adds the elements of another collection to the end of the .
+ ///
+ /// The whose elements
+ /// should be added to the end of the current collection.
+ ///
+ /// is a null reference.
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The TrackCollection has a fixed size.
+ /// -or-
+ /// The TrackCollection already contains one or more elements
+ /// in the specified , and the TrackCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ public virtual void AddRange(TrackCollection collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException("collection");
+
+ if (collection.Count == 0) return;
+ if (this._count + collection.Count > this._array.Length)
+ EnsureCapacity(this._count + collection.Count);
+
+ ++this._version;
+ Array.Copy(collection.InnerArray, 0,
+ this._array, this._count, collection.Count);
+ this._count += collection.Count;
+ }
+
+ #endregion
+ #region AddRange(Track[])
+
+ ///
+ /// Adds the elements of a array
+ /// to the end of the .
+ ///
+ /// An of elements
+ /// that should be added to the end of the .
+ ///
+ /// is a null reference.
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The TrackCollection has a fixed size.
+ /// -or-
+ /// The TrackCollection already contains one or more elements
+ /// in the specified , and the TrackCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ public virtual void AddRange(Track[] array)
+ {
+ if (array == null)
+ throw new ArgumentNullException("array");
+
+ if (array.Length == 0) return;
+ if (this._count + array.Length > this._array.Length)
+ EnsureCapacity(this._count + array.Length);
+
+ ++this._version;
+ Array.Copy(array, 0, this._array, this._count, array.Length);
+ this._count += array.Length;
+ }
+
+ #endregion
+ #region BinarySearch
+
+ ///
+ /// Searches the entire sorted for an
+ /// element using the default comparer
+ /// and returns the zero-based index of the element.
+ ///
+ /// The object
+ /// to locate in the .
+ /// This argument can be a null reference.
+ ///
+ /// The zero-based index of in the sorted
+ /// , if is found;
+ /// otherwise, a negative number, which is the bitwise complement of the index
+ /// of the next element that is larger than or, if there
+ /// is no larger element, the bitwise complement of .
+ ///
+ /// Neither nor the elements of the
+ /// implement the interface.
+ /// Please refer to for details.
+
+ public virtual int BinarySearch(Track value)
+ {
+ return Array.BinarySearch(this._array, 0, this._count, value);
+ }
+
+ #endregion
+ #region Clear
+
+ ///
+ /// Removes all elements from the .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The TrackCollection has a fixed size.
+ /// Please refer to for details.
+
+ public virtual void Clear()
+ {
+ if (this._count == 0) return;
+
+ ++this._version;
+ Array.Clear(this._array, 0, this._count);
+ this._count = 0;
+ }
+
+ #endregion
+ #region Clone
+
+ ///
+ /// Creates a shallow copy of the .
+ ///
+ /// A shallow copy of the .
+ /// Please refer to for details.
+
+ public virtual object Clone()
+ {
+ TrackCollection collection = new TrackCollection(this._count);
+
+ Array.Copy(this._array, 0, collection._array, 0, this._count);
+ collection._count = this._count;
+ collection._version = this._version;
+
+ return collection;
+ }
+
+ #endregion
+ #region Contains(Track)
+
+ ///
+ /// Determines whether the
+ /// contains the specified element.
+ ///
+ /// The object
+ /// to locate in the .
+ /// This argument can be a null reference.
+ ///
+ /// true if is found in the
+ /// ; otherwise, false.
+ /// Please refer to for details.
+
+ public bool Contains(Track value)
+ {
+ return (IndexOf(value) >= 0);
+ }
+
+ #endregion
+ #region IList.Contains(Object)
+
+ ///
+ /// Determines whether the contains the specified element.
+ ///
+ /// The object to locate in the .
+ /// This argument must be compatible with .
+ /// This argument can be a null reference.
+ ///
+ /// true if is found in the
+ /// ; otherwise, false.
+ ///
+ /// is not compatible with .
+ /// Please refer to for details.
+
+ bool IList.Contains(object value)
+ {
+ return Contains((Track) value);
+ }
+
+ #endregion
+ #region CopyTo(Track[])
+
+ ///
+ /// Copies the or a portion of it to a one-dimensional array.
+ ///
+ ///
+ /// Copies the entire to a one-dimensional
+ /// of elements, starting at the beginning of the target array.
+ ///
+ /// The one-dimensional that is the destination of the
+ /// elements copied from the .
+ /// The Array must have zero-based indexing.
+ ///
+ /// is a null reference.
+ ///
+ /// The number of elements in the source is greater
+ /// than the available space in the destination .
+ /// Please refer to for details.
+
+ public virtual void CopyTo(Track[] array)
+ {
+ CheckTargetArray(array, 0);
+ Array.Copy(this._array, array, this._count);
+ }
+
+ #endregion
+ #region CopyTo(Track[], Int32)
+
+ ///
+ /// Copies the entire to a one-dimensional
+ /// of elements, starting at the specified index of the target array.
+ ///
+ /// The one-dimensional that is the destination of the
+ /// elements copied from the .
+ /// The Array must have zero-based indexing.
+ /// The zero-based index in
+ /// at which copying begins.
+ ///
+ /// is a null reference.
+ ///
+ /// is less than zero.
+ ///
+ /// is equal to or greater than the length of .
+ /// -or-
+ /// The number of elements in the source is greater than the
+ /// available space from to the end of the destination
+ /// .
+ /// Please refer to for details.
+
+ public virtual void CopyTo(Track[] array, int arrayIndex)
+ {
+ CheckTargetArray(array, arrayIndex);
+ Array.Copy(this._array, 0, array, arrayIndex, this._count);
+ }
+
+ #endregion
+ #region ICollection.CopyTo(Array, Int32)
+
+ ///
+ /// Copies the entire to a one-dimensional ,
+ /// starting at the specified index of the target array.
+ ///
+ /// The one-dimensional that is the destination of the
+ /// elements copied from the .
+ /// The Array must have zero-based indexing.
+ /// The zero-based index in
+ /// at which copying begins.
+ ///
+ /// is a null reference.
+ ///
+ /// is less than zero.
+ ///
+ /// is multidimensional.
+ /// -or-
+ /// is equal to or greater than the length of .
+ /// -or-
+ /// The number of elements in the source is greater than the
+ /// available space from to the end of the destination
+ /// .
+ ///
+ /// The type cannot be cast automatically
+ /// to the type of the destination .
+ /// Please refer to for details.
+
+ void ICollection.CopyTo(Array array, int arrayIndex)
+ {
+ CopyTo((Track[]) array, arrayIndex);
+ }
+
+ #endregion
+ #region GetEnumerator: ITrackEnumerator
+
+ ///
+ /// Returns an that can
+ /// iterate through the .
+ ///
+ /// An
+ /// for the entire .
+ /// Please refer to for details.
+
+ public virtual ITrackEnumerator GetEnumerator()
+ {
+ return new Enumerator(this);
+ }
+
+ #endregion
+ #region IEnumerable.GetEnumerator: IEnumerator
+
+ ///
+ /// Returns an that can
+ /// iterate through the .
+ ///
+ /// An
+ /// for the entire .
+ /// Please refer to for details.
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return (IEnumerator) GetEnumerator();
+ }
+
+ #endregion
+ #region IndexOf(Track)
+
+ ///
+ /// Returns the zero-based index of the first occurrence of the specified
+ /// in the .
+ ///
+ /// The object
+ /// to locate in the .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// The zero-based index of the first occurrence of
+ /// in the , if found; otherwise, -1.
+ ///
+ /// Please refer to for details.
+
+ public virtual int IndexOf(Track value)
+ {
+ return Array.IndexOf(this._array, value, 0, this._count);
+ }
+
+ #endregion
+ #region IList.IndexOf(Object)
+
+ ///
+ /// Returns the zero-based index of the first occurrence of the specified
+ /// in the .
+ ///
+ /// The object to locate in the .
+ /// This argument must be compatible with .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// The zero-based index of the first occurrence of
+ /// in the , if found; otherwise, -1.
+ ///
+ ///
+ /// is not compatible with .
+ /// Please refer to for details.
+
+ int IList.IndexOf(object value)
+ {
+ return IndexOf((Track) value);
+ }
+
+ #endregion
+ #region Insert(Int32, Track)
+
+ ///
+ /// Inserts a element into the
+ /// at the specified index.
+ ///
+ /// The zero-based index at which
+ /// should be inserted.
+ /// The object
+ /// to insert into the .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is greater than .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The TrackCollection has a fixed size.
+ /// -or-
+ /// The TrackCollection already contains the specified
+ /// , and the TrackCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ public virtual void Insert(int index, Track value)
+ {
+ if (index < 0)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument cannot be negative.");
+
+ if (index > this._count)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument cannot exceed Count.");
+
+ if (this._count == this._array.Length)
+ EnsureCapacity(this._count + 1);
+
+ ++this._version;
+ if (index < this._count)
+ Array.Copy(this._array, index,
+ this._array, index + 1, this._count - index);
+
+ this._array[index] = value;
+ ++this._count;
+ }
+
+ #endregion
+ #region IList.Insert(Int32, Object)
+
+ ///
+ /// Inserts an element into the at the specified index.
+ ///
+ /// The zero-based index at which
+ /// should be inserted.
+ /// The object to insert into the .
+ /// This argument must be compatible with .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is greater than .
+ ///
+ ///
+ /// is not compatible with .
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The TrackCollection has a fixed size.
+ /// -or-
+ /// The TrackCollection already contains the specified
+ /// , and the TrackCollection
+ /// ensures that all elements are unique.
+ /// Please refer to for details.
+
+ void IList.Insert(int index, object value)
+ {
+ Insert(index, (Track) value);
+ }
+
+ #endregion
+ #region ReadOnly
+
+ ///
+ /// Returns a read-only wrapper for the specified .
+ ///
+ /// The to wrap.
+ /// A read-only wrapper around .
+ ///
+ /// is a null reference.
+ /// Please refer to for details.
+
+ public static TrackCollection ReadOnly(TrackCollection collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException("collection");
+
+ return new ReadOnlyList(collection);
+ }
+
+ #endregion
+ #region Remove(Track)
+
+ ///
+ /// Removes the first occurrence of the specified
+ /// from the .
+ ///
+ /// The object
+ /// to remove from the .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The TrackCollection has a fixed size.
+ /// Please refer to for details.
+
+ public virtual void Remove(Track value)
+ {
+ int index = IndexOf(value);
+ if (index >= 0) RemoveAt(index);
+ }
+
+ #endregion
+ #region IList.Remove(Object)
+
+ ///
+ /// Removes the first occurrence of the specified
+ /// from the .
+ ///
+ /// The object to remove from the .
+ /// This argument must be compatible with .
+ /// This argument can be a null reference.
+ ///
+ ///
+ /// is not compatible with .
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The TrackCollection has a fixed size.
+ /// Please refer to for details.
+
+ void IList.Remove(object value)
+ {
+ Remove((Track) value);
+ }
+
+ #endregion
+ #region RemoveAt
+
+ ///
+ /// Removes the element at the specified index of the .
+ ///
+ /// The zero-based index of the element to remove.
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is equal to or greater than .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The TrackCollection has a fixed size.
+ /// Please refer to for details.
+
+ public virtual void RemoveAt(int index)
+ {
+ ValidateIndex(index);
+
+ ++this._version;
+ if (index < --this._count)
+ Array.Copy(this._array, index + 1,
+ this._array, index, this._count - index);
+
+ this._array[this._count] = null;
+ }
+
+ #endregion
+ #region RemoveRange
+
+ ///
+ /// Removes the specified range of elements from the .
+ ///
+ /// The zero-based starting index of the range
+ /// of elements to remove.
+ /// The number of elements to remove.
+ ///
+ /// and do not denote a
+ /// valid range of elements in the .
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is less than zero.
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The TrackCollection has a fixed size.
+ /// Please refer to for details.
+
+ public virtual void RemoveRange(int index, int count)
+ {
+ if (index < 0)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument cannot be negative.");
+
+ if (count < 0)
+ throw new ArgumentOutOfRangeException("count",
+ count, "Argument cannot be negative.");
+
+ if (index + count > this._count)
+ throw new ArgumentException(
+ "Arguments denote invalid range of elements.");
+
+ if (count == 0) return;
+
+ ++this._version;
+ this._count -= count;
+
+ if (index < this._count)
+ Array.Copy(this._array, index + count,
+ this._array, index, this._count - index);
+
+ Array.Clear(this._array, this._count, count);
+ }
+
+ #endregion
+ #region Reverse()
+
+ ///
+ /// Reverses the order of the elements in the
+ /// or a portion of it.
+ ///
+ ///
+ /// Reverses the order of the elements in the entire .
+ ///
+ ///
+ /// The is read-only.
+ /// Please refer to for details.
+
+ public virtual void Reverse()
+ {
+ if (this._count <= 1) return;
+ ++this._version;
+ Array.Reverse(this._array, 0, this._count);
+ }
+
+ #endregion
+ #region Reverse(Int32, Int32)
+
+ ///
+ /// Reverses the order of the elements in the specified range.
+ ///
+ /// The zero-based starting index of the range
+ /// of elements to reverse.
+ /// The number of elements to reverse.
+ ///
+ /// and do not denote a
+ /// valid range of elements in the .
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is less than zero.
+ ///
+ ///
+ /// The is read-only.
+ /// Please refer to for details.
+
+ public virtual void Reverse(int index, int count)
+ {
+ if (index < 0)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument cannot be negative.");
+
+ if (count < 0)
+ throw new ArgumentOutOfRangeException("count",
+ count, "Argument cannot be negative.");
+
+ if (index + count > this._count)
+ throw new ArgumentException(
+ "Arguments denote invalid range of elements.");
+
+ if (count <= 1 || this._count <= 1) return;
+ ++this._version;
+ Array.Reverse(this._array, index, count);
+ }
+
+ #endregion
+ #region Sort()
+
+ ///
+ /// Sorts the elements in the or a portion of it.
+ ///
+ ///
+ /// Sorts the elements in the entire
+ /// using the implementation of each element.
+ ///
+ ///
+ /// The is read-only.
+ /// Please refer to for details.
+
+ public virtual void Sort()
+ {
+ if (this._count <= 1) return;
+ ++this._version;
+ Array.Sort(this._array, 0, this._count);
+ }
+
+ #endregion
+ #region Sort(IComparer)
+
+ ///
+ /// Sorts the elements in the entire
+ /// using the specified interface.
+ ///
+ ///
+ /// The implementation to use when comparing elements.
+ /// -or-
+ /// A null reference to use the implementation
+ /// of each element.
+ ///
+ /// The is read-only.
+ /// Please refer to for details.
+
+ public virtual void Sort(IComparer comparer)
+ {
+ if (this._count <= 1) return;
+ ++this._version;
+ Array.Sort(this._array, 0, this._count, comparer);
+ }
+
+ #endregion
+ #region Sort(Int32, Int32, IComparer)
+
+ ///
+ /// Sorts the elements in the specified range
+ /// using the specified interface.
+ ///
+ /// The zero-based starting index of the range
+ /// of elements to sort.
+ /// The number of elements to sort.
+ ///
+ /// The implementation to use when comparing elements.
+ /// -or-
+ /// A null reference to use the implementation
+ /// of each element.
+ ///
+ /// and do not denote a
+ /// valid range of elements in the .
+ ///
+ /// is less than zero.
+ /// -or-
+ /// is less than zero.
+ ///
+ ///
+ /// The is read-only.
+ /// Please refer to for details.
+
+ public virtual void Sort(int index, int count, IComparer comparer)
+ {
+ if (index < 0)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument cannot be negative.");
+
+ if (count < 0)
+ throw new ArgumentOutOfRangeException("count",
+ count, "Argument cannot be negative.");
+
+ if (index + count > this._count)
+ throw new ArgumentException(
+ "Arguments denote invalid range of elements.");
+
+ if (count <= 1 || this._count <= 1) return;
+ ++this._version;
+ Array.Sort(this._array, index, count, comparer);
+ }
+
+ #endregion
+ #region Synchronized
+
+ ///
+ /// Returns a synchronized (thread-safe) wrapper
+ /// for the specified .
+ ///
+ /// The to synchronize.
+ ///
+ /// A synchronized (thread-safe) wrapper around .
+ ///
+ ///
+ /// is a null reference.
+ /// Please refer to for details.
+
+ public static TrackCollection Synchronized(TrackCollection collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException("collection");
+
+ return new SyncList(collection);
+ }
+
+ #endregion
+ #region ToArray
+
+ ///
+ /// Copies the elements of the to a new
+ /// of elements.
+ ///
+ /// A one-dimensional of
+ /// elements containing copies of the elements of the .
+ /// Please refer to for details.
+
+ public virtual Track[] ToArray()
+ {
+ Track[] array = new Track[this._count];
+ Array.Copy(this._array, array, this._count);
+ return array;
+ }
+
+ #endregion
+ #region TrimToSize
+
+ ///
+ /// Sets the capacity to the actual number of elements in the .
+ ///
+ ///
+ /// The is read-only.
+ /// -or-
+ /// The TrackCollection has a fixed size.
+ /// Please refer to for details.
+
+ public virtual void TrimToSize()
+ {
+ Capacity = this._count;
+ }
+
+ #endregion
+ #region Unique
+
+ ///
+ /// Returns a wrapper for the specified
+ /// ensuring that all elements are unique.
+ ///
+ /// The to wrap.
+ ///
+ /// A wrapper around ensuring that all elements are unique.
+ ///
+ ///
+ /// contains duplicate elements.
+ ///
+ /// is a null reference.
+ ///
+ /// The Unique wrapper provides a set-like collection by ensuring
+ /// that all elements in the are unique.
+ ///
+ /// Unique raises an if the specified
+ /// contains any duplicate elements. The returned
+ /// wrapper raises a whenever the user attempts
+ /// to add an element that is already contained in the TrackCollection.
+ ///
+ /// Note: The Unique wrapper reflects any changes made
+ /// to the underlying , including the possible
+ /// creation of duplicate elements. The uniqueness of all elements is therefore
+ /// no longer assured if the underlying collection is manipulated directly.
+ ///
+
+ public static TrackCollection Unique(TrackCollection collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException("collection");
+
+ for (int i = collection.Count - 1; i > 0; i--)
+ if (collection.IndexOf(collection[i]) < i)
+ throw new ArgumentException("collection",
+ "Argument cannot contain duplicate elements.");
+
+ return new UniqueList(collection);
+ }
+
+ #endregion
+ #endregion
+ #region Private Methods
+ #region CheckEnumIndex
+
+ private void CheckEnumIndex(int index)
+ {
+ if (index < 0 || index >= this._count)
+ throw new InvalidOperationException(
+ "Enumerator is not on a collection element.");
+ }
+
+ #endregion
+ #region CheckEnumVersion
+
+ private void CheckEnumVersion(int version)
+ {
+ if (version != this._version)
+ throw new InvalidOperationException(
+ "Enumerator invalidated by modification to collection.");
+ }
+
+ #endregion
+ #region CheckTargetArray
+
+ private void CheckTargetArray(Array array, int arrayIndex)
+ {
+ if (array == null)
+ throw new ArgumentNullException("array");
+ if (array.Rank > 1)
+ throw new ArgumentException(
+ "Argument cannot be multidimensional.", "array");
+
+ if (arrayIndex < 0)
+ throw new ArgumentOutOfRangeException("arrayIndex",
+ arrayIndex, "Argument cannot be negative.");
+ if (arrayIndex >= array.Length)
+ throw new ArgumentException(
+ "Argument must be less than array length.", "arrayIndex");
+
+ if (this._count > array.Length - arrayIndex)
+ throw new ArgumentException(
+ "Argument section must be large enough for collection.", "array");
+ }
+
+ #endregion
+ #region EnsureCapacity
+
+ private void EnsureCapacity(int minimum)
+ {
+ int newCapacity = (this._array.Length == 0 ?
+ _defaultCapacity : this._array.Length * 2);
+
+ if (newCapacity < minimum) newCapacity = minimum;
+ Capacity = newCapacity;
+ }
+
+ #endregion
+ #region ValidateIndex
+
+ private void ValidateIndex(int index)
+ {
+ if (index < 0)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument cannot be negative.");
+
+ if (index >= this._count)
+ throw new ArgumentOutOfRangeException("index",
+ index, "Argument must be less than Count.");
+ }
+
+ #endregion
+ #endregion
+ #region Class Enumerator
+
+ [Serializable]
+ private sealed class Enumerator:
+ ITrackEnumerator, IEnumerator
+ {
+ #region Private Fields
+
+ private readonly TrackCollection _collection;
+ private readonly int _version;
+ private int _index;
+
+ #endregion
+ #region Internal Constructors
+
+ internal Enumerator(TrackCollection collection)
+ {
+ this._collection = collection;
+ this._version = collection._version;
+ this._index = -1;
+ }
+
+ #endregion
+ #region Public Properties
+
+ public Track Current
+ {
+ get
+ {
+ this._collection.CheckEnumIndex(this._index);
+ this._collection.CheckEnumVersion(this._version);
+ return this._collection[this._index];
+ }
+ }
+
+ object IEnumerator.Current
+ {
+ get { return Current; }
+ }
+
+ #endregion
+ #region Public Methods
+
+ public bool MoveNext()
+ {
+ this._collection.CheckEnumVersion(this._version);
+ return (++this._index < this._collection.Count);
+ }
+
+ public void Reset()
+ {
+ this._collection.CheckEnumVersion(this._version);
+ this._index = -1;
+ }
+
+ #endregion
+ }
+
+ #endregion
+ #region Class ReadOnlyList
+
+ [Serializable]
+ private sealed class ReadOnlyList: TrackCollection
+ {
+ #region Private Fields
+
+ private TrackCollection _collection;
+
+ #endregion
+ #region Internal Constructors
+
+ internal ReadOnlyList(TrackCollection collection):
+ base(Tag.Default)
+ {
+ this._collection = collection;
+ }
+
+ #endregion
+ #region Protected Properties
+
+ protected override Track[] InnerArray
+ {
+ get { return this._collection.InnerArray; }
+ }
+
+ #endregion
+ #region Public Properties
+
+ public override int Capacity
+ {
+ get { return this._collection.Capacity; }
+ set
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified."); }
+ }
+
+ public override int Count
+ {
+ get { return this._collection.Count; }
+ }
+
+ public override bool IsFixedSize
+ {
+ get { return true; }
+ }
+
+ public override bool IsReadOnly
+ {
+ get { return true; }
+ }
+
+ public override bool IsSynchronized
+ {
+ get { return this._collection.IsSynchronized; }
+ }
+
+ public override bool IsUnique
+ {
+ get { return this._collection.IsUnique; }
+ }
+
+ public override Track this[int index]
+ {
+ get { return this._collection[index]; }
+ set
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified."); }
+ }
+
+ public override object SyncRoot
+ {
+ get { return this._collection.SyncRoot; }
+ }
+
+ #endregion
+ #region Public Methods
+
+ public override int Add(Track value)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void AddRange(TrackCollection collection)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void AddRange(Track[] array)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override int BinarySearch(Track value)
+ {
+ return this._collection.BinarySearch(value);
+ }
+
+ public override void Clear()
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override object Clone()
+ {
+ return new ReadOnlyList((TrackCollection) this._collection.Clone());
+ }
+
+ public override void CopyTo(Track[] array)
+ {
+ this._collection.CopyTo(array);
+ }
+
+ public override void CopyTo(Track[] array, int arrayIndex)
+ {
+ this._collection.CopyTo(array, arrayIndex);
+ }
+
+ public override ITrackEnumerator GetEnumerator()
+ {
+ return this._collection.GetEnumerator();
+ }
+
+ public override int IndexOf(Track value)
+ {
+ return this._collection.IndexOf(value);
+ }
+
+ public override void Insert(int index, Track value)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void Remove(Track value)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void RemoveAt(int index)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void RemoveRange(int index, int count)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void Reverse()
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void Reverse(int index, int count)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void Sort()
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void Sort(IComparer comparer)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override void Sort(int index, int count, IComparer comparer)
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ public override Track[] ToArray()
+ {
+ return this._collection.ToArray();
+ }
+
+ public override void TrimToSize()
+ {
+ throw new NotSupportedException(
+ "Read-only collections cannot be modified.");
+ }
+
+ #endregion
+ }
+
+ #endregion
+ #region Class SyncList
+
+ [Serializable]
+ private sealed class SyncList: TrackCollection
+ {
+ #region Private Fields
+
+ private TrackCollection _collection;
+ private object _root;
+
+ #endregion
+ #region Internal Constructors
+
+ internal SyncList(TrackCollection collection):
+ base(Tag.Default)
+ {
+
+ this._root = collection.SyncRoot;
+ this._collection = collection;
+ }
+
+ #endregion
+ #region Protected Properties
+
+ protected override Track[] InnerArray
+ {
+ get { lock (this._root) return this._collection.InnerArray; }
+ }
+
+ #endregion
+ #region Public Properties
+
+ public override int Capacity
+ {
+ get { lock (this._root) return this._collection.Capacity; }
+ set { lock (this._root) this._collection.Capacity = value; }
+ }
+
+ public override int Count
+ {
+ get { lock (this._root) return this._collection.Count; }
+ }
+
+ public override bool IsFixedSize
+ {
+ get { return this._collection.IsFixedSize; }
+ }
+
+ public override bool IsReadOnly
+ {
+ get { return this._collection.IsReadOnly; }
+ }
+
+ public override bool IsSynchronized
+ {
+ get { return true; }
+ }
+
+ public override bool IsUnique
+ {
+ get { return this._collection.IsUnique; }
+ }
+
+ public override Track this[int index]
+ {
+ get { lock (this._root) return this._collection[index]; }
+ set { lock (this._root) this._collection[index] = value; }
+ }
+
+ public override object SyncRoot
+ {
+ get { return this._root; }
+ }
+
+ #endregion
+ #region Public Methods
+
+ public override int Add(Track value)
+ {
+ lock (this._root) return this._collection.Add(value);
+ }
+
+ public override void AddRange(TrackCollection collection)
+ {
+ lock (this._root) this._collection.AddRange(collection);
+ }
+
+ public override void AddRange(Track[] array)
+ {
+ lock (this._root) this._collection.AddRange(array);
+ }
+
+ public override int BinarySearch(Track value)
+ {
+ lock (this._root) return this._collection.BinarySearch(value);
+ }
+
+ public override void Clear()
+ {
+ lock (this._root) this._collection.Clear();
+ }
+
+ public override object Clone()
+ {
+ lock (this._root)
+ return new SyncList((TrackCollection) this._collection.Clone());
+ }
+
+ public override void CopyTo(Track[] array)
+ {
+ lock (this._root) this._collection.CopyTo(array);
+ }
+
+ public override void CopyTo(Track[] array, int arrayIndex)
+ {
+ lock (this._root) this._collection.CopyTo(array, arrayIndex);
+ }
+
+ public override ITrackEnumerator GetEnumerator()
+ {
+ lock (this._root) return this._collection.GetEnumerator();
+ }
+
+ public override int IndexOf(Track value)
+ {
+ lock (this._root) return this._collection.IndexOf(value);
+ }
+
+ public override void Insert(int index, Track value)
+ {
+ lock (this._root) this._collection.Insert(index, value);
+ }
+
+ public override void Remove(Track value)
+ {
+ lock (this._root) this._collection.Remove(value);
+ }
+
+ public override void RemoveAt(int index)
+ {
+ lock (this._root) this._collection.RemoveAt(index);
+ }
+
+ public override void RemoveRange(int index, int count)
+ {
+ lock (this._root) this._collection.RemoveRange(index, count);
+ }
+
+ public override void Reverse()
+ {
+ lock (this._root) this._collection.Reverse();
+ }
+
+ public override void Reverse(int index, int count)
+ {
+ lock (this._root) this._collection.Reverse(index, count);
+ }
+
+ public override void Sort()
+ {
+ lock (this._root) this._collection.Sort();
+ }
+
+ public override void Sort(IComparer comparer)
+ {
+ lock (this._root) this._collection.Sort(comparer);
+ }
+
+ public override void Sort(int index, int count, IComparer comparer)
+ {
+ lock (this._root) this._collection.Sort(index, count, comparer);
+ }
+
+ public override Track[] ToArray()
+ {
+ lock (this._root) return this._collection.ToArray();
+ }
+
+ public override void TrimToSize()
+ {
+ lock (this._root) this._collection.TrimToSize();
+ }
+
+ #endregion
+ }
+
+ #endregion
+ #region Class UniqueList
+
+ [Serializable]
+ private sealed class UniqueList: TrackCollection
+ {
+ #region Private Fields
+
+ private TrackCollection _collection;
+
+ #endregion
+ #region Internal Constructors
+
+ internal UniqueList(TrackCollection collection):
+ base(Tag.Default)
+ {
+ this._collection = collection;
+ }
+
+ #endregion
+ #region Protected Properties
+
+ protected override Track[] InnerArray
+ {
+ get { return this._collection.InnerArray; }
+ }
+
+ #endregion
+ #region Public Properties
+
+ public override int Capacity
+ {
+ get { return this._collection.Capacity; }
+ set { this._collection.Capacity = value; }
+ }
+
+ public override int Count
+ {
+ get { return this._collection.Count; }
+ }
+
+ public override bool IsFixedSize
+ {
+ get { return this._collection.IsFixedSize; }
+ }
+
+ public override bool IsReadOnly
+ {
+ get { return this._collection.IsReadOnly; }
+ }
+
+ public override bool IsSynchronized
+ {
+ get { return this._collection.IsSynchronized; }
+ }
+
+ public override bool IsUnique
+ {
+ get { return true; }
+ }
+
+ public override Track this[int index]
+ {
+ get { return this._collection[index]; }
+ set
+ {
+ CheckUnique(index, value);
+ this._collection[index] = value;
+ }
+ }
+
+ public override object SyncRoot
+ {
+ get { return this._collection.SyncRoot; }
+ }
+
+ #endregion
+ #region Public Methods
+
+ public override int Add(Track value)
+ {
+ CheckUnique(value);
+ return this._collection.Add(value);
+ }
+
+ public override void AddRange(TrackCollection collection)
+ {
+ foreach (Track value in collection)
+ CheckUnique(value);
+
+ this._collection.AddRange(collection);
+ }
+
+ public override void AddRange(Track[] array)
+ {
+ foreach (Track value in array)
+ CheckUnique(value);
+
+ this._collection.AddRange(array);
+ }
+
+ public override int BinarySearch(Track value)
+ {
+ return this._collection.BinarySearch(value);
+ }
+
+ public override void Clear()
+ {
+ this._collection.Clear();
+ }
+
+ public override object Clone()
+ {
+ return new UniqueList((TrackCollection) this._collection.Clone());
+ }
+
+ public override void CopyTo(Track[] array)
+ {
+ this._collection.CopyTo(array);
+ }
+
+ public override void CopyTo(Track[] array, int arrayIndex)
+ {
+ this._collection.CopyTo(array, arrayIndex);
+ }
+
+ public override ITrackEnumerator GetEnumerator()
+ {
+ return this._collection.GetEnumerator();
+ }
+
+ public override int IndexOf(Track value)
+ {
+ return this._collection.IndexOf(value);
+ }
+
+ public override void Insert(int index, Track value)
+ {
+ CheckUnique(value);
+ this._collection.Insert(index, value);
+ }
+
+ public override void Remove(Track value)
+ {
+ this._collection.Remove(value);
+ }
+
+ public override void RemoveAt(int index)
+ {
+ this._collection.RemoveAt(index);
+ }
+
+ public override void RemoveRange(int index, int count)
+ {
+ this._collection.RemoveRange(index, count);
+ }
+
+ public override void Reverse()
+ {
+ this._collection.Reverse();
+ }
+
+ public override void Reverse(int index, int count)
+ {
+ this._collection.Reverse(index, count);
+ }
+
+ public override void Sort()
+ {
+ this._collection.Sort();
+ }
+
+ public override void Sort(IComparer comparer)
+ {
+ this._collection.Sort(comparer);
+ }
+
+ public override void Sort(int index, int count, IComparer comparer)
+ {
+ this._collection.Sort(index, count, comparer);
+ }
+
+ public override Track[] ToArray()
+ {
+ return this._collection.ToArray();
+ }
+
+ public override void TrimToSize()
+ {
+ this._collection.TrimToSize();
+ }
+
+ #endregion
+ #region Private Methods
+
+ private void CheckUnique(Track value)
+ {
+ if (IndexOf(value) >= 0)
+ throw new NotSupportedException(
+ "Unique collections cannot contain duplicate elements.");
+ }
+
+ private void CheckUnique(int index, Track value)
+ {
+ int existing = IndexOf(value);
+ if (existing >= 0 && existing != index)
+ throw new NotSupportedException(
+ "Unique collections cannot contain duplicate elements.");
+ }
+
+ #endregion
+ }
+
+ #endregion
+ }
+
+ #endregion
+}
diff --git a/Freedb/cddbproto.txt b/Freedb/cddbproto.txt
new file mode 100644
index 0000000..4ad21fb
--- /dev/null
+++ b/Freedb/cddbproto.txt
@@ -0,0 +1,885 @@
+CDDB Server Protocol
+--------------------
+
+By Steve Scherf and Ti Kan
+(Protocol level 5 & 6 specification by freedb developer team)
+
+
+Applies to cddbd 1.5.2
+$Id: CDDBPROTO,v 1.10.2.2 2006/04/14 14:45:06 joerg78 Exp $
+
+
+Notation:
+-> : client to server
+<- : server to client
+
+terminating marker: `.' character in the beginning of a line
+
+
+Server response code (three digit code):
+
+First digit:
+1xx Informative message
+2xx Command OK
+3xx Command OK so far, continue
+4xx Command OK, but cannot be performed for some specified reasons
+5xx Command unimplemented, incorrect, or program error
+
+Second digit:
+x0x Ready for further commands
+x1x More server-to-client output follows (until terminating marker)
+x2x More client-to-server input follows (until terminating marker)
+x3x Connection will close
+
+Third digit:
+xx[0-9] Command-specific code
+
+Note: "*" means, that the command is only for administrative use and requires
+special access permissions, that normal users don't have.
+
+
+CDDB Protocol Level 1:
+----------------------
+
+Server sign-on banner:
+----------------------
+<- code hostname CDDBP server version ready at date
+
+ code:
+ 200 OK, read/write allowed
+ 201 OK, read only
+ 432 No connections allowed: permission denied
+ 433 No connections allowed: X users allowed, Y currently active
+ 434 No connections allowed: system load too high
+ hostname:
+ Server host name. Example: xyz.fubar.com
+ version:
+ Version number of server software. Example: v1.0PL0
+ date:
+ Current date and time. Example: Wed Mar 13 00:41:34 1996
+
+
+Initial client-server handshake:
+--------------------------------
+Note: This handshake must occur before other cddb commands
+ are accepted by the server.
+
+Client command:
+-> cddb hello username hostname clientname version
+
+ username:
+ Login name of user. Example: johndoe
+ hostname:
+ Host name of client. Example: abc.fubar.com
+ clientname:
+ The name of the connecting client. Example: xmcd, cda, EasyCD,
+ et cetera. Do not use the name of another client which already
+ exists.
+ version:
+ Version number of client software. Example: v1.0PL0
+
+Server response:
+<- code hello and welcome username@hostname running clientname version
+
+ code:
+ 200 Handshake successful
+ 431 Handshake not successful, closing connection
+ 402 Already shook hands
+
+
+List the genre categories:
+--------------------------
+Client command:
+-> cddb lscat
+
+Server response:
+<- code Okay category list follows (until terminating marker)
+<- category
+<- category
+<- (more categories...)
+<- .
+
+ code:
+ 210 Okay category list follows
+ category:
+ CD category. Example: rock
+
+
+Query database for matching entries:
+------------------------------------
+Client command:
+-> cddb query discid ntrks off1 off2 ... nsecs
+
+ discid:
+ CD disc ID number. Example: f50a3b13
+ ntrks:
+ Total number of tracks on CD.
+ off1, off2, ...:
+ Frame offset of the starting location of each track.
+ nsecs:
+ Total playing length of CD in seconds.
+
+Server response:
+<- code categ discid dtitle
+ or
+<- code close matches found
+<- categ discid dtitle
+<- categ discid dtitle
+<- (more matches...)
+<- .
+
+ code:
+ 200 Found exact match
+ 211 Found inexact matches, list follows (until terminating marker)
+ 202 No match found
+ 403 Database entry is corrupt
+ 409 No handshake
+ categ:
+ CD category. Example: rock
+ discid:
+ CD disc ID number of the found entry. Example: f50a3b13
+ dtitle:
+ The Disc Artist and Disc Title (The DTITLE line). For example:
+ Pink Floyd / The Dark Side of the Moon
+
+
+Read entry from database:
+-------------------------
+Client command:
+-> cddb read categ discid
+
+ categ:
+ CD category. Example: rock
+ discid:
+ CD disc ID number. Example: f50a3b13
+
+Server response:
+<- code categ discid
+<- # xmcd 2.0 CD database file
+<- # ...
+<- (CDDB data...)
+<- .
+ or
+<- code categ discid No such CD entry in database.
+
+ code:
+ 210 OK, CDDB database entry follows (until terminating marker)
+ 401 Specified CDDB entry not found.
+ 402 Server error.
+ 403 Database entry is corrupt.
+ 409 No handshake.
+ categ:
+ CD category. Example: rock
+ discid:
+ CD disc ID number. Example: f50a3b13
+
+
+* Delete entry from database:
+-----------------------------
+Client command:
+-> cddb unlink categ discid
+
+ categ:
+ CD category. Example: rock
+ discid:
+ CD disc ID number. Example: f50a3b13
+
+Server response:
+<- code and message
+
+ code and message:
+ 200 OK, file has been deleted.
+ 401 Permission denied.
+ 402 File access failed.
+ 501 Invalid category: categ.
+ categ:
+ CD category. Example: rock
+
+
+* Write entry to database:
+--------------------------
+Client command:
+-> cddb write categ discid
+
+ categ:
+ CD category. Example: rock
+ discid:
+ CD disc ID number. Example: f50a3b13
+
+Server response:
+<- code and message
+
+ code and message:
+ 320 OK, input CDDB data (until terminating marker)
+ 401 Permission denied.
+ 402 Server file system full/file access failed.
+ 409 No handshake.
+
+Client data:
+-> # xmcd 2.0 CD database file
+-> # ...
+-> (CDDB data)
+-> .
+
+Server response:
+<- code message
+
+ code:
+ 200 CDDB entry accepted
+ 501 Entry rejected: reason for rejection.
+ message:
+ Message string to indicate write status:
+ CDDB entry accepted, or CDDB entry rejected.
+
+
+Discid calculation:
+------------------
+Client command:
+-> discid ntrks off_1 off_2 ... off_n nsecs
+
+ ntrks:
+ total number of tracks on CD.
+ off_X:
+ frame offset of track X.
+ nsecs:
+ total playing length of the CD in seconds.
+
+Server response:
+<- code Disc ID is discid
+
+ code:
+ 200 Calculated disc ID properly
+ 500 Command Syntax error
+ discid:
+ CD disc ID number calculated from the given arguments.
+
+
+* Get a server system file:
+---------------------------
+Client command:
+-> get file
+
+ file:
+ filename of the file to get
+
+Server response:
+
+<- code message
+
+ or
+
+<- code OK, (filename) follows (until terminating `.')
+<- (file content)
+<- .
+
+ code and message:
+ 210 OK, %s follows (until terminating `.')
+ 401 Permission denied.
+ 402 File access failed.
+ 402 File not found.
+
+
+Help information:
+-----------------
+Client command:
+-> help
+ or
+-> help cmd
+
+ cmd:
+ CDDB command. Example: quit
+
+ or
+
+-> help cmd subcmd
+
+ cmd:
+ CDDB command. Example: cddb
+ subcmd:
+ CDDB command argument. Example: query
+
+Server response:
+<- code Help information follows
+<- (help data ...)
+<- .
+ or
+<- code no help information available
+
+ code:
+ 210 OK, help information follows (until terminating marker)
+ 401 No help information available
+
+
+* Log statistics:
+-----------------
+Client command:
+-> log [[-l lines] [start date [end date]] | [day [days]] | [get]]
+
+ lines:
+ The maximum number of lines to print for each data list in the
+ log statistics.
+ start date:
+ The date after which statistics should be calculated. Date is
+ of the format: hh[mm[ss[MM[DD[[CC]YY]]]]]
+
+ E.g.: 201200053196 for 8:12 PM on May 31, 1996.
+ 20120005312096 for 8:12 PM on May 31, 2096.
+ 080530 for today at at 8:15 and 30 seconds.
+
+ If the century ("CC") is omitted, a reasonable guess is made. If
+ this argument is omitted, all messages are considered.
+ end date:
+ The date after which statistics should not be calculated. If
+ omitted, the end date is assumed to be the current date.
+ day:
+ The string "day". This solitary argument will cause a log search
+ of messages generated within the last day.
+ days:
+ A positive numerical argument which modifies the number of days'
+ messages to searh. If this argument is left out, the default is 1.
+ get:
+ The string "get". This solitary argument will cause the server
+ to send the contents of the log file.
+
+Server response:
+<- code Log summary follows
+<- (log stats)
+<- .
+ or
+<- code Log follows
+<- (log stats)
+<- .
+
+ code:
+ 210 OK, log summary follows (until terminating marker)
+ 211 OK, log follows (until terminating marker)
+ 401 Permission denied
+ 402 No log information available
+ 501 Invalid start/end date
+
+
+Message of the day:
+------------------
+Client command:
+-> motd
+
+Server response:
+<- code Last modified: date MOTD follows (until terminating marker)
+<- (message text)
+<- .
+
+ code:
+ 210 Last modified: 05/31/96 06:31:14 MOTD follows (until terminating marker)
+ 401 No message of the day available
+ date:
+ The date the text of the message of the day was modified. The date
+ appears in the following format:
+
+ 05/31/96 06:31:14
+
+ This value may be used by client software as a message timestamp
+ for purposes of determining if it has already been displayed. This
+ format was chosen because it is more easily parsed than the standard
+ ctime() format.
+
+
+Server protocol level:
+----------------------
+Client command:
+-> proto [level]
+
+ level:
+ The (numerical) protocol level to set the server to.
+
+Server response:
+<- code CDDB protocol level: current cur_level, supported supported_level
+ or
+<- code OK, protocol version now: cur_level
+
+ code:
+ 200 CDDB protocol level: current cur_level, supported supp_level
+ 201 OK, protocol version now: cur_level
+ 501 Illegal protocol level.
+ 502 Protocol level already cur_level.
+ cur_level:
+ The current protocol level at which the server is running.
+ supported_level:
+ The maximum supported protocol level.
+
+
+* Put a server system file:
+---------------------------
+Client command:
+-> put file
+
+ file:
+ sites or motd
+
+Server response:
+<- code message
+
+ code and message:
+ 320 OK, input file data (terminate with `.')
+ 401 Permission denied.
+ 402 File access failed.
+ 402 Not a regular file.
+
+Client data:
+-> (file data of the file, that shall be written)
+-> .
+
+Server response
+
+<- code message
+
+ code and message:
+ 200 Put successful.
+ 402 File access failed.
+ 501 Input too long.
+
+
+Close connection to server:
+---------------------------
+Client command:
+-> quit
+
+Server response:
+<- code hostname message
+
+ code and message:
+ 230 Closing connection. Goodbye.
+ 530 error, closing connection.
+ hostname:
+ Server host name. Example: xyz.fubar.com
+
+
+Server sites:
+--------------
+Client command:
+-> sites
+
+Server response:
+<- code OK, site information follows (until terminating `.')
+<- (data)
+<- .
+
+ code:
+ 210 Ok, site information follows
+ 401 No site information available.
+
+ The data format is as follows:
+ site port latitude longitude description
+
+ The fields are as follows:
+ site:
+ The Internet address of the remote site.
+ port:
+ The port at which the server resides on that site.
+ latitude:
+ The latitude of the server site. The format is as follows:
+ CDDD.MM
+ Where "C" is the compass direction (N, S), "DDD" is the
+ degrees, and "MM" is the minutes.
+ longitude:
+ The longitude of the server site. Format is as above, except
+ the compass direction must be one of (E, W).
+ description:
+ A short description of the geographical location of the site.
+
+ Example:
+ us.freedb.org 8880 N037.21 W121.55 San Jose, CA USA
+
+
+Server status:
+--------------
+Client command:
+-> stat
+
+Server response:
+<- code OK, status information follows (until terminating `.')
+<- (data)
+<- .
+
+ code:
+ 210 Ok, status information follows
+
+ The possible data is as follows:
+ current proto:
+ An integer representing the server's current operating protocol
+ level.
+ max proto:
+ The maximum supported protocol level.
+ gets:
+ Whether or not the client is allowed to get log information,
+ according to the string "yes" or "no".
+ updates:
+ Whether or not the client is allowed to initiate a database
+ update, according to the string "yes" or "no".
+ posting:
+ Whether or not the client is allowed to post new entries,
+ according to the string "yes" or "no".
+ quotes:
+ Whether or not quoted arguments are enabled, according to
+ the string "yes" or "no".
+ current users:
+ The number of users currently connected to the server.
+ max users:
+ The number of users that can concurrently connect to the server.
+ strip ext:
+ Whether or not extended data is stripped by the server before
+ presented to the user.
+ Database entries:
+ The total number of entries in the database.
+ Database entries by category:
+ This field is followed by a list of catgories and the number
+ of entries in that category. Each entry is of the following
+ format:
+
+ catgory:
+
+ The list of entries is terminated by the first line that does
+ not begin with white space.
+
+ * Pending file transmissions:
+ This field is followed by a list of sites that are fed new
+ database entries at periodic intervals, and the number of
+ entries that have yet to be transmitted to that site.
+ Each entry is of the following format:
+
+ site:
+
+ The list of entries is terminated by the first line that does
+ not begin with white space.
+
+ This list may grow as needed, so clients must expect possible
+ unrecognizable data. Also, additional fields may be added to
+ the currently existing lines, although no existing fields will
+ be removed or change position.
+
+
+* Database update:
+----------------
+Client command:
+-> update
+
+Server response:
+<- code Updating the database.
+ or
+<- code Permission denied.
+ or
+<- code Unable to update the database.
+
+ code:
+ 200 Updating the database.
+ 401 Permission denied.
+ 402 Unable to update the database.
+
+
+* Perform user validation:
+--------------------------
+Client command:
+-> validate
+
+Server response:
+<- 503 Validation not required.
+
+or
+
+<- 320 OK, input validation string, salt=saltvalue (terminate with newline)
+
+Client data:
+-> validation string
+
+Server response:
+
+-> code message
+
+ code and message:
+ 200 Validation successful.
+ 501 Incorrect validation string length.
+ 502 Invalid validation string.
+
+
+Server version:
+---------------
+Client command:
+-> ver
+
+Server response:
+<- code servername version copyright
+ or
+<- code Version information follows
+
+ code:
+ 200 Version information.
+ 211 OK, version information follows (until terminating marker)
+ version:
+ Server version. Example: v1.5PL0
+ copyright:
+ Copyright string. Example: Copyright (c) 1996-2001 Steve Scherf et al.
+
+
+* Server users:
+---------------
+Client command:
+-> whom
+
+Server response:
+<- code message
+
+ code and message:
+ 210 OK, user list follows (until terminating marker)
+ 401 No user information available.
+
+
+General errors:
+---------------
+
+Server response:
+<- code error
+ code:
+ 402 Server error.
+ 408 CGI environment error.
+ 500 Command syntax error, command unknown, command unimplemented.
+ 530 Server error, server timeout.
+
+
+Reserved errors:
+----------------
+
+The following error codes are reserved, and will never be returned as a
+response to a CDDB protocol command. They are intended to be used internally
+by clients that have a need for generating pseudo-responses.
+
+ 600-699
+
+
+CDDB Protocol Level 2:
+----------------------
+
+In all respects, protocol level 2 is the same as level 1, with the exceptions
+listed below.
+
+Arguments to commands may be surrounded by double quotes. All characters
+within the quotes, including white space, are included in the argument. All
+white space is replaced by the `_' (2Dh) character by the server. White space
+is defined as ` ' (20h) and `^I' (control-I, or 09h).
+
+Arguments containing quotes that should not be interpreted with the special
+meaning described above should be escaped with a preceding backslash character,
+or '\' (5Ch). If an actual backslash appears in an argument, it should be
+escaped with a preceding backslash. In both cases, the preceding backslash
+will be removed from the input before being interpreted.
+
+
+CDDB Protocol Level 3:
+----------------------
+
+Protocol level 3 is the same as level 2, with the exception listed below.
+
+The output of the "sites" command has changed to meet the folowing description:
+
+ The data format is as follows:
+ site protocol port address latitude longitude description
+
+ The fields are as follows:
+ site:
+ The Internet address of the remote site.
+ protocol:
+ The transfer protocol used to access the site.
+ port:
+ The port at which the server resides on that site.
+ address:
+ Any additional addressing information needed to access the
+ server. For example, for HTTP protocol servers, this would be
+ the path to the CDDB server CGI script. This field will be
+ "-" if no additional addressing information is needed.
+ latitude:
+ The latitude of the server site. The format is as follows:
+ CDDD.MM
+ Where "C" is the compass direction (N, S), "DDD" is the
+ degrees, and "MM" is the minutes.
+ longitude:
+ The longitude of the server site. Format is as above, except
+ the compass direction must be one of (E, W).
+ description:
+ A short description of the geographical location of the site.
+
+ Example:
+ us.freedb.org cddbp 8880 - N037.21 W121.55 San Jose, CA USA
+ us.freedb.org http 80 /~cddb/cddb.cgi N037.21 W121.55 San Jose, CA USA
+
+Note that a site may appear once for each type of protocol it supports for
+accessing the server.
+
+
+CDDB Protocol Level 4:
+----------------------
+
+Protocol level 4 is the same as level 3, with the exception listed below.
+
+The output of the "cddb query" command may result in multiple exact matches.
+A new response code, 210, has been added to indicate that more than one
+exact match has been found.
+
+Server response:
+----------------
+<- code exact matches found
+<- categ discid dtitle
+<- categ discid dtitle
+<- (more matches...)
+<- .
+
+ code:
+ 210 Found exact matches, list follows (until terminating marker)
+
+
+CDDB Protocol Level 5:
+----------------------
+
+Protocol level 5 is the same as level 4, with the following exception:
+
+The database entries returned when issuing the "cddb read" command now also
+contain DYEAR and DGENRE fields (between the DTITLE and the TTITLE's).
+For more info on the new database entry fields take a look at the
+database format specification
+
+
+CDDB Protocol Level 6:
+----------------------
+
+Protocol level 6 is the same as level 5 except that the character set
+is now UTF-8 instead of ISO-8859-1. Note that UTF-8 is an extension of
+US-ASCII, just like ISO-8859-1 is an extension of US-ASCII, so there
+is no difference between levels 5 and 6 as far as 7-bit ASCII data is
+concerned.
+
+Clients can convert data between UTF-8 and the user's preferred
+character set using the iconv program and library function which are
+provided by glibc-2.2 or by the portable library libiconv. (They are
+also provided by the C library on some non-glibc systems, but often in
+a buggy or incompatible form.) For example, to convert data to UTF-8
+from the character set of the current locale in a shell script use
+"iconv -t utf-8 < in > out".
+
+For more information about Unicode and UTF-8 see:
+
+ ftp://ftp.ilog.fr/pub/Users/haible/utf8/Unicode-HOWTO.html
+ http://www.cl.cam.ac.uk/~mgk25/unicode.html
+
+
+Addendum A: Proper use of CDDBP:
+--------------------------------
+
+There are a few guidelines that must be followed in order to make proper use
+of CDDBP:
+
+- When handshaking with the server via the "cddb hello" command, the client
+ must specify its own name and version, not that of some other client (such
+ as xmcd).
+
+- Before performing a "cddb read", the client program MUST perform a
+ "cddb query". Failure to do so may result in the client program receiving
+ incorrect data from the server. Also, without performing a query, the
+ client program will not benefit from close matches in the event of the
+ lack of an exact match in the database.
+
+
+Addendum B: CDDBP under HTTP:
+-----------------------------
+
+Accessing a server as a CGI script is done in much the same way as through
+direct interaction. The command set is identical, though the method of
+communication is through CDDBP commands encapsulated in the HTTP protocol.
+The only limitation is that a single command may be executed per connection,
+since HTTP is not truly interactive. For the server to be accessed in this
+way, it must reside on the target host at a known URL which is accessible by
+the host HTTP server. The client program must connect to the HTTP server on
+the target host and issue an HTTP command with the appropriate CDDBP command
+encapsulated within.
+
+Commands may be submitted to servers in CGI mode using either the "GET" or
+"POST" HTTP commands. Both methods are supported, and there is no real
+difference between how both are to be used other than the syntactical
+difference between the two methods. The "POST" method may provide the ability
+to issue longer commands, though, depending on the architecture of the system
+on which the server resides.
+
+The server command must be sent as part of the "Request-URL" in the case
+of the "GET" method, and as the "Entity-Body" in the case of the "POST"
+method. In both cases, the command must be of the following form:
+
+cmd=server+command&hello=joe+my.host.com+clientname+version&proto=6
+
+Where the text following the "cmd=" represents the CDDBP command to be
+executed, the text following the "hello=" represents the arguments to
+the "cddb hello" command that is implied by this operation, and the
+text following the "proto=" represents the argument to the "proto" command
+that is implied by this operation.
+
+The "+" characters in the input represent spaces, and will be translated
+by the server before performing the request. Special characters may be
+represented by the sequence "%XX" where "XX" is a two-digit hex number
+corresponding to the ASCII (ISO-8859-1) sequence of that character. The
+"&" characters denote separations between the command, hello and proto
+arguments. Newlines and carriage returns must not appear anywhere in the
+string except at the end.
+
+All CDDBP commands are supported under HTTP, except for "cddb hello",
+"cddb write", "proto", "put", "validate" and "quit".
+
+For example, should user "joe" on system "my.host.com" be running xmcd 2.1,
+a read request for his currenly playing CD might look like this:
+
+cmd=cddb+read+rock+12345678&hello=joe+my.host.com+xmcd+2.1&proto=3
+
+The server will perform the implied "proto" and "cddb hello" commands,
+and then perform the requested "cddb read" command.
+
+Server response to the command is encapsulated in the HTTP server response,
+and appears in the "Entity-Body" exactly as it would appear using the CDDBP
+protocol. Note that the HTTP response "Entity-Header" is not guaranteed to
+contain a "Content-Length" field, so clients should be prepared to accept
+variable length input. This is no different from operation under CDDBP. The
+header will always contain a Mime "Content-Type" field which describes the
+body of data as "text/plain".
+
+For more detailed information on HTTP and Mime, see RFC 1945 and RFC 1521.
+
+
+Addendum C: CDDBP under SMTP:
+-----------------------------
+
+The use of e-mail mode (SMTP) commands is simple. A special subject line
+lets the server know that the e-mail contains a command, and somewhere in the
+body there should be a HTTP-style server command; the server will execute
+only one such commands per e-mail.
+
+The subject for e-mail commands should look like this:
+
+Subject: cddb #command arbitrary_string
+
+The "arbitrary_string" should be some randomly-chosen string. The server
+will include this string in the subject of the response. The rest of the
+subject should appear literally as it does here.
+
+Somewhere in the body of the e-mail should be exactly one server command. For
+example:
+
+cmd=motd&hello=joe+my.host.com+xmcd_via_email+v1.0&proto=6
+
+As you might have noticed, this command is exactly the same as a HTTP-mode
+CDDBP command. The command response will be mailed to the sender. Upon
+successful completion of an e-mail command request (even if the command
+itself was not successful), the reply will contain a subject which looks
+like this:
+
+Subject cddb #response ok arbitrary_string
+
+Should the server be unable to process the e-mail command for some reason, the
+subject will look like this:
+
+Subject cddb #response failed arbitrary_string
+
+In both cases, the "arbitrary_string" is the same as the one specified in the
+initial command e-mail.
diff --git a/MAC_SDK/Source/MACLib/Assembly/Assembly.obj b/MAC_SDK/Source/MACLib/Assembly/Assembly.obj
index c1db5fd..e2165b5 100644
Binary files a/MAC_SDK/Source/MACLib/Assembly/Assembly.obj and b/MAC_SDK/Source/MACLib/Assembly/Assembly.obj differ