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