<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Newtonsoft.Json</RootNamespace>
<AssemblyName>Newtonsoft.Json</AssemblyName>
- <SignAssembly>false</SignAssembly>
- <AssemblyOriginatorKeyFile>
- </AssemblyOriginatorKeyFile>
+ <SignAssembly>true</SignAssembly>
+ <AssemblyOriginatorKeyFile>Dynamic.snk</AssemblyOriginatorKeyFile>
<SccProjectName>
</SccProjectName>
<SccLocalPath>
#elif NET35
[assembly: InternalsVisibleTo("Newtonsoft.Json.Tests.Net35")]
#else
-[assembly: InternalsVisibleTo("Newtonsoft.Json.Tests")]
+//[assembly: InternalsVisibleTo("Newtonsoft.Json.Tests")]
#endif
#else
<CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
<CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
</PropertyGroup>
+ <PropertyGroup>
+ <SignAssembly>true</SignAssembly>
+ </PropertyGroup>
+ <PropertyGroup>
+ <AssemblyOriginatorKeyFile>pithos.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Compile Include="TaskSchedulers\WorkStealingTaskScheduler.cs" />
<Compile Include="Utils\SortedTopN.cs" />
</ItemGroup>
+ <ItemGroup>
+ <None Include="pithos.snk" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
<CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
</PropertyGroup>
+ <PropertyGroup>
+ <SignAssembly>true</SignAssembly>
+ </PropertyGroup>
+ <PropertyGroup>
+ <AssemblyOriginatorKeyFile>pithos.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
</EmbeddedResource>
<None Include="app.config" />
<None Include="packages.config" />
+ <None Include="pithos.snk" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
- <ListBox Name="Settings_Accounts" SelectedItem="{Binding CurrentAccount}" Grid.Row="0"
+ <ListBox Name="Settings_Accounts" SelectedIndex="{Binding SelectedAccountIndex}" Grid.Row="0"
VerticalAlignment="Stretch" >
<ListBox.ItemTemplate>
<DataTemplate>
- <TextBlock Text="{Binding AccountName}"/>
+ <TextBlock Text="{Binding AccountName}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Name="RemoveAccount" Content="Remove" Style="{StaticResource ButtonStyle}" Width="50"/>
</StackPanel>
</Grid>
- <GroupBox Header="Account" Padding="5" Margin="5" Height="137" HorizontalAlignment="Stretch" VerticalAlignment="Top" Width="272">
+ <GroupBox Header="Account" Padding="5" Margin="5" Height="160" HorizontalAlignment="Stretch" VerticalAlignment="Top" Width="272">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
+ <RowDefinition Height="Auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<Label Content="Account" Grid.Column="0" Grid.Row="0" Margin="0,5" HorizontalAlignment="Left"/>
<TextBox Name="CurrentAccount_AccountName" Grid.Column="1" Grid.Row="0" Margin="5"/>
<Label Content="API Key" Grid.Column="0" Grid.Row="1" Margin="0,5" HorizontalAlignment="Left"/>
<TextBox Name="CurrentAccount_ApiKey" Grid.Column="1" Grid.Row="1" Margin="5"/>
- <Button Name="SelectSyncFolders" Content="Selective Sync" Width="Auto" HorizontalAlignment="Left" Style="{StaticResource ButtonStyle}" Grid.Column="1" Grid.Row="2"/>
+ <CheckBox Name="CurrentAccount_IsActive" Content="Account is Active" Grid.Column="1" Grid.Row="2" Margin="5"/>
+ <Button Name="SelectSyncFolders" Content="Selective Sync" Width="Auto" HorizontalAlignment="Left" Style="{StaticResource ButtonStyle}" Grid.Column="1" Grid.Row="3"/>
+
</Grid>
</GroupBox>
</StackPanel>
using System.Diagnostics;
using System.IO;
using System.IO.IsolatedStorage;
+using System.Linq.Expressions;
using System.Net;
+using System.Reflection;
using System.Runtime.Serialization;
using System.Windows;
using System.Windows.Forms;
Settings=settings;
Monitor=monitor;
-
-
-
Taskbar.UsageMessage = "Using 15% of 50 GB";
Taskbar.RecentFiles.AddRange(new[]
Taskbar.StatusMessage = "In Synch";
Taskbar.UpdateStatus();
}
+
protected override void OnViewAttached(object view, object context)
{
var window = (Window)view;
-/*
- window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
- window.ShowInTaskbar = false;
-*/
base.OnViewAttached(view, context);
}
#region Commands
- /*public void ShowPreferences()
- {
- Settings.Reload();
-
- var window = (Window)this.GetView();
- window.Show();
- }*/
-
-
- /*public PithosCommand OpenPithosFolderCommand { get; private set; }
-
- public void OpenPithosFolder()
- {
- Process.Start(Settings.PithosPath);
- }
-
- public void GoToSite()
- {
-
- }
-
- public void ToggleSynching()
- {
-
- }
-*/
+
public void SaveChanges()
{
DoSave();
- /*var window = (Window)GetView();
- window.Hide();*/
+
}
public void RejectChanges()
{
Settings.Reload();
- /* var window = (Window)GetView();
- window.Hide();*/
+
}
public void ApplyChanges()
private void DoSave()
{
Settings.Save();
+ NotifyOfPropertyChange(()=>Settings);
Monitor.Start();
}
Settings.PithosPath = newPath;
Settings.Save();
NotifyOfPropertyChange(() => Settings);
+
}
}
- /* public void ExitPithos()
- {
- Monitor.Stop();
- this.TryClose();
- }
-*/
-
- public void AddAccount()
+ public void AddAccount()
{
var newAccount = new AccountSettings();
Settings.Accounts.Add(newAccount);
- CurrentAccount = newAccount;
+ SelectedAccountIndex= Settings.Accounts.Count-1;
NotifyOfPropertyChange(()=>Settings);
}
public void RemoveAccount()
{
-// var idx = Settings.Accounts.IndexOf(CurrentAccount);
Settings.Accounts.RemoveAll(account => account.AccountName == CurrentAccount.AccountName);
-// Settings.Accounts.RemoveAt(idx);
- CurrentAccount = null;
+
+ NotifyOfPropertyChange(()=>CurrentAccount);
NotifyOfPropertyChange(()=>Settings);
- NotifyOfPropertyChange("Settings.Accounts");
+ //NotifyOfPropertyChange("Settings.Accounts");
}
public bool CanRemoveAccount
}
#endregion
- private AccountSettings _currentAccount;
- public AccountSettings CurrentAccount
+ private int _selectedAccountIndex;
+ public int SelectedAccountIndex
{
- get { return _currentAccount; }
+ get { return _selectedAccountIndex; }
set
{
- _currentAccount = value;
- NotifyOfPropertyChange(()=>CurrentAccount);
- NotifyOfPropertyChange(()=>CanRemoveAccount);
+ _selectedAccountIndex = value;
+ NotifyOfPropertyChange(() => CurrentAccount);
+ NotifyOfPropertyChange(() => CanRemoveAccount);
+ NotifyOfPropertyChange(()=>SelectedAccountIndex);
}
}
-
-
- /* private void UnregisterExtensions()
+ private AccountSettings _currentAccount;
+ public AccountSettings CurrentAccount
{
- using (var installer = new ProjectInstaller())
+ get { return Settings.Accounts[SelectedAccountIndex]; }
+/*
+ set
{
- IDictionary state = ShellExtensionController.LoadState();
- installer.Uninstall(state);
+ _currentAccount = value;
}
+*/
}
- private void RegisterExtensions()
- {
- using (var installer = new ProjectInstaller())
- {
- IDictionary state = new Dictionary<object, object>();
- installer.Install(state);
- ShellExtensionController.SaveState(state);
- }
- }*/
}
}
<AccountSettings>
<AccountName>pkanavos</AccountName>
<ApiKey>9d3cb7b231e96f72ebe96af1c6cd5112</ApiKey>
+ <IsActive>true</IsActive>
<SelectiveFolders />
</AccountSettings>
</ArrayOfAccountSettings>")]
<AccountSettings>
<AccountName>pkanavos</AccountName>
<ApiKey>9d3cb7b231e96f72ebe96af1c6cd5112</ApiKey>
+ <IsActive>true</IsActive>
<SelectiveFolders />
</AccountSettings>
</ArrayOfAccountSettings></Value>
using System.ComponentModel.Composition;
using System.Diagnostics;
+using System.IO;
using System.Windows;
using Caliburn.Micro;
using Pithos.Client.WPF.Properties;
Settings = settings;
Monitor = monitor;
+ var account=settings.Accounts.FirstOrDefault(act => act.IsActive);
+ if (account != null)
+ {
+ Monitor.UserName = account.AccountName;
+ Monitor.ApiKey = account.ApiKey;
+ Monitor.RootPath = Path.Combine(Settings.PithosPath, account.RootPath??"");
+ }
+
}
#region Status Properties
StatusIcon = String.Format(@"Images/{0}.ico", info.IconName);
StatusMessage = String.Format("Pithos 1.0\r\n{0}", info.StatusText);
}
- if (!String.IsNullOrWhiteSpace(Settings.UserName) &&
- !String.IsNullOrWhiteSpace(Settings.ApiKey))
+ if (!String.IsNullOrWhiteSpace(Monitor.UserName) &&
+ !String.IsNullOrWhiteSpace(Monitor.ApiKey))
Monitor.Start();
}
}
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
- <section name="Pithos.Client.WPF.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>
+ <section name="Pithos.Client.WPF.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
- <section name="Pithos.Client.WPF.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/>
+ <section name="Pithos.Client.WPF.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
- <assemblyIdentity name="Caliburn.Micro" publicKeyToken="8e5891231f2ed21f" culture="neutral"/>
- <bindingRedirect oldVersion="0.0.0.0-1.2.0.0" newVersion="1.2.0.0"/>
+ <assemblyIdentity name="Caliburn.Micro" publicKeyToken="8e5891231f2ed21f" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-1.2.0.0" newVersion="1.2.0.0" />
</dependentAssembly>
<dependentAssembly>
- <assemblyIdentity name="NHibernate" publicKeyToken="aa95f207798dfdb4" culture="neutral"/>
- <bindingRedirect oldVersion="0.0.0.0-3.1.0.4000" newVersion="3.1.0.4000"/>
+ <assemblyIdentity name="NHibernate" publicKeyToken="aa95f207798dfdb4" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-3.1.0.4000" newVersion="3.1.0.4000" />
</dependentAssembly>
<dependentAssembly>
- <assemblyIdentity name="NHibernate.ByteCode.Castle" publicKeyToken="aa95f207798dfdb4" culture="neutral"/>
- <bindingRedirect oldVersion="0.0.0.0-3.1.0.4000" newVersion="3.1.0.4000"/>
+ <assemblyIdentity name="NHibernate.ByteCode.Castle" publicKeyToken="aa95f207798dfdb4" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-3.1.0.4000" newVersion="3.1.0.4000" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<value>C:\Program Files\Common Files\TortoiseOverlays\icons\XPStyle</value>
</setting>
<setting name="ProxyServer" serializeAs="String">
- <value/>
+ <value />
</setting>
<setting name="ProxyPort" serializeAs="String">
<value>8080</value>
</setting>
<setting name="ProxyUsername" serializeAs="String">
- <value/>
+ <value />
</setting>
<setting name="ProxyPassword" serializeAs="String">
- <value/>
+ <value />
</setting>
<setting name="ProxyAuthentication" serializeAs="String">
<value>False</value>
<setting name="UseManualProxy" serializeAs="String">
<value>False</value>
</setting>
+ <setting name="Accounts" serializeAs="Xml">
+ <value>
+ <ArrayOfAccountSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <AccountSettings>
+ <AccountName>pkanavos</AccountName>
+ <ApiKey>9d3cb7b231e96f72ebe96af1c6cd5112</ApiKey>
+ <IsActive>true</IsActive>
+ <SelectiveFolders />
+ </AccountSettings>
+ </ArrayOfAccountSettings>
+ </value>
+ </setting>
</Pithos.Client.WPF.Properties.Settings>
</userSettings>
<connectionStrings>
- <add name="Sqlite_InMemory" providerName="System.Data.SQLite" connectionString="Data Source=:memory:;Version=3;New=True"/>
+ <add name="Sqlite_InMemory" providerName="System.Data.SQLite" connectionString="Data Source=:memory:;Version=3;New=True" />
</connectionStrings>
<system.data>
<DbProviderFactories>
- <remove invariant="System.Data.SQLite"/>
- <add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".Net Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite"/>
+ <remove invariant="System.Data.SQLite" />
+ <add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".Net Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" />
</DbProviderFactories>
</system.data>
<startup useLegacyV2RuntimeActivationPolicy="true">
- <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/>
+ <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client" />
</startup>
<applicationSettings>
<Pithos.Client.WPF.Properties.Settings>
</setting>
</Pithos.Client.WPF.Properties.Settings>
</applicationSettings>
-</configuration>
+</configuration>
\ No newline at end of file
}
+ public void Stop()
+ {
+ throw new NotImplementedException();
+ }
+
private PithosStatus _pithosStatus = PithosStatus.InSynch;
public void SetPithosStatus(PithosStatus status)
[ActiveRecord]
public class FileState:ActiveRecordLinqBase<FileState>
{
+ private string _filePath;
+
[PrimaryKey]
- public string FilePath { get; set; }
+ public string FilePath
+ {
+ get { return _filePath; }
+ set { _filePath = value.ToLower(); }
+ }
[Property]
public FileOverlayStatus OverlayStatus { get; set; }
void SetPithosStatus(PithosStatus status);
FileOverlayStatus GetFileOverlayStatus(string path);
IEnumerable<string> StoreUnversionedFiles(ParallelQuery<string> paths);
+ void Stop();
}
[ContractClassFor(typeof(IStatusKeeper))]
return default(IEnumerable<string>);
}
+ public void Stop()
+ {
+
+ }
+
public void ClearFileStatus(string path)
{
Contract.Requires(!String.IsNullOrWhiteSpace(path));
return files.GetConsumingEnumerable();
}
+ public void Stop()
+ {
+
+ }
+
private PithosStatus _pithosStatus = PithosStatus.InSynch;
public void SetPithosStatus(PithosStatus status)
<CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
<CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
</PropertyGroup>
+ <PropertyGroup>
+ <SignAssembly>true</SignAssembly>
+ </PropertyGroup>
+ <PropertyGroup>
+ <AssemblyOriginatorKeyFile>pithos.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
<ItemGroup>
- <Reference Include="Castle.ActiveRecord">
- <HintPath>..\packages\Castle.Activerecord.3.0.0.1\lib\Net40\Castle.ActiveRecord.dll</HintPath>
+ <Reference Include="Castle.ActiveRecord, Version=3.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
+ <HintPath>..\Libraries\Castle.ActiveRecord.dll</HintPath>
</Reference>
- <Reference Include="Castle.ActiveRecord.Web">
- <HintPath>..\packages\Castle.Activerecord.3.0.0.1\lib\Net40\Castle.ActiveRecord.Web.dll</HintPath>
+ <Reference Include="Castle.Components.Validator, Version=2.5.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
+ <HintPath>..\Libraries\Castle.Components.Validator.dll</HintPath>
</Reference>
- <Reference Include="Castle.Components.Validator">
- <HintPath>..\packages\Castle.Components.Validator.2.5.0\lib\NET40\Castle.Components.Validator.dll</HintPath>
+ <Reference Include="Castle.Core, Version=2.5.1.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
+ <HintPath>..\Libraries\Castle.Core.dll</HintPath>
</Reference>
- <Reference Include="Castle.Core">
- <HintPath>..\packages\Castle.Core.2.5.2\lib\NET35\Castle.Core.dll</HintPath>
+ <Reference Include="Iesi.Collections, Version=1.0.1.0, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL">
+ <HintPath>..\Libraries\Iesi.Collections.dll</HintPath>
</Reference>
- <Reference Include="Iesi.Collections">
- <HintPath>..\packages\Iesi.Collections.3.1.0.4000\lib\Net35\Iesi.Collections.dll</HintPath>
+ <Reference Include="log4net">
+ <HintPath>..\Libraries\log4net.dll</HintPath>
</Reference>
- <Reference Include="Microsoft.WindowsAPICodePack">
- <HintPath>..\packages\Windows7APICodePack.1.0.0.0\lib\Microsoft.WindowsAPICodePack.dll</HintPath>
+ <Reference Include="Microsoft.WindowsAPICodePack, Version=1.1.0.0, Culture=neutral, PublicKeyToken=2cc55badaa91f4de, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\Libraries\Microsoft.WindowsAPICodePack.dll</HintPath>
</Reference>
- <Reference Include="NHibernate">
- <HintPath>..\packages\NHibernate.3.1.0.4000\lib\Net35\NHibernate.dll</HintPath>
+ <Reference Include="NHibernate, Version=3.1.0.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL">
+ <HintPath>..\Libraries\NHibernate.dll</HintPath>
</Reference>
- <Reference Include="NHibernate.ByteCode.Castle">
- <HintPath>..\packages\NHibernate.Castle.3.1.0.4000\lib\Net35\NHibernate.ByteCode.Castle.dll</HintPath>
+ <Reference Include="NHibernate.ByteCode.Castle, Version=3.1.0.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL">
+ <HintPath>..\Libraries\NHibernate.ByteCode.Castle.dll</HintPath>
</Reference>
- <Reference Include="NHibernate.Search">
- <HintPath>..\packages\Castle.Activerecord.3.0.0.1\lib\Net40\NHibernate.Search.dll</HintPath>
+ <Reference Include="NHibernate.Search, Version=0.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
+ <HintPath>..\Libraries\NHibernate.Search.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Compile Include="FileState.cs" />
<Compile Include="IStatusService.cs" />
<Compile Include="Signature.cs" />
- <Compile Include="StatusChecker.cs" />
+ <Compile Include="StatusKeeper.cs" />
<Compile Include="IPithosWorkflow.cs" />
<Compile Include="IStatusKeeper.cs" />
<Compile Include="NativeMethods.cs" />
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
+ <None Include="pithos.snk" />
</ItemGroup>
<ItemGroup>
<Content Include="DbConfig.xml">
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using Castle.ActiveRecord.Queries;
using Microsoft.WindowsAPICodePack.Net;
using Pithos.Interfaces;
using System.ServiceModel;
[Import]
public ICloudClient CloudListeningClient { get; set; }
+ public string UserName { get; set; }
+ public string ApiKey { get; set; }
+
private ServiceHost _statusService { get; set; }
private FileSystemWatcher _watcher;
}
}
+ public string RootPath { get; set; }
+
CancellationTokenSource _cancellationSource;
}
_cancellationSource = new CancellationTokenSource();
- string path = Settings.PithosPath;
var proxyUri = ProxyFromSettings();
CloudClient.Proxy = proxyUri;
- IndexLocalFiles(path);
- StartMonitoringFiles(path);
+ //CloudClient.UsePithos = true;
+ IndexLocalFiles(RootPath);
+ StartMonitoringFiles(RootPath);
StartStatusService();
select filePath;
StatusKeeper.StoreUnversionedFiles(files);
- var newFiles= FileState.FindAllByProperty("OverlayStatus", FileOverlayStatus.Unversioned)
- .Select(state=>state.FilePath);
- foreach (var newFile in newFiles)
- {
- _uploadEvents.Add(new WorkflowState
- {
- Path = newFile,
- FileName = Path.GetFileName(newFile),
- TriggeringChange = WatcherChangeTypes.Created
- });
- }
-
+ RestartInterruptedFiles();
}
catch (Exception exc)
{
}
}
+ private void RestartInterruptedFiles()
+ {
+ var interruptedStates = new[] { FileOverlayStatus.Unversioned, FileOverlayStatus.Synch };
+ var filesQuery = from state in FileState.Queryable
+ where interruptedStates.Contains(state.OverlayStatus)
+ select new WorkflowState
+ {
+ Path = state.FilePath.ToLower(),
+ FileName = Path.GetFileName(state.FilePath).ToLower(),
+ Status=state.OverlayStatus==FileOverlayStatus.Unversioned?
+ FileStatus.Created:
+ FileStatus.Modified,
+ TriggeringChange = state.OverlayStatus==FileOverlayStatus.Unversioned?
+ WatcherChangeTypes.Created:
+ WatcherChangeTypes.Changed
+ };
+ _uploadEvents.AddFromEnumerable(filesQuery,false);
+
+ }
+
private void StartStatusService()
{
// Create a ServiceHost for the CalculatorService type and provide the base address.
try
{
-
- CloudClient.Authenticate(Settings.UserName, Settings.ApiKey);
+ CloudClient.UsePithos = false;
+ CloudClient.Authenticate(UserName, ApiKey);
- StartListening(Settings.PithosPath);
+ StartListening(RootPath);
StartSending();
}
catch (Exception)
var localFile = action.LocalFile;
var cloudFile = action.CloudFile;
var downloadPath = (cloudFile == null)? String.Empty
- : Path.Combine(Settings.PithosPath,cloudFile.Name);
+ : Path.Combine(RootPath,cloudFile.Name);
try
{
switch (action.Action)
catch (Exception exc)
{
Trace.TraceError("[REQUEUE] {0} : {1} -> {2} due to exception\r\n{3}",
- action.Action, action.LocalFile,action.CloudFile,exc);
- Trace.TraceError(exc.ToString());
+ action.Action, action.LocalFile,action.CloudFile,exc);
_listenerActions.Add(action);
}
throw;
}
catch(Exception ex)
- {}
+ {
+ Trace.TraceError("[ERROR] Synch for {0}:\r{1}",state.FileName,ex);
+ }
}
},_cancellationSource.Token);
{
Contract.Requires(!Path.IsPathRooted(fileName));
//Even if GetObjectInfo times out, we can proceed with the upload
- var info=CloudClient.GetObjectInfo("PITHOS", fileName);
- if ( hash != info.Hash)
+ var info = CloudClient.GetObjectInfo("PITHOS", fileName);
+ Task.Factory.StartNew(() =>
{
- this.StatusKeeper.SetFileOverlayStatus(path, FileOverlayStatus.Synch);
-
- CloudClient.PutObject("PITHOS", fileName, path, hash).Wait();
+ if (hash != info.Hash)
+ {
+ Task.Factory.StartNew(() =>
+ this.StatusKeeper.SetFileOverlayStatus(path, FileOverlayStatus.Synch))
+ .ContinueWith(t =>
+ CloudClient.PutObject("PITHOS", fileName, path, hash));
+ }
}
- this.StatusKeeper.SetFileStatus(path,FileStatus.Unchanged);
- this.StatusKeeper.SetFileOverlayStatus(path,FileOverlayStatus.Normal);
+ )
+ .ContinueWith(t =>{
+ this.StatusKeeper.SetFileStatus(path, FileStatus.Unchanged);
+ this.StatusKeeper.SetFileOverlayStatus(path, FileOverlayStatus.Normal);
+ })
+ .Wait();
Workflow.RaiseChangeNotification(path);
}
--- /dev/null
+using System.IO;
+using System.Security.Cryptography;
+using System.Text;
+
+public static class Signature
+{
+ public static string CalculateHash(string path)
+ {
+ string hash;
+ using (var hasher = MD5.Create())
+ using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, true))
+ {
+ var hashBytes = hasher.ComputeHash(stream);
+ var hashBuilder = new StringBuilder();
+ foreach (byte b in hashBytes)
+ hashBuilder.Append(b.ToString("x2").ToLower());
+ hash = hashBuilder.ToString();
+ }
+ return hash;
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.ComponentModel.Composition;
+using System.Diagnostics;
+using System.Diagnostics.Contracts;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Castle.ActiveRecord;
+using Castle.ActiveRecord.Framework;
+using Castle.ActiveRecord.Framework.Config;
+using Pithos.Interfaces;
+
+namespace Pithos.Core
+{
+ [Export(typeof(IStatusChecker)),Export(typeof(IStatusKeeper))]
+ public class StatusKeeper:IStatusChecker,IStatusKeeper
+ {
+ [System.ComponentModel.Composition.Import]
+ public IPithosSettings Settings { get; set; }
+
+ private BlockingCollection<Action> _statusUpdateQueue = new BlockingCollection<Action>();
+ //private readonly CancellationToken _cancel=new CancellationToken();
+
+ public StatusKeeper()
+ {
+ var source = new XmlConfigurationSource("DbConfig.xml");
+ ActiveRecordStarter.Initialize(source,typeof(FileState));
+
+ if (!File.Exists("pithos.db"))
+ ActiveRecordStarter.CreateSchema();
+
+ Task.Factory.StartNew(ProcessUpdates);
+ }
+
+ public void ProcessUpdates()
+ {
+ foreach (var action in _statusUpdateQueue.GetConsumingEnumerable())
+ {
+ action();
+ }
+ }
+
+ public void Stop()
+ {
+ _statusUpdateQueue.CompleteAdding();
+ }
+
+ public FileOverlayStatus GetFileOverlayStatus(string path)
+ {
+ try
+ {
+ var state = FileState.TryFind(path.ToLower());
+ return state == null ? FileOverlayStatus.Unversioned : state.OverlayStatus;
+ }
+ catch (Exception exc)
+ {
+ Trace.TraceError(exc.ToString());
+ return FileOverlayStatus.Unversioned;
+ }
+ }
+
+ public IEnumerable<string> StoreUnversionedFiles(ParallelQuery<string> paths)
+ {
+ var existingFiles = from state in FileState.Queryable
+ select state.FilePath;
+
+ var newFiles = (from file in paths.Except(existingFiles.AsParallel())
+ select new FileState
+ {
+ FilePath = file,
+ OverlayStatus = FileOverlayStatus.Unversioned,
+ FileStatus=FileStatus.Created,
+ Checksum=Signature.CalculateHash(file)
+ }
+ );
+
+ //var files=new ConcurrentBag<string>();
+ newFiles.ForAll(state=> _statusUpdateQueue.Add(state.Save));
+
+ return newFiles.Select(state => state.FilePath);// files.GetConsumingEnumerable();
+
+ }
+
+/*
+ private static Task<string> CalculateHashAsync(string path)
+ {
+
+ string hash;
+ using (var hasher = MD5.Create())
+ {
+ return FileAsync.ReadAllBytes(path)
+ .ContinueWith(t => hasher.ComputeHash(t.Result))
+ .ContinueWith(t =>
+ {
+ //var hashBuilder = new StringBuilder();
+ return (from byte b in t.Result.AsParallel()
+ select b.ToString("x2").ToLower()).Aggregate((s1, s2) => s1 + s2);
+ });
+ }
+ /*using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, true))
+ {
+
+ stream.ReadAllBytes()
+ .ContinueWith(result => hasher.ComputeHash(result.Result))
+ .;
+ var hashBytes = hasher.ComputeHash(stream);
+ var hashBuilder = new StringBuilder();
+ foreach (byte b in hasher.ComputeHash(stream))
+ hashBuilder.Append(b.ToString("x2").ToLower());
+ hash = hashBuilder.ToString();
+
+ }
+ return hash;#1#
+ }
+*/
+
+
+ private PithosStatus _pithosStatus=PithosStatus.InSynch;
+
+ public void SetPithosStatus(PithosStatus status)
+ {
+ _pithosStatus = status;
+ }
+
+ public PithosStatus GetPithosStatus()
+ {
+ return _pithosStatus;
+ }
+
+ public void SetFileOverlayStatus(string path, FileOverlayStatus overlayStatus)
+ {
+ _statusUpdateQueue.Add(() =>
+ InnerSetOverlayStatus(path, overlayStatus));
+ }
+
+ private static void InnerSetOverlayStatus(string path, FileOverlayStatus overlayStatus)
+ {
+ var state = FileState.TryFind(path.ToLower());
+ if (state != null)
+ {
+ state.OverlayStatus = overlayStatus;
+ state.Update();
+ }
+ else
+ {
+ state = new FileState
+ {FilePath = path, OverlayStatus = overlayStatus};
+ state.Save();
+ }
+ }
+
+ public void RemoveFileOverlayStatus(string path)
+ {
+ _statusUpdateQueue.Add(() =>
+ InnerRemoveFileOverlayStatus(path));
+ }
+
+ private static void InnerRemoveFileOverlayStatus(string path)
+ {
+ FileState.DeleteAll(new[] {path});
+ }
+
+ public void RenameFileOverlayStatus(string oldPath, string newPath)
+ {
+ _statusUpdateQueue.Add(() =>
+ InnerRenameFileOverlayStatus(oldPath, newPath));
+ }
+
+ private static void InnerRenameFileOverlayStatus(string oldPath, string newPath)
+ {
+ var state = FileState.Find(oldPath);
+ //NOTE: This will cause problems if path is used as a key in relationships
+ state.FilePath = newPath;
+ state.Update();
+ }
+
+ public void SetFileStatus(string path, FileStatus status)
+ {
+ _statusUpdateQueue.Add(() =>
+ InnerSetFileStatus(path, status));
+ }
+
+ private static void InnerSetFileStatus(string path, FileStatus status)
+ {
+ var state = FileState.Find(path);
+ state.FileStatus = status;
+ }
+
+ public FileStatus GetFileStatus(string path)
+ {
+ var state = FileState.TryFind(path.ToLower());
+ return (state==null)?FileStatus.Missing:state.FileStatus ;
+ }
+
+ public void ClearFileStatus(string path)
+ {
+ //TODO:SHOULDN'T need both clear file status and remove overlay status
+ FileState.DeleteAll(new[] { path });
+ }
+
+ public void UpdateFileChecksum(string path, string checksum)
+ {
+ var state = FileState.Find(path);
+ state.Checksum = checksum;
+ state.Update();
+ }
+ }
+}
namespace Pithos.Interfaces
{
/// <summary>
- /// TODO: Update summary.
+ /// PITHOS Account Settings
/// </summary>
- //[ActiveRecord]
- //[Serializable]
- public class AccountSettings//:ActiveRecordBase<AccountSettings>
+ public class AccountSettings
{
- //[PrimaryKey]
+
public string AccountName { get; set; }
- //[Property]
+
public string ApiKey { get; set; }
+ public bool IsActive { get; set; }
+
+ public string RootPath { get; set; }
+
private StringCollection _selectiveFolders = new StringCollection();
- //[Property]
+
public StringCollection SelectiveFolders
{
get { return _selectiveFolders; }
Deleted=-2,
Unversioned=-1,
Normal=0,
- Modified,
- Conflict,
- Synch
+ Modified=1,
+ Conflict=2,
+ Synch=3
}
public enum PithosStatus
public class CloudFilesClient:ICloudClient
{
string _rackSpaceAuthUrl = "https://auth.api.rackspacecloud.com";
- private string _pithosAuthUrl = "http://pithos.dev.grnet.gr";
+ private string _pithosAuthUrl = "https://pithos.grnet.gr";
private RestClient _client;
private readonly TimeSpan _shortTimeout = TimeSpan.FromSeconds(10);
public void Authenticate(string userName,string apiKey)
{
- Trace.TraceInformation("[AUTHENTICATE] Start for {0}",userName);
+ Trace.TraceInformation("[AUTHENTICATE] Start for {0}", userName);
if (String.IsNullOrWhiteSpace(userName))
- throw new ArgumentNullException("userName","The userName property can't be empty");
+ throw new ArgumentNullException("userName", "The userName property can't be empty");
if (String.IsNullOrWhiteSpace(apiKey))
throw new ArgumentNullException("apiKey", "The apiKey property can't be empty");
-
UserName = userName;
ApiKey = apiKey;
-
- string authUrl = UsePithos ? String.Format("{0}/{1}/{2}", AuthUrl, VersionPath,UserName)
- : String.Format("{0}/{1}", AuthUrl, VersionPath);
-
- var proxy = Proxy != null ? Proxy.ToString():null;
-
- var authClient = new RestClient{Path=authUrl,Proxy=proxy};
-
- authClient.AddHeader("X-Auth-User", UserName);
- authClient.AddHeader("X-Auth-Key", ApiKey);
- var response=authClient.Request();
-
- ThrowIfNotStatusOK(response, "Authentication failed");
+ var proxy = Proxy != null ? Proxy.ToString() : null;
+ if (UsePithos)
+ {
+ Token = "0000";
+ string storageUrl = String.Format("{0}/{1}/{2}", AuthUrl, VersionPath, UserName);
+ StorageUrl = new Uri(storageUrl);
+ }
+ else
+ {
- var keys = response.Headers.AllKeys.AsQueryable();
+ string authUrl = String.Format("{0}/{1}", AuthUrl, VersionPath);
+ var authClient = new RestClient {Path = authUrl, Proxy = proxy};
- string storageUrl =UsePithos?
- String.Format("{0}/{1}/{2}",AuthUrl,VersionPath,UserName)
- :GetHeaderValue("X-Storage-Url", response, keys);
-
- if (String.IsNullOrWhiteSpace(storageUrl))
- throw new InvalidOperationException("Failed to obtain storage url");
- StorageUrl = new Uri(storageUrl);
+ authClient.AddHeader("X-Auth-User", UserName);
+ authClient.AddHeader("X-Auth-Key", ApiKey);
+
+ var response = authClient.Request();
+
+ ThrowIfNotStatusOK(response, "Authentication failed");
+
+ var keys = response.Headers.AllKeys.AsQueryable();
+
+ string storageUrl = GetHeaderValue("X-Storage-Url", response, keys);
+ if (String.IsNullOrWhiteSpace(storageUrl))
+ throw new InvalidOperationException("Failed to obtain storage url");
+ StorageUrl = new Uri(storageUrl);
- if (!UsePithos)
- {
var token = GetHeaderValue("X-Auth-Token", response, keys);
if (String.IsNullOrWhiteSpace(token))
throw new InvalidOperationException("Failed to obtain token url");
Token = token;
}
- else
- Token = "0000";
_retryPolicy = new RetryPolicy { RetryCount = _retries };
_retryPolicy.RetryConditions.Add(new TimeoutRetryCondition());
_client.FileProgress += OnFileProgress;
_client.AddHeader("X-Auth-Token", Token);
- if (UsePithos)
+ /*if (UsePithos)
{
_client.AddHeader("X-Auth-User", UserName);
_client.AddHeader("X-Auth-Key",ApiKey);
- }
+ }*/
Trace.TraceInformation("[AUTHENTICATE] End for {0}", userName);
}
var statusCode = (int)response.StatusCode;
if (statusCode < 200 || statusCode >= 300)
{
- Trace.TraceWarning("ListObjects failed with code {1} - {2}", response.StatusCode, response.StatusDescription);
+ Trace.TraceWarning("ListObjects failed with code {0} - {1}", response.StatusCode, response.StatusDescription);
return new List<ObjectInfo>();
}
if (!File.Exists(fileName))
throw new FileNotFoundException("The file does not exist",fileName);
-
- string url = container + "/" + objectName;
-
- var request = new RestRequest {Path=url,Method=WebMethod.Put};
-/*
- if(UploadPercentLimit>0)
- request.TaskOptions=new TaskOptions<int>{RateLimitPercent=UploadPercentLimit};
-*/
- Trace.TraceInformation("[PUT] START {0}",objectName);
- string etag = hash??CalculateHash(fileName);
- request.AddFile(fileName, fileName, fileName);
- //request.AddPostContent(File.ReadAllBytes(fileName));
- request.AddHeader("Content-Type","application/octet-stream");
- request.AddHeader("ETag", etag);
- //_client.TaskOptions = new TaskOptions<int> {RateLimitPercent = 0.5};
try
{
-
- var response=_client.Request(request);
- Trace.TraceInformation("[PUT] END {0}", objectName);
-
- if (response.StatusCode == HttpStatusCode.Created)
- return Task.Factory.StartNew(()=>{});
- if (response.StatusCode == HttpStatusCode.LengthRequired)
- throw new InvalidOperationException();
- else
- throw new WebException(String.Format("GetObject failed with unexpected status code {0}",
- response.StatusCode));
- /* return Task.Factory.FromAsync(_client.BeginRequest(request),ar=>_client.EndRequest(ar))
- .ContinueWith(t=>
- {*/
+ var url = String.Join("/",new[]{_client.Authority,container,objectName});
+ var uri = new Uri(url);
+
+ var client = new WebClient();
+ string etag = hash ?? CalculateHash(fileName);
+
+ client.Headers.Add("Content-Type", "application/octet-stream");
+ client.Headers.Add("ETag", etag);
+
+ if(!String.IsNullOrWhiteSpace(_client.Proxy))
+ client.Proxy = new WebProxy(_client.Proxy);
+
+ CopyHeaders(_client, client);
+
+ Trace.TraceInformation("[PUT] START {0}", objectName);
+ client.UploadProgressChanged += (sender, args) =>
+ {
+ Trace.TraceInformation("[PROGRESS] {0} {1}% {2} of {3}", fileName, args.ProgressPercentage, args.BytesSent, args.TotalBytesToSend);
+ };
+
+ return client.UploadFileTask(uri, "PUT", fileName)
+ .ContinueWith(upload=>
+ {
+ client.Dispose();
+
+ if (upload.IsFaulted)
+ {
+ Trace.TraceError("[PUT] FAIL for {0} with \r{1}",objectName,upload.Exception);
+ }
+ else
+ Trace.TraceInformation("[PUT] END {0}", objectName);
+ });
}
catch (Exception exc)
{
throw;
}
-/*
- var response = t.Result;
- if (t.IsFaulted)
- Trace.TraceError("[PUT] END {0} with {1}", objectName, t.Exception);
- else
- {
- Trace.TraceInformation("[PUT] END {0}",objectName);
- }
-*/
- /* if (response.StatusCode == HttpStatusCode.Created)
- return;
- if (response.StatusCode == HttpStatusCode.LengthRequired)
- throw new InvalidOperationException();
- else
- throw new WebException(String.Format("GetObject failed with unexpected status code {0}",
- response.StatusCode));*/
- /*});*/
+ }
+
+ /// <summary>
+ /// Copies headers from a Hammock RestClient to a WebClient
+ /// </summary>
+ /// <param name="source">The RestClient from which the headers are copied</param>
+ /// <param name="target">The WebClient to which the headers are copied</param>
+ private static void CopyHeaders(RestClient source, WebClient target)
+ {
+ Contract.Requires(source!=null,"source can't be null");
+ Contract.Requires(target != null, "target can't be null");
+ if (source == null)
+ throw new ArgumentNullException("source", "source can't be null");
+ if (source == null)
+ throw new ArgumentNullException("target", "target can't be null");
+
+ foreach (var header in source.GetAllHeaders())
+ {
+ target.Headers.Add(header.Name, header.Value);
+ }
}
private static string CalculateHash(string fileName)
<CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
<CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
</PropertyGroup>
+ <PropertyGroup>
+ <SignAssembly>true</SignAssembly>
+ </PropertyGroup>
+ <PropertyGroup>
+ <AssemblyOriginatorKeyFile>pithos.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
<ItemGroup>
+ <Reference Include="Hammock.ClientProfile, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c148cfba29ed1a4d, processorArchitecture=MSIL">
+ <HintPath>..\packages\Hammock.1.2.6\lib\net40-client\Hammock.ClientProfile.dll</HintPath>
+ </Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
<Compile Include="TimeoutRetryCondition.cs" />
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="..\hammock\src\net40\Hammock.ClientProfile\Hammock.ClientProfile.csproj">
- <Project>{487B7E3C-9689-47BC-8785-73CCD92A3749}</Project>
- <Name>Hammock.ClientProfile</Name>
- </ProjectReference>
<ProjectReference Include="..\Libraries\Json40r2\Source\Src\Newtonsoft.Json\Newtonsoft.Json.csproj">
<Project>{A9AE40FF-1A21-414A-9FE7-3BE13644CC6D}</Project>
<Name>Newtonsoft.Json</Name>
</ProjectReference>
+ <ProjectReference Include="..\Libraries\ParallelExtensionsExtras\ParallelExtensionsExtras.csproj">
+ <Project>{C45218F8-09E7-4F57-85BC-5D8D2AC736A3}</Project>
+ <Name>ParallelExtensionsExtras</Name>
+ </ProjectReference>
<ProjectReference Include="..\Pithos.Interfaces\Pithos.Interfaces.csproj">
<Project>{7EEFF32F-CCF8-436A-9E0B-F40434C09AF4}</Project>
<Name>Pithos.Interfaces</Name>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
+ <None Include="pithos.snk" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
{
get
{
- Trace.Write(String.Format("Managed path is {0}\r\n Current Path is {1}", PithosPath, CurrentFile));
+ Debug.WriteLine( String.Format("Managed path is {0}\r\n Current Path is {1}", PithosPath, CurrentFile),LogCategories.Shell);
return CurrentFolder.StartsWith(PithosPath, true, null);
}
}
set
{
_currentFile = value.ToLower();
- Trace.Write(String.Format("File is {0}", _currentFile));
+ Debug.WriteLine(String.Format("File is {0}", _currentFile), LogCategories.Shell);
if (Directory.Exists(_currentFile))
{
_currentFolder = _currentFile;
}
catch (Exception exc)
{
- Trace.TraceError(exc.ToString());
+ Trace.TraceError("Composition Error: {0}",exc);
throw;
}
}
--- /dev/null
+// -----------------------------------------------------------------------
+// <copyright file="LogCategories.cs" company="Microsoft">
+// TODO: Update copyright text.
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Pithos.ShellExtensions
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ /// <summary>
+ /// TODO: Update summary.
+ /// </summary>
+ public class LogCategories
+ {
+ public const string Shell = "[SHELL]";
+ public const string ShellMenu = "[SHELL MENU]";
+ public const string ShellOverlays = "[SHELL OVERLAYS]";
+ }
+}
}
- Trace.Write("Initializing");
+ Debug.WriteLine("Initializing", LogCategories.ShellMenu);
if (pDataObj != IntPtr.Zero)
{
- Trace.Write("Got a data object");
+ Debug.WriteLine("Got a data object", LogCategories.ShellMenu);
FORMATETC fe = new FORMATETC();
fe.cfFormat = (short)CLIPFORMAT.CF_HDROP;
// Determine how many files are involved in this operation.
uint nFiles = NativeMethods.DragQueryFile(hDrop, UInt32.MaxValue, null, 0);
- Trace.Write(String.Format("Got {0} files", nFiles));
+ Debug.WriteLine(String.Format("Got {0} files", nFiles), LogCategories.ShellMenu);
// This code sample displays the custom context menu item when only
// one file is selected.
if (nFiles == 1)
if (pidlFolder != IntPtr.Zero)
{
- Trace.Write("Got a folder");
+ Debug.WriteLine("Got a folder", LogCategories.ShellMenu);
StringBuilder path = new StringBuilder();
if (!NativeMethods.SHGetPathFromIDList(pidlFolder, path))
{
Marshal.ThrowExceptionForHR(error);
}
Context.CurrentFolder = path.ToString();
- Trace.Write(String.Format("Folder is {0}", Context.CurrentFolder));
+ Debug.WriteLine(String.Format("Folder is {0}", Context.CurrentFolder), LogCategories.ShellMenu);
}
}
uint idCmdLast,
uint uFlags)
{
- Trace.Write("Start qcm");
+ Debug.WriteLine("Start qcm", LogCategories.ShellMenu);
// If uFlags include CMF_DEFAULTONLY then we should not do anything.
- Trace.Write(String.Format("Flags {0}", uFlags));
+ Debug.WriteLine(String.Format("Flags {0}", uFlags), LogCategories.ShellMenu);
if (((uint)CMF.CMF_DEFAULTONLY & uFlags) != 0)
{
- Trace.Write("Default only flag, returning");
+ Debug.WriteLine("Default only flag, returning", LogCategories.ShellMenu);
return WinError.MAKE_HRESULT(WinError.SEVERITY_SUCCESS, 0, 0);
}
if (!Context.IsManaged)
{
- Trace.Write("Not a PITHOS folder");
+ Debug.WriteLine("Not a PITHOS folder",LogCategories.ShellMenu);
return WinError.MAKE_HRESULT(WinError.SEVERITY_SUCCESS, 0, 0);
}
DisplayFlags itemType = (Context.IsFolder) ? DisplayFlags.Folder : DisplayFlags.File;
- Trace.Write(String.Format("Item Flags {0}", itemType));
+ Debug.WriteLine(String.Format("Item Flags {0}", itemType), LogCategories.ShellMenu);
foreach (var menuItem in _items.Values)
{
- Trace.Write(String.Format("Menu Flags {0}", menuItem.DisplayFlags));
+ Debug.WriteLine(String.Format("Menu Flags {0}", menuItem.DisplayFlags), LogCategories.ShellMenu);
if ((itemType & menuItem.DisplayFlags) != DisplayFlags.None)
{
- Trace.Write("Adding Menu");
+ Debug.WriteLine("Adding Menu", LogCategories.ShellMenu);
MENUITEMINFO mii = menuItem.CreateInfo(idCmdFirst);
if (!NativeMethods.InsertMenuItem(hMenu, iMenu, true, ref mii))
}
}
- Trace.Write("Adding Separator 1");
+ Debug.Write("Adding Separator 1", LogCategories.ShellMenu);
// Add a separator.
MENUITEMINFO sep = new MENUITEMINFO();
sep.cbSize = (uint)Marshal.SizeOf(sep);
- Trace.Write("Menus added");
+ Debug.WriteLine("Menus added", LogCategories.ShellOverlays);
// Return an HRESULT value with the severity set to SEVERITY_SUCCESS.
// Set the code value to the offset of the largest command identifier
// that was assigned, plus one (1).
--- /dev/null
+// -----------------------------------------------------------------------
+// <copyright file="AddedIcodOverlay.cs" company="Microsoft">
+// TODO: Update copyright text.
+// </copyright>
+// -----------------------------------------------------------------------
+
+using System.Runtime.InteropServices;
+
+namespace Pithos.ShellExtensions.Overlays
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ [ClassInterface(ClassInterfaceType.None)]
+ [Guid("EAD1663B-9A03-4E92-80D3-B01B981CD828"), ComVisible(true)]
+ public class AddedIcodOverlay: IconOverlayBase
+ {
+
+ private static string _iconName = "Added";
+
+ public AddedIcodOverlay()
+ : base(_iconName)
+ {
+
+ }
+
+ #region Shell Extension Registration
+ [ComRegisterFunction()]
+ public static void Register(Type t)
+ {
+ RegisterOverlay(t,_iconName);
+ }
+
+ [ComUnregisterFunction]
+ public static void Unregister(Type t)
+ {
+ UnregisterOverlay(t,_iconName);
+ }
+
+ #endregion
+ }
+}
public IconOverlayBase(string iconName)
{
- Trace.Write("Icon Overlay Instance created");
+ if (String.IsNullOrWhiteSpace(iconName))
+ throw new ArgumentNullException("iconName","Empty iconName");
+
+ Debug.WriteLine("Icon Overlay Instance created", LogCategories.ShellOverlays);
IoC.Current.Compose(this);
public int IsMemberOf(string path, uint attributes)
{
if (String.IsNullOrWhiteSpace(path))
- throw new ArgumentNullException("Empty path");
+ throw new ArgumentNullException("path","Empty path");
- Trace.Write(String.Format("ICON Status check for {0} - {1}",path,GetType().Name));
+ Debug.WriteLine(String.Format("ICON Status check for {0} - {1}", path, GetType().Name), LogCategories.ShellOverlays);
if (!path.StartsWith(Settings.PithosPath,true,null))
return WinError.S_FALSE;
var status=StatusChecker.GetFileOverlayStatus(path);
var isMember = (PithosPrefix + status == OverlayName);
- Trace.Write(String.Format("Status check for {0} is {1}",path,isMember));
+ Debug.WriteLine(String.Format("[STATUS] Was {0}, expected {1} for {2}", status, OverlayName,path ), LogCategories.ShellOverlays);
return isMember ? WinError.S_OK : WinError.S_FALSE;
}
out int iconIndex,
out uint flags)
{
- Trace.Write("Looking for icons");
-
- Trace.WriteLine(string.Format("ICON file {0}", IconPath));
+ Contract.Requires(iconFileBuffer!=IntPtr.Zero);
+ Contract.Requires(iconFileBufferSize>0);
+
+ if (iconFileBuffer == IntPtr.Zero)
+ throw new ArgumentNullException("iconFileBuffer","iconFileBuffer not initialized");
+ if (iconFileBufferSize<=0)
+ throw new ArgumentException("iconFileBufferSize", "iconFileBufferSize must be greatere than 0");
+ Debug.WriteLine("Looking for icons", LogCategories.ShellOverlays);
+ Debug.WriteLine(string.Format("ICON file {0}", IconPath), LogCategories.ShellOverlays);
int bytesCount = System.Text.Encoding.Unicode.GetByteCount(IconPath);
-
- Trace.WriteLine(string.Format(" GetOverlayInfo::{0}",bytesCount));
+ Debug.WriteLine(string.Format(" GetOverlayInfo::{0}", bytesCount), LogCategories.ShellOverlays);
MarshalHelpers.CopyToBuffer(IconPath, iconFileBuffer, iconFileBufferSize);
public int GetPriority(out int priority)
{
- Trace.Write("Checking for priority");
+ Debug.WriteLine("Checking for priority");
priority = 0;
return WinError.S_OK;
}
- public static void RegisterOverlay(Type t,string iconName)
+ public static void RegisterOverlay(Type type,string iconName)
{
+ Contract.Requires(type != null);
+ Contract.Requires(!String.IsNullOrWhiteSpace(iconName));
+
+ if (type == null)
+ throw new ArgumentNullException("type", "type can't be null");
+ if (String.IsNullOrWhiteSpace(iconName))
+ throw new ArgumentNullException("iconName", "iconName can't be null");
+
try
{
- ShellExtReg.RegisterIconOverlayIdentifier(t.GUID, iconName);
+ ShellExtReg.RegisterIconOverlayIdentifier(type.GUID, iconName);
NativeMethods.SHChangeNotify(HChangeNotifyEventID.SHCNE_ASSOCCHANGED, HChangeNotifyFlags.SHCNF_IDLIST,
IntPtr.Zero, IntPtr.Zero);
- Trace.Write("Registered icon handler");
+ Debug.WriteLine("Registered icon handler");
}
catch (Exception ex)
{
- Trace.WriteLine(ex.Message); // Log the error
+ Debug.WriteLine(ex.Message); // Log the error
throw; // Re-throw the exception
}
}
- public static void UnregisterOverlay(Type t,string iconName)
+ public static void UnregisterOverlay(Type type,string iconName)
{
+ Contract.Requires(type!=null);
+ Contract.Requires(!String.IsNullOrWhiteSpace(iconName));
+
+ if (type==null)
+ throw new ArgumentNullException("type","type can't be null");
+ if (String.IsNullOrWhiteSpace(iconName))
+ throw new ArgumentNullException("iconName","iconName can't be null");
try
{
- ShellExtReg.UnregisterIconOverlayIdentifier(t.GUID, iconName);
- Trace.Write("UnRegistered icon handler");
+ ShellExtReg.UnregisterIconOverlayIdentifier(type.GUID, iconName);
+ Debug.WriteLine(String.Format("UnRegistered icon handler {0}:{1}",iconName,type.GUID), LogCategories.ShellOverlays);
}
catch (Exception ex)
{
- Trace.WriteLine(ex.Message); // Log the error
- throw; // Re-throw the exception
+ //Log and rethrow
+ Trace.TraceError("Failed to unregister overlay {0}:{1} with error {2}",iconName,type.GUID,ex.Message);
+ throw;
}
}
}
--- /dev/null
+// -----------------------------------------------------------------------
+// <copyright file="UnversionedIconOverlay.cs" company="Microsoft">
+// TODO: Update copyright text.
+// </copyright>
+// -----------------------------------------------------------------------
+
+using System.Runtime.InteropServices;
+
+namespace Pithos.ShellExtensions.Overlays
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ [ClassInterface(ClassInterfaceType.None)]
+ [Guid("10CF08FE-1252-4AAB-BE78-971B0C5E8AE0"), ComVisible(true)]
+ public class UnversionedIconOverlay : IconOverlayBase
+ {
+ private static string _iconName = "Unversioned";
+
+ public UnversionedIconOverlay()
+ : base(_iconName)
+ {
+
+ }
+
+ #region Shell Extension Registration
+ [ComRegisterFunction()]
+ public static void Register(Type t)
+ {
+ RegisterOverlay(t, _iconName);
+ }
+
+ [ComUnregisterFunction]
+ public static void Unregister(Type t)
+ {
+ UnregisterOverlay(t, _iconName);
+ }
+
+ #endregion
+ }
+}
<ItemGroup>
<Compile Include="FileContext.cs" />
<Compile Include="IoC.cs" />
+ <Compile Include="LogCategories.cs" />
<Compile Include="MarshalHelpers.cs" />
<Compile Include="Menus\DisplayFlags.cs" />
<Compile Include="Menus\FileContextMenu.cs" />
--- /dev/null
+// -----------------------------------------------------------------------
+// <copyright file="PithosHost.cs" company="Microsoft">
+// TODO: Update copyright text.
+// </copyright>
+// -----------------------------------------------------------------------
+
+using System.Diagnostics;
+using System.IO;
+using System.ServiceModel;
+using Microsoft.Win32;
+using Pithos.ShellExtensions.PithosService;
+
+namespace Pithos.ShellExtensions
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ /// <summary>
+ /// TODO: Update summary.
+ /// </summary>
+ public static class PithosHost
+ {
+ public static void EnsureHost()
+ {
+ if (Process.GetProcessesByName("Pithos.Client.WPF").Length == 0 &&
+ Process.GetProcessesByName("Pithos.Client.WPF.vshost").Length == 0)
+ {
+ var fileName = (string)Registry.LocalMachine.GetValue(@"Software\Pithos\AppPath");
+ var workingDirectory = Path.GetDirectoryName(fileName);
+ var info = new ProcessStartInfo {FileName = fileName, WorkingDirectory = workingDirectory};
+ Process.Start(info);
+ }
+ }
+
+ public static StatusServiceClient GetStatusClient()
+ {
+ EnsureHost();
+
+ var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
+ var remoteAddress = new EndpointAddress("net.pipe://localhost/pithos/statuscache");
+
+ return new StatusServiceClient(binding, remoteAddress);
+ }
+
+ public static SettingsServiceClient GetSettingsClient()
+ {
+ EnsureHost();
+
+ var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
+ var remoteAddress = new EndpointAddress("net.pipe://localhost/pithos/settings");
+
+ return new SettingsServiceClient(binding, remoteAddress);
+ }
+ }
+}
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:tns="http://schemas.datacontract.org/2004/07/Pithos.Interfaces" elementFormDefault="qualified" targetNamespace="http://schemas.datacontract.org/2004/07/Pithos.Interfaces" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import schemaLocation="http://localhost:30000/pithos/mex?xsd=xsd1" namespace="http://schemas.microsoft.com/2003/10/Serialization/" />
<xs:import schemaLocation="http://localhost:30000/pithos/mex?xsd=xsd4" namespace="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
<xs:element minOccurs="0" name="ExtensionsActivated" type="xs:boolean" />
<xs:element minOccurs="0" name="IconsPath" nillable="true" type="xs:string" />
<xs:element minOccurs="0" name="PithosPath" nillable="true" type="xs:string" />
+ <xs:element minOccurs="0" name="PithosSite" nillable="true" type="xs:string" />
<xs:element minOccurs="0" name="ProxyAuthentication" type="xs:boolean" />
<xs:element minOccurs="0" name="ProxyPassword" nillable="true" type="xs:string" />
<xs:element minOccurs="0" name="ProxyPort" type="xs:int" />
<xs:sequence>
<xs:element minOccurs="0" name="AccountName" nillable="true" type="xs:string" />
<xs:element minOccurs="0" name="ApiKey" nillable="true" type="xs:string" />
+ <xs:element minOccurs="0" name="IsActive" type="xs:boolean" />
<xs:element xmlns:q1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" minOccurs="0" name="SelectiveFolders" nillable="true" type="q1:ArrayOfanyType" />
</xs:sequence>
</xs:complexType>
public static void MarkApproved(Guid guid, string friendlyName)
{
- Trace.Write(String.Format("Marking approved {0} {1}", guid, friendlyName));
+ Debug.WriteLine(String.Format("Marking approved {0} {1}", guid, friendlyName), LogCategories.Shell);
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(_approvedKey))
{
// Set the default value of the key.
}
else
{
- Trace.Write("Error - failed to open key " + _approvedKey);
+ Debug.WriteLine("Error - failed to open key " + _approvedKey,LogCategories.Shell);
}
}
}
}
else
{
- Trace.Write("Error - failed to open key " + _approvedKey);
+ Debug.WriteLine("Error - failed to open key " + _approvedKey, LogCategories.Shell);
}
}
}
}
catch (Exception exc)
{
- Trace.WriteLine(exc.ToString());
- Trace.TraceError(exc.ToString());
+ Trace.TraceError("[ERROR] while loading settings:\r{0}",exc);
_settings = new Lazy<IPithosSettings>(LoadSettings);
}
return null;
}
catch (Exception exc)
{
- Trace.TraceError(exc.ToString());
+ Trace.TraceError("[ERROR] retrieving overlay status for {0}:\r{1}",path,exc);
return FileOverlayStatus.Unversioned;
}
}
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Caliburn.Micro.WPF", "..\..\..\Downloads\caliburnmicro\caliburnmicro_1f6100f2f0af\src\Caliburn.Micro.WPF\Caliburn.Micro.WPF.csproj", "{B633FE8C-B40E-4122-A763-F94C8B1A70F8}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hammock.ClientProfile", "hammock\src\net40\Hammock.ClientProfile\Hammock.ClientProfile.csproj", "{487B7E3C-9689-47BC-8785-73CCD92A3749}"
-EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
{B633FE8C-B40E-4122-A763-F94C8B1A70F8}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU
{B633FE8C-B40E-4122-A763-F94C8B1A70F8}.Test|Mixed Platforms.Build.0 = Release|Any CPU
{B633FE8C-B40E-4122-A763-F94C8B1A70F8}.Test|x86.ActiveCfg = Release|Any CPU
- {487B7E3C-9689-47BC-8785-73CCD92A3749}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {487B7E3C-9689-47BC-8785-73CCD92A3749}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {487B7E3C-9689-47BC-8785-73CCD92A3749}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {487B7E3C-9689-47BC-8785-73CCD92A3749}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
- {487B7E3C-9689-47BC-8785-73CCD92A3749}.Debug|x86.ActiveCfg = Debug|Any CPU
- {487B7E3C-9689-47BC-8785-73CCD92A3749}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {487B7E3C-9689-47BC-8785-73CCD92A3749}.Release|Any CPU.Build.0 = Release|Any CPU
- {487B7E3C-9689-47BC-8785-73CCD92A3749}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {487B7E3C-9689-47BC-8785-73CCD92A3749}.Release|Mixed Platforms.Build.0 = Release|Any CPU
- {487B7E3C-9689-47BC-8785-73CCD92A3749}.Release|x86.ActiveCfg = Release|Any CPU
- {487B7E3C-9689-47BC-8785-73CCD92A3749}.Test|Any CPU.ActiveCfg = Release|Any CPU
- {487B7E3C-9689-47BC-8785-73CCD92A3749}.Test|Any CPU.Build.0 = Release|Any CPU
- {487B7E3C-9689-47BC-8785-73CCD92A3749}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU
- {487B7E3C-9689-47BC-8785-73CCD92A3749}.Test|Mixed Platforms.Build.0 = Release|Any CPU
- {487B7E3C-9689-47BC-8785-73CCD92A3749}.Test|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
--- /dev/null
+#ignore thumbnails created by windows
+Thumbs.db
+#Ignore files build by Visual Studio
+*.obj
+*.pdb
+*.user
+*.aps
+*.pch
+*.vspscc
+*_i.c
+*_p.c
+*.ncb
+*.suo
+*.tlb
+*.tlh
+*.bak
+*.cache
+*.ilk
+*.log
+[Bb]in
+[Dd]ebug*/
+[Cc]lientBin*/
+*.lib
+*.sbr
+obj/
+[Rr]elease*/
+_ReSharper*/
+[Tt]est[Rr]esult*
+deploy.config
+Examples*/
+*.vsmdi
+*.pidb
+*.userprefs
+*.testrunconfig
+publish.xml
+TestResults
+src/net40/Hammock.Tests/app.config
+$SSH_ENV
\ No newline at end of file
--- /dev/null
+# regexp syntax.
+syntax: glob
+*.pdb
+*.suo
+*.user
+bin/net35/*.*
+bin/net35/de/*.*
+bin/net35/fr/*.*
+bin/net35/es/*.*
+bin/net35/it/*.*
+bin/net35/ko/*.*
+bin/net35/ja/*.*
+bin/net35/ru/*.*
+bin/net35/zh-Hans/*.*
+bin/net35/zh-Hant/*.*
+bin/net40/*.*
+bin/net40/de/*.*
+bin/net40/fr/*.*
+bin/net40/es/*.*
+bin/net40/it/*.*
+bin/net40/ko/*.*
+bin/net40/ja/*.*
+bin/net40/ru/*.*
+bin/net40/zh-Hans/*.*
+bin/net40/zh-Hant/*.*
+
+syntax: regexp
+/obj/
+/bin/
+/Bin/
+/_ReSharper.Hammock/
+glob:src/net35/Hammock.Tests/app.config
+glob:bin/mono/*.*
+glob:*.orig
+glob:src/net35/Hammock.Tests/App.config
+glob:src/net35/ICSharpCode.SharpZipLib.Silverlight.Tests/ClientBin/*.*
+glob:src/net35/ICSharpCode.SharpZipLib.Silverlight.Tests/ClientBin/de/*.*
+glob:src/net35/ICSharpCode.SharpZipLib.Silverlight.Tests/ClientBin/es/*.*
+glob:src/net35/ICSharpCode.SharpZipLib.Silverlight.Tests/ClientBin/fr/*.*
+glob:src/net35/ICSharpCode.SharpZipLib.Silverlight.Tests/ClientBin/it/*.*
+glob:src/net35/ICSharpCode.SharpZipLib.Silverlight.Tests/ClientBin/ja/*.*
+glob:src/net35/ICSharpCode.SharpZipLib.Silverlight.Tests/ClientBin/ko/*.*
+glob:src/net35/ICSharpCode.SharpZipLib.Silverlight.Tests/ClientBin/zh-Hans/*.*
+glob:src/net35/ICSharpCode.SharpZipLib.Silverlight.Tests/ClientBin/zh-Hant/*.*
+
+relre:/_ReSharper.Hammock.Silverlight/*
+relre:/_ReSharper.Hammock.WindowsPhone/*
+glob:src/mono/Hammock.Mono/Hammock.Mono.pidb
+glob:src/net40/Hammock.Tests/app.config
+glob:bin/net20/*.*
+relre:src/_ReSharper*
+src/mono/test-results
+relre:bin/lib/*
+relre:bin/*
+glob:*.userprefs
+glob:*.pidb
--- /dev/null
+Hammock (http://github.com/danielcrenna/hammock)
+--------------------------------------
+Copyright (c) 2010 Daniel Crenna and Jason Diller
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Hammock for Silverlight and Windows Phone 7
+--------------------------------------
+This target optionally links to a port of SharpZipLib http://www.icsharpcode.net/opensource/sharpziplib as an independent
+module that does not derive from, and is not based on, SharpZipLib. As such it is compliant with the special
+exception of SharpZipLib's GNU General Public License and may be used in commercial, closed-source applications.
+As the independent module, this is compliant with Hammock's MIT X11 Licence.
+
+Hammock Extras
+--------------------------------------
+The Extras project in source code provides an example serializer that includes JSON.NET,
+licensed under the MIT X11 License http://www.opensource.org/licenses/mit-license.php.
\ No newline at end of file
--- /dev/null
+# Hammock - REST, easy.
+
+#### Welcome to the Programmable Web
+
+If you haven't had the requirement to connect with another web service in your projects, you soon will.
+In an increasingly connected world, where the presence of an Application Programming Interface (API) is
+as essential to a growing company's online success as a blog was five years ago, it's inevitable that you
+will need to build software that integrates with multiple sources of data from numerous partners.
+This is achieved through API programming, and by way of adoption this is most often accomplished through
+HTTP programming, based on the REST architectural style (to varying degrees), which provides convenient
+metaphors for creating, retrieving, updating, and deleting data over HTTP, as well as providing smooth
+transitions from one set of data to the next through the URIs embedded in a literal web of results.
+
+Notable companies that provide a REST-like API for their customers include Twitter, Facebook, Google, Amazon,
+and Microsoft. There are too many more to mention. When you are tasked with consuming multiple APIs, you need a
+simple, expressive toolset that allows you to rapidly build client code that is easy to understand, while
+allowing you to meet the needs of multiple styles, authentication requirements, and messaging.
+This is where Hammock comes in.
+
+#### The Philosophy and Purpose of Hammock
+
+Hammock's philosophy is simple: _REST, easy._
+Hammock's purpose is to provide a common foundation for RESTful communication in .NET that gives developers a
+clean and easy way to build RESTful client libraries, or consume RESTful services from their applications,
+without compromising time or quality. It shares similar aspirations with other web API utilities, but focuses on
+completeness, performance, and getting out of your way.
+
+#### A Brief History of Hammock
+
+Hammock grew from the networking code in TweetSharp (http://tweetsharp.com), .NET's most popular Twitter API library.
+When the library's authors found themselves maintaining numerous API projects, they turned to TweetSharp's foundation again
+and again, pulling in snippets and adding new features. As APIs continued to explode online, it made sense to consolidate
+the code into a common library, add an abstraction layer to sweeten its use, and open it up to the public to benefit.
+The project was launched feature complete in April 2010 and is still in active development.
+
+#### What Does It Do?
+
+Hammock provides classes to help you consume RESTful services or develop your own client API libraries with a
+minimum of effort. It supports asynchronous operation, query caching and mocking, periodic and rate limited tasks,
+object model serialization, multi-part forms, Basic and OAuth authentication, and timeout and retry policies.
+It is designed to allow you to extend it easily, so you can provide your own serialization scheme, custom validation,
+rate limiting rules, and web credentials. It also helps you unify projects across a wide range of platforms and
+devices, as it works on .NET, .NET Compact Framework, Silverlight, Windows Phone, Mono, MonoTouch, and MonoDroid.
+
+
+
+## What You Need to Get Started
+[]
+
+
+
+## Creating REST Requests
+
+This section covers creating a RESTful request issued from your application to the service you intend to consume.
+Building requests in Hammock uses the language of HTTP, to make it easier to find the methods you're looking for.
+If you need to add an HTTP header to your outgoing HttpRequest, you'd use the AddHeader method, and so on.
+
+### RestClient, RestRequest, and RestResponse
+These three classes form the backbone of Hammock, and provide all of the properties you need to build RESTful
+requests and process their results. RestClient and RestRequest have a special relationship; any property that can
+be set on both classes obeys a hierarchical relationship, so you are free to set common values on RestClient,
+and override them with RestRequest, depending on your needs. This makes it easy and efficient to create a
+RestClient with the most common request values, and then use specific request values for each request sent through
+the client. An obvious example of that could be credentials; if your authorization requirements never change between
+requests for the client you are consuming, then setting credentials on RestClient makes the most sense, and will allow
+you to omit setting them on every RestRequest.
+
+As a working example, here is a simple Twitter API RestClient that stores basic information about the service, and a
+RestRequest that sets values, like credentials specific to the user, and the target API path, using your application.
+
+ BasicAuthCredentials credentials = new BasicAuthCredentials
+ {
+ Username = "username",
+ Password = "password"
+ };
+ RestClient client = new RestClient
+ {
+ Authority = "http://api.twitter.com",
+ VersionPath = "1"
+ };
+ RestRequest request = new RestRequest
+ {
+ Credentials = credentials,
+ Path = "statuses/home_timeline.json"
+ };
+ RestResponse response = client.Request(request);
+
+
+### Building Request Paths
+
+The final URL for a request path is constructed first from the RestClient's Authority property. From there, either RestRequest
+or RestClient is inspected for the VersionPath, and Path values. The VersionPath is always inserted between the Authority and
+Path values. It is useful for targeting specific versions of an API endpoint, or for any URI path fragment that varies between
+the authority and the target path. Hammock can handle secure endpoints, just ensure you include the HTTPS scheme when declaring
+your authority.
+
+// TODO
+
+Once your path is defined, you still need to add request state. State in a REST request refers to the query string parameters,
+POST parameters or fields, request headers, or entity body contents that make up the data sent to the specified path.
+In Hammock, you can do this one of two ways: using a traditional method API, or applying attributes to a custom class that is passed
+to Hammock.
+
+### Request State Using Method Style
+
+Properties and methods on both RestClient and RestRequest form the basis of most requests in Hammock: WebMethod, UserAgent, AddHeader,
+AddParameter, AddFile, AddField, and Entity form the list of major members. Methods that begin with Add allow setting multiple values,
+while the properties allow setting a single value. All of these members are allowable on either class, making it easier to build up
+clients with default behavior. The UserAgent property is a formalized way of setting the User-Agent request property, but it can be
+set using either the property or the AddHeader method. If both are explicitly set...
+
+[]
+
+The Entity property allows you to set the body of a POST or PUT request, and it can be set to any object. If you do not specify a
+WebMethod before setting the Entity, Hammock will assume you are making a POST request.
+
+[]
+
+### Request State Using Attribute Style
+
+Some APIs, like TweetSharp, need a more stateful approach to assembling REST requests. For example, you may want to collect information
+about a particular request over time in your own class, and at request time, transform it into the appropriate header, parameter,
+user agent, and entity body values. You can certainly do this using the previous method style, but it would result in a lot of
+"left right" coding, or mapping state from your code to the most appropriate RestClient or RestRequest properties. To avoid having to
+perform this work, and to enable some advanced validation and transforming capabilities, you can use Hammock's attributes style.
+
+[]
+
+### Using IWebQueryInfo
+
+The IWebQueryInfo interface is an empty marker interface you can attach to the class you intend to pass to Hammock to build requests.
+Once your class implements IWebQueryInfo, you can use the built-in specialized attributes to declare essential request data like
+parameters, headers, user agent, and entity, and you can use ours or your own validation attributes to transform values or throw
+exceptions based on property values at the time of the request. Attributes are only applied to public properties defined in your class.
+Once you have an instance of your IWebQueryInfo class with attributes applied, you can set the Info property of RestClient or
+RestRequest to that instance, and Hammock will set all request values appropriately. As always, the Info set on RestRequest will
+override the Info set on RestClient.
+
+[]
+
+### Specialized Attributes
+
+Specialized attributes set fundamental HTTP API elements on outgoing requests. By marking a public property with UserAgentAttribute,
+its value is used as the request's "User-Agent" header value. ParameterAttribute and HeaderAttribute are used to set request URL or
+POST parameters and headers respectively, and require a name string to identify the name of the name-value pair to use. The next
+listing demonstrates an IWebQueryInfo class with some fundamental request values using attributes.
+
+[]
+
+### Validation Attributes
+
+Hammock includes a number of validation attributes for your use, that we've found are useful for building libraries. The purpose of a
+validation attribute is to transform, at request time, the value of the decorated public property. This gives you an opportunity to
+course correct for your needs (such as is the case with DateFormatAttribute and BooleanToIntegerAttribute), or prevent issuing requests
+that don't meet specific criteria (as in SpecificationAttribute and RequiredAttribute). You can also derive from ValidationAttribute
+to create your own custom validation or transformations. The following example demonstrates an IWebQueryInfo class with typical
+validation attributes, including the use of a Hammock-provided ValidEmailSpecification specification and SpecificationAttribute.
+In the example, a ValidationException will throw if the value of Email is not a valid email address at the time of a request, and if
+it were, the value of the valid email address would be passed in a parameter named "Contact" (either in the URL with GET or in the POST
+body, depending on the request).
+
+ // A IWebQueryInfo implementation for custom validation
+ public class MyCustomInfo : IWebQueryInfo
+ {
+ [Parameter("Contact")]
+ [Specification(typeof(ValidEmailSpecification))]
+ public string Email { get; set; }
+ }
+
+ // Example code that would throw an exception due to an invalid email address
+ IWebQueryInfo info = new MyCustomInfo { Email = "nowhere" };
+
+ RestClient client = new RestClient
+ {
+ Authority = "http://nowhere.com",
+ Info = info
+ };
+
+ RestRequest request = new RestRequest
+ {
+ Path = "fast"
+ };
+
+ client.Request(request);
+
+ // From Hammock.Validation namespace, for illustration purposes
+ public class ValidEmailSpecification : HammockSpecification<string>
+ {
+ // Accepts names, i.e. John Smith <john@johnsmith.com>
+ private static readonly Regex _names =
+ new Regex(
+ @"\w*<([-_a-z0-9'+*$^&%=~!?{}]+(?:\.[-_a-z0-9'+*$^&%=~!?{}]+)*@(?:(?![-.])[-a-z0-9.]+(?<![-.])\.[a-z]{2,6}|\d{1,3}(?:\.\d{1,3}){3})(?::\d+)?)>",
+ RegexOptions.Compiled | RegexOptions.IgnoreCase
+ );
+
+ // Just an email address
+ private static readonly Regex _explicit =
+ new Regex(
+ @"^[-_a-z0-9'+*$^&%=~!?{}]+(?:\.[-_a-z0-9'+*$^&%=~!?{}]+)*@(?:(?![-.])[-a-z0-9.]+(?<![-.])\.[a-z]{2,6}|\d{1,3}(?:\.\d{1,3}){3})(?::\d+)?$",
+ RegexOptions.Compiled | RegexOptions.IgnoreCase
+ );
+
+ public override bool IsSatisfiedBy(string instance)
+ {
+ var result = _explicit.IsMatch(instance) || _names.IsMatch(instance);
+ return result;
+ }
+ }
+
+
+### Writing a Custom Validation Attribute
+
+You can supply your own transformation or validation behaviors by extending the abstract ValidationAttribute class and providing an
+implementation for the single method defined. The next code example shows a custom implementation of a validation attribute that
+uppercases a string value, and converts null values to string literals. The value passed to TransformValue could be _null_, so your
+validation attribute should account for this.
+
+### Combining Method and Attribute Styles
+
+You can use a combination of method and attribute style programming to build your requests, just keep in mind that Hammock will
+honor the RestClient and then RestRequest values you specify before using attributes. In other words, if you specify a parameter or
+user agent attribute on a class with IWebQueryInfo, that has the same name as a parameter you pass to RestClient, the value of that
+parameter or the user agent will take the RestClient value, not the attribute value. Headers will continue to combine values from all
+sources.
+
+
+
+## Sending Web API Requests
+
+After your request is ready for transport, you can execute it sequentially or asynchronously to return a RestResponse object.
+RestResponse is also available as a generic class scoped to the expected return value. This is useful if you are expecting a response
+entity that you can deserialize into a common class, making the process of converting content from the HTTP seam to regular .NET
+classes transparent; in this case the object is available in `RestResponse<T>`'s ContentEntity property. If you do not specify an
+`IDeserializer` on `RestRequest` or `RestClient`, but you expect a `ContentEntity` anyway, it will return a null value. If you are not
+intending to capture strongly typed responses, you can obtain the raw results from the Content property or cast the `ContentEntity`
+yourself provided you also supplied a ResponseEntityType along with your non-generic request, otherwise the deserializer would not know
+which target type you intended. Other diagnostic information about the request is available in the RestResponse class, and Hammock
+will output essential information about requests and responses through .NET's tracing capability, so you can attach your own listeners
+to log important details.
+
+[]
+
+### Basic Operation
+
+There are two methods available to send sequential requests when your application will wait for the results: `Request`, and `Request<T>`.
+The only difference is whether you expect to deserialize the response body as a .NET class before building the RestResponse object.
+
+<pre>
+using System;
+using System.IO;
+using Hammock.Serialization;
+using Newtonsoft.Json;
+
+namespace Hammock.Extras
+{
+ public class HammockJsonDotNetSerializer : ISerializer, IDeserializer
+ {
+ private readonly JsonSerializer _serializer;
+
+ public HammockJsonDotNetSerializer(JsonSerializerSettings settings)
+ {
+ _serializer = new JsonSerializer
+ {
+ ConstructorHandling = settings.ConstructorHandling,
+ ContractResolver = settings.ContractResolver,
+ ObjectCreationHandling = settings.ObjectCreationHandling,
+ MissingMemberHandling = settings.MissingMemberHandling,
+ DefaultValueHandling = settings.DefaultValueHandling,
+ NullValueHandling = settings.NullValueHandling
+ };
+
+ foreach (var converter in settings.Converters)
+ {
+ _serializer.Converters.Add(converter);
+ }
+ }
+
+ #region IDeserializer Members
+
+ public virtual object Deserialize(string content, Type type)
+ {
+ using (var sr = new StringReader(content))
+ {
+ using (var jtr = new JsonTextReader(sr))
+ {
+ return _serializer.Deserialize(jtr, type);
+ }
+ }
+ }
+
+ public virtual T Deserialize<T>(string content)
+ {
+ using (var sr = new StringReader(content))
+ {
+ using (var jtr = new JsonTextReader(sr))
+ {
+ return _serializer.Deserialize<T>(jtr);
+ }
+ }
+ }
+
+ #endregion
+
+ #region ISerializer Members
+
+ public virtual string Serialize(object instance, Type type)
+ {
+ using (var sw = new StringWriter())
+ {
+ using (var jtw = new JsonTextWriter(sw))
+ {
+ jtw = Formatting.Indented;
+ jtw = '"';
+
+ _serializer.Serialize(jtw, instance);
+ var result = sw();
+ return result;
+ }
+ }
+ }
+
+ public virtual string ContentType
+ {
+ get { return "application/json"; }
+ }
+
+ public virtual Encoding ContentEncoding
+ {
+ get { return Encoding.UTF8; }
+ }
+
+ #endregion
+ }
+}
+</pre>
+
+### Asynchronous Operation
+[]
+
+### Using RetryPolicy and Timeout
+[]
+
+### Caching Responses
+[]
+
+### Mocking Responses
+[]
+
+### Authenticating Requests
+[]
+
+#### Using BasicAuthCredentials
+[]
+
+#### Using OAuthCredentials
+[]
+
+#### Creating Custom Credentials
+[]
+
+### Request Tracing
+[]
+
+### Entity Serialization
+
+Hammock provides hooks to allow you to serialize objects into your preferred format, usually JSON or XML when sending a POST or PUT
+request. This is a common scenario in many APIs that expect an entity when creating or updating records. Similarly, you can attach a
+deserializer to automatically convert a server entity into a regular class, to make it easy to work with in your code.
+
+Hammock doesn't push a particular serialization strategy on you. There are already too many ways to serialize and deserialize objects
+(communiy favorites are JSON.NET http://codeplex.com/json and ServiceStack TypeSerializer http://code.google.com/p/servicestack/wiki/TypeSerializer,
+and we don't want to introduce another one.
+
+You decide how you will serialize or deserialize your entities, and provide an implementation of ISerializer and IDeserializer to do
+the work. That said, Hammock does include stock .NET serializers that will serialize and deserialize entities based on
+DataContractSerializer, DataContractJsonSerializer, JavaScriptSerializer, and XmlSerializer, so if you are already using those schemes
+in your code, hooking them up is straightforward.
+
+#### Creating Custom Serializers
+
+If you are using a different serialization scheme, you will need to provide an implementation of ISerializer, IDeserializer, or both,
+typically in the same concrete class, depending on your needs. One popular serialization library for JSON (with support for XML) is
+JSON.NET, which is used in TweetSharp. Here is an example implementation of a custom Hammock serializer that will let you use JSON.NET
+to serialize and deserialize your request and response entities, respectively. This example is provided in the Hammock.Extras project
+included with the source code.
+
+<pre>
+</pre>
+
+#### Achieving POCO for XML and JSON Entities
+
+#### Dynamic serialization in .NET 4.0
+
+### Periodic Tasks
+
+### Rate Limiting
+
+## Handling REST Responses
+### Deserializing Responses
+### Handling Errors
+
+## Walkthrough: Postmark (JSON)
+
+## Walkthrough: FreshBooks (XML)
+
+## Walkthrough: Twitter (OAuth 1.0a)
+### OAuth 1.0a Authentication
+### Credential Proxies using OAuth Echo
+
+## Walkthrough: Facebook Graph (OAuth 2.0)
+### OAuth 2.0 Authentication
+
+
--- /dev/null
+@echo off
+echo Deleting all bin and obj folders...
+rmdir /s /q bin\lib\
+pushd src
+for /f "tokens=*" %%i in ('DIR /B /AD /S obj') do rmdir /s /q %%i
+for /f "tokens=*" %%i in ('DIR /B /AD /S bin') do rmdir /s /q %%i
+popd
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<package>
+ <metadata>
+ <id>Hammock</id>
+ <version>1.2.6</version>
+ <authors>Daniel Crenna and Jason Diller</authors>
+ <owners>Daniel Crenna</owners>
+ <description>Hammock is an HTTP API library for .NET that greatly simplifies consuming and wrapping RESTful services.</description>
+ <summary>REST, easy.</summary>
+ <language>en-US</language>
+ <projectUrl>http://hammockrest.com</projectUrl>
+ <licenseUrl>https://github.com/danielcrenna/hammock/blob/master/LICENSE</licenseUrl>
+ <iconUrl>http://apitize.com.s3.amazonaws.com/logo_hammock.png</iconUrl>
+ <tags>web api client http rest services wrapper json xml</tags>
+ </metadata>
+</package>
\ No newline at end of file
--- /dev/null
+copy LICENSE bin
+..\NuGet.exe pack hammock.nuspec -b bin -o bin
\ No newline at end of file
--- /dev/null
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hammock.Compact", "netCF\Hammock.Compact\Hammock.Compact.csproj", "{392866D3-D060-4F54-B761-2BAF509989CF}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {392866D3-D060-4F54-B761-2BAF509989CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {392866D3-D060-4F54-B761-2BAF509989CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {392866D3-D060-4F54-B761-2BAF509989CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {392866D3-D060-4F54-B761-2BAF509989CF}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
--- /dev/null
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hammock.Mono", "mono\Hammock.Mono\Hammock.Mono.csproj", "{C8371692-DA90-4437-BCB7-A5A2EF37B095}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hammock.MonoDroid", "mono\Hammock.MonoDroid\Hammock.MonoDroid.csproj", "{63A4D4F2-12EF-48CB-A2A7-2A9E9FF2730D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hammock.MonoTouch", "mono\Hammock.MonoTouch\Hammock.MonoTouch.csproj", "{BB4BA4FD-691F-4E5B-B27D-1E9EC80072AB}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ Debug|iPhoneSimulator = Debug|iPhoneSimulator
+ Release|iPhoneSimulator = Release|iPhoneSimulator
+ Debug|iPhone = Debug|iPhone
+ Release|iPhone = Release|iPhone
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {63A4D4F2-12EF-48CB-A2A7-2A9E9FF2730D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {63A4D4F2-12EF-48CB-A2A7-2A9E9FF2730D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {63A4D4F2-12EF-48CB-A2A7-2A9E9FF2730D}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {63A4D4F2-12EF-48CB-A2A7-2A9E9FF2730D}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {63A4D4F2-12EF-48CB-A2A7-2A9E9FF2730D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {63A4D4F2-12EF-48CB-A2A7-2A9E9FF2730D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {63A4D4F2-12EF-48CB-A2A7-2A9E9FF2730D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {63A4D4F2-12EF-48CB-A2A7-2A9E9FF2730D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {63A4D4F2-12EF-48CB-A2A7-2A9E9FF2730D}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {63A4D4F2-12EF-48CB-A2A7-2A9E9FF2730D}.Release|iPhone.Build.0 = Release|Any CPU
+ {63A4D4F2-12EF-48CB-A2A7-2A9E9FF2730D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {63A4D4F2-12EF-48CB-A2A7-2A9E9FF2730D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {BB4BA4FD-691F-4E5B-B27D-1E9EC80072AB}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
+ {BB4BA4FD-691F-4E5B-B27D-1E9EC80072AB}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator
+ {BB4BA4FD-691F-4E5B-B27D-1E9EC80072AB}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {BB4BA4FD-691F-4E5B-B27D-1E9EC80072AB}.Debug|iPhone.Build.0 = Debug|iPhone
+ {BB4BA4FD-691F-4E5B-B27D-1E9EC80072AB}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {BB4BA4FD-691F-4E5B-B27D-1E9EC80072AB}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {BB4BA4FD-691F-4E5B-B27D-1E9EC80072AB}.Release|Any CPU.ActiveCfg = Release|iPhoneSimulator
+ {BB4BA4FD-691F-4E5B-B27D-1E9EC80072AB}.Release|Any CPU.Build.0 = Release|iPhoneSimulator
+ {BB4BA4FD-691F-4E5B-B27D-1E9EC80072AB}.Release|iPhone.ActiveCfg = Release|iPhone
+ {BB4BA4FD-691F-4E5B-B27D-1E9EC80072AB}.Release|iPhone.Build.0 = Release|iPhone
+ {BB4BA4FD-691F-4E5B-B27D-1E9EC80072AB}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {BB4BA4FD-691F-4E5B-B27D-1E9EC80072AB}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ {C8371692-DA90-4437-BCB7-A5A2EF37B095}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C8371692-DA90-4437-BCB7-A5A2EF37B095}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C8371692-DA90-4437-BCB7-A5A2EF37B095}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {C8371692-DA90-4437-BCB7-A5A2EF37B095}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {C8371692-DA90-4437-BCB7-A5A2EF37B095}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {C8371692-DA90-4437-BCB7-A5A2EF37B095}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {C8371692-DA90-4437-BCB7-A5A2EF37B095}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C8371692-DA90-4437-BCB7-A5A2EF37B095}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C8371692-DA90-4437-BCB7-A5A2EF37B095}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {C8371692-DA90-4437-BCB7-A5A2EF37B095}.Release|iPhone.Build.0 = Release|Any CPU
+ {C8371692-DA90-4437-BCB7-A5A2EF37B095}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {C8371692-DA90-4437-BCB7-A5A2EF37B095}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ StartupItem = mono\Hammock.Mono\Hammock.Mono.csproj
+ Policies = $0
+ $0.DotNetNamingPolicy = $1
+ $1.DirectoryNamespaceAssociation = None
+ $1.ResourceNamePolicy = FileFormatDefault
+ $0.StandardHeader = $2
+ $2.Text =
+ $2.inheritsSet = Apache2License
+ $0.VersionControlPolicy = $3
+ $3.inheritsSet = Mono
+ $0.ChangeLogPolicy = $4
+ $4.UpdateMode = None
+ $4.MessageStyle = $5
+ $5.LineAlign = 0
+ $4.inheritsSet = Mono
+ outputpath = ..\..\bin\mono
+ EndGlobalSection
+EndGlobal
--- /dev/null
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hammock.WindowsPhone", "net40\Hammock.WindowsPhone\Hammock.WindowsPhone.csproj", "{3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.SharpZipLib.WindowsPhone", "net40\ICSharpCode.SharpZipLib.WindowsPhone\ICSharpCode.SharpZipLib.WindowsPhone.csproj", "{BF04A546-D681-4F5A-AC41-CFC67CAEC66E}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
--- /dev/null
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SharpZipLib", "SharpZipLib", "{0D6CBA8E-3846-4559-AA4E-AEE3373A03CB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hammock", "net35\Hammock\Hammock.csproj", "{6679078A-C585-4CB6-96E9-908DBDAA2716}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hammock.Silverlight", "net35\Hammock.Silverlight\Hammock.Silverlight.csproj", "{E0461346-CB62-489E-9893-CFEA249F8380}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.SharpZipLib.Silverlight", "net35\ICSharpCode.SharpZipLib.Silverlight\ICSharpCode.SharpZipLib.Silverlight.csproj", "{2E420750-6124-473B-808D-41755C907648}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".NET 3.5", ".NET 3.5", "{0F12EB19-73E5-4F38-BEF2-070C625508B7}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".NET 4.0", ".NET 4.0", "{3FB92FF7-A9F8-4F15-864B-69E7EBC3E16B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hammock", "net40\Hammock\Hammock.csproj", "{CD569558-9092-466B-8670-EA1B151150E0}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hammock.ClientProfile", "net40\Hammock.ClientProfile\Hammock.ClientProfile.csproj", "{487B7E3C-9689-47BC-8785-73CCD92A3749}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hammock.Silverlight", "net40\Hammock.Silverlight\Hammock.Silverlight.csproj", "{46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.SharpZipLib.Silverlight", "net40\ICSharpCode.SharpZipLib.Silverlight\ICSharpCode.SharpZipLib.Silverlight.csproj", "{5953279F-F478-4D5F-9906-03D56CE2DA2D}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SharpZipLib", "SharpZipLib", "{7090D3D7-90C3-4EB1-BB62-716046673F29}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.SharpZipLib.WindowsPhone", "net40\ICSharpCode.SharpZipLib.WindowsPhone\ICSharpCode.SharpZipLib.WindowsPhone.csproj", "{BF04A546-D681-4F5A-AC41-CFC67CAEC66E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hammock.ClientProfile", "net35\Hammock.ClientProfile\Hammock.ClientProfile.csproj", "{73015806-7BE4-4BAB-AA07-ACC719EFE85A}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".NET 2.0", ".NET 2.0", "{6052AEDE-F8B1-4E24-B791-DBB7FF9621D3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hammock", "net20\Hammock\Hammock.csproj", "{80647B8C-E162-4E34-A758-590280F11B97}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9AE58B14-D363-4A3E-B9E3-005FCBCEA7AC}"
+ ProjectSection(SolutionItems) = preProject
+ net35\BuildWindowsAndRunTests.proj = net35\BuildWindowsAndRunTests.proj
+ ..\clean.bat = ..\clean.bat
+ ..\hammock.nuspec = ..\hammock.nuspec
+ ..\LICENSE = ..\LICENSE
+ ..\pack-nuget.bat = ..\pack-nuget.bat
+ ..\README.markdown = ..\README.markdown
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hammock.WindowsPhone", "net40\Hammock.WindowsPhone\Hammock.WindowsPhone.csproj", "{3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ ClientProfiles|Any CPU = ClientProfiles|Any CPU
+ ClientProfiles|Mixed Platforms = ClientProfiles|Mixed Platforms
+ ClientProfiles|x86 = ClientProfiles|x86
+ Debug|Any CPU = Debug|Any CPU
+ Debug|Mixed Platforms = Debug|Mixed Platforms
+ Debug|x86 = Debug|x86
+ Mono|Any CPU = Mono|Any CPU
+ Mono|Mixed Platforms = Mono|Mixed Platforms
+ Mono|x86 = Mono|x86
+ Release|Any CPU = Release|Any CPU
+ Release|Mixed Platforms = Release|Mixed Platforms
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {6679078A-C585-4CB6-96E9-908DBDAA2716}.ClientProfiles|Any CPU.ActiveCfg = Mono|Any CPU
+ {6679078A-C585-4CB6-96E9-908DBDAA2716}.ClientProfiles|Any CPU.Build.0 = Mono|Any CPU
+ {6679078A-C585-4CB6-96E9-908DBDAA2716}.ClientProfiles|Mixed Platforms.ActiveCfg = Mono|Any CPU
+ {6679078A-C585-4CB6-96E9-908DBDAA2716}.ClientProfiles|Mixed Platforms.Build.0 = Mono|Any CPU
+ {6679078A-C585-4CB6-96E9-908DBDAA2716}.ClientProfiles|x86.ActiveCfg = Mono|Any CPU
+ {6679078A-C585-4CB6-96E9-908DBDAA2716}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6679078A-C585-4CB6-96E9-908DBDAA2716}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6679078A-C585-4CB6-96E9-908DBDAA2716}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {6679078A-C585-4CB6-96E9-908DBDAA2716}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {6679078A-C585-4CB6-96E9-908DBDAA2716}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6679078A-C585-4CB6-96E9-908DBDAA2716}.Mono|Any CPU.ActiveCfg = Mono|Any CPU
+ {6679078A-C585-4CB6-96E9-908DBDAA2716}.Mono|Any CPU.Build.0 = Mono|Any CPU
+ {6679078A-C585-4CB6-96E9-908DBDAA2716}.Mono|Mixed Platforms.ActiveCfg = Mono|Any CPU
+ {6679078A-C585-4CB6-96E9-908DBDAA2716}.Mono|Mixed Platforms.Build.0 = Mono|Any CPU
+ {6679078A-C585-4CB6-96E9-908DBDAA2716}.Mono|x86.ActiveCfg = Mono|Any CPU
+ {6679078A-C585-4CB6-96E9-908DBDAA2716}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6679078A-C585-4CB6-96E9-908DBDAA2716}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6679078A-C585-4CB6-96E9-908DBDAA2716}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {6679078A-C585-4CB6-96E9-908DBDAA2716}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {6679078A-C585-4CB6-96E9-908DBDAA2716}.Release|x86.ActiveCfg = Release|Any CPU
+ {E0461346-CB62-489E-9893-CFEA249F8380}.ClientProfiles|Any CPU.ActiveCfg = Mono|Any CPU
+ {E0461346-CB62-489E-9893-CFEA249F8380}.ClientProfiles|Any CPU.Build.0 = Mono|Any CPU
+ {E0461346-CB62-489E-9893-CFEA249F8380}.ClientProfiles|Mixed Platforms.ActiveCfg = Mono|Any CPU
+ {E0461346-CB62-489E-9893-CFEA249F8380}.ClientProfiles|Mixed Platforms.Build.0 = Mono|Any CPU
+ {E0461346-CB62-489E-9893-CFEA249F8380}.ClientProfiles|x86.ActiveCfg = Mono|Any CPU
+ {E0461346-CB62-489E-9893-CFEA249F8380}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E0461346-CB62-489E-9893-CFEA249F8380}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E0461346-CB62-489E-9893-CFEA249F8380}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {E0461346-CB62-489E-9893-CFEA249F8380}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {E0461346-CB62-489E-9893-CFEA249F8380}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E0461346-CB62-489E-9893-CFEA249F8380}.Mono|Any CPU.ActiveCfg = Mono|Any CPU
+ {E0461346-CB62-489E-9893-CFEA249F8380}.Mono|Any CPU.Build.0 = Mono|Any CPU
+ {E0461346-CB62-489E-9893-CFEA249F8380}.Mono|Mixed Platforms.ActiveCfg = Mono|Any CPU
+ {E0461346-CB62-489E-9893-CFEA249F8380}.Mono|Mixed Platforms.Build.0 = Mono|Any CPU
+ {E0461346-CB62-489E-9893-CFEA249F8380}.Mono|x86.ActiveCfg = Mono|Any CPU
+ {E0461346-CB62-489E-9893-CFEA249F8380}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E0461346-CB62-489E-9893-CFEA249F8380}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E0461346-CB62-489E-9893-CFEA249F8380}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {E0461346-CB62-489E-9893-CFEA249F8380}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {E0461346-CB62-489E-9893-CFEA249F8380}.Release|x86.ActiveCfg = Release|Any CPU
+ {2E420750-6124-473B-808D-41755C907648}.ClientProfiles|Any CPU.ActiveCfg = Release|Any CPU
+ {2E420750-6124-473B-808D-41755C907648}.ClientProfiles|Any CPU.Build.0 = Release|Any CPU
+ {2E420750-6124-473B-808D-41755C907648}.ClientProfiles|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {2E420750-6124-473B-808D-41755C907648}.ClientProfiles|Mixed Platforms.Build.0 = Release|Any CPU
+ {2E420750-6124-473B-808D-41755C907648}.ClientProfiles|x86.ActiveCfg = Release|Any CPU
+ {2E420750-6124-473B-808D-41755C907648}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2E420750-6124-473B-808D-41755C907648}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2E420750-6124-473B-808D-41755C907648}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {2E420750-6124-473B-808D-41755C907648}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {2E420750-6124-473B-808D-41755C907648}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {2E420750-6124-473B-808D-41755C907648}.Mono|Any CPU.ActiveCfg = Release|Any CPU
+ {2E420750-6124-473B-808D-41755C907648}.Mono|Any CPU.Build.0 = Release|Any CPU
+ {2E420750-6124-473B-808D-41755C907648}.Mono|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {2E420750-6124-473B-808D-41755C907648}.Mono|Mixed Platforms.Build.0 = Release|Any CPU
+ {2E420750-6124-473B-808D-41755C907648}.Mono|x86.ActiveCfg = Release|Any CPU
+ {2E420750-6124-473B-808D-41755C907648}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2E420750-6124-473B-808D-41755C907648}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2E420750-6124-473B-808D-41755C907648}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {2E420750-6124-473B-808D-41755C907648}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {2E420750-6124-473B-808D-41755C907648}.Release|x86.ActiveCfg = Release|Any CPU
+ {CD569558-9092-466B-8670-EA1B151150E0}.ClientProfiles|Any CPU.ActiveCfg = ClientProfiles|Any CPU
+ {CD569558-9092-466B-8670-EA1B151150E0}.ClientProfiles|Any CPU.Build.0 = ClientProfiles|Any CPU
+ {CD569558-9092-466B-8670-EA1B151150E0}.ClientProfiles|Mixed Platforms.ActiveCfg = ClientProfiles|Any CPU
+ {CD569558-9092-466B-8670-EA1B151150E0}.ClientProfiles|Mixed Platforms.Build.0 = ClientProfiles|Any CPU
+ {CD569558-9092-466B-8670-EA1B151150E0}.ClientProfiles|x86.ActiveCfg = ClientProfiles|Any CPU
+ {CD569558-9092-466B-8670-EA1B151150E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CD569558-9092-466B-8670-EA1B151150E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CD569558-9092-466B-8670-EA1B151150E0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {CD569558-9092-466B-8670-EA1B151150E0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {CD569558-9092-466B-8670-EA1B151150E0}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {CD569558-9092-466B-8670-EA1B151150E0}.Mono|Any CPU.ActiveCfg = ClientProfiles|Any CPU
+ {CD569558-9092-466B-8670-EA1B151150E0}.Mono|Any CPU.Build.0 = ClientProfiles|Any CPU
+ {CD569558-9092-466B-8670-EA1B151150E0}.Mono|Mixed Platforms.ActiveCfg = ClientProfiles|Any CPU
+ {CD569558-9092-466B-8670-EA1B151150E0}.Mono|Mixed Platforms.Build.0 = ClientProfiles|Any CPU
+ {CD569558-9092-466B-8670-EA1B151150E0}.Mono|x86.ActiveCfg = ClientProfiles|Any CPU
+ {CD569558-9092-466B-8670-EA1B151150E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CD569558-9092-466B-8670-EA1B151150E0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CD569558-9092-466B-8670-EA1B151150E0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {CD569558-9092-466B-8670-EA1B151150E0}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {CD569558-9092-466B-8670-EA1B151150E0}.Release|x86.ActiveCfg = Release|Any CPU
+ {487B7E3C-9689-47BC-8785-73CCD92A3749}.ClientProfiles|Any CPU.ActiveCfg = Release|Any CPU
+ {487B7E3C-9689-47BC-8785-73CCD92A3749}.ClientProfiles|Any CPU.Build.0 = Release|Any CPU
+ {487B7E3C-9689-47BC-8785-73CCD92A3749}.ClientProfiles|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {487B7E3C-9689-47BC-8785-73CCD92A3749}.ClientProfiles|Mixed Platforms.Build.0 = Release|Any CPU
+ {487B7E3C-9689-47BC-8785-73CCD92A3749}.ClientProfiles|x86.ActiveCfg = Release|Any CPU
+ {487B7E3C-9689-47BC-8785-73CCD92A3749}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {487B7E3C-9689-47BC-8785-73CCD92A3749}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {487B7E3C-9689-47BC-8785-73CCD92A3749}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {487B7E3C-9689-47BC-8785-73CCD92A3749}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {487B7E3C-9689-47BC-8785-73CCD92A3749}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {487B7E3C-9689-47BC-8785-73CCD92A3749}.Mono|Any CPU.ActiveCfg = Release|Any CPU
+ {487B7E3C-9689-47BC-8785-73CCD92A3749}.Mono|Any CPU.Build.0 = Release|Any CPU
+ {487B7E3C-9689-47BC-8785-73CCD92A3749}.Mono|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {487B7E3C-9689-47BC-8785-73CCD92A3749}.Mono|Mixed Platforms.Build.0 = Release|Any CPU
+ {487B7E3C-9689-47BC-8785-73CCD92A3749}.Mono|x86.ActiveCfg = Release|Any CPU
+ {487B7E3C-9689-47BC-8785-73CCD92A3749}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {487B7E3C-9689-47BC-8785-73CCD92A3749}.Release|Any CPU.Build.0 = Release|Any CPU
+ {487B7E3C-9689-47BC-8785-73CCD92A3749}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {487B7E3C-9689-47BC-8785-73CCD92A3749}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {487B7E3C-9689-47BC-8785-73CCD92A3749}.Release|x86.ActiveCfg = Release|Any CPU
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}.ClientProfiles|Any CPU.ActiveCfg = ClientProfiles|Any CPU
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}.ClientProfiles|Any CPU.Build.0 = ClientProfiles|Any CPU
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}.ClientProfiles|Mixed Platforms.ActiveCfg = ClientProfiles|Any CPU
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}.ClientProfiles|Mixed Platforms.Build.0 = ClientProfiles|Any CPU
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}.ClientProfiles|x86.ActiveCfg = ClientProfiles|Any CPU
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}.Mono|Any CPU.ActiveCfg = ClientProfiles|Any CPU
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}.Mono|Any CPU.Build.0 = ClientProfiles|Any CPU
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}.Mono|Mixed Platforms.ActiveCfg = ClientProfiles|Any CPU
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}.Mono|Mixed Platforms.Build.0 = ClientProfiles|Any CPU
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}.Mono|x86.ActiveCfg = ClientProfiles|Any CPU
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}.Release|Any CPU.Build.0 = Release|Any CPU
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}.Release|x86.ActiveCfg = Release|Any CPU
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D}.ClientProfiles|Any CPU.ActiveCfg = Release|Any CPU
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D}.ClientProfiles|Any CPU.Build.0 = Release|Any CPU
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D}.ClientProfiles|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D}.ClientProfiles|Mixed Platforms.Build.0 = Release|Any CPU
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D}.ClientProfiles|x86.ActiveCfg = Release|Any CPU
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D}.Mono|Any CPU.ActiveCfg = Release|Any CPU
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D}.Mono|Any CPU.Build.0 = Release|Any CPU
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D}.Mono|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D}.Mono|Mixed Platforms.Build.0 = Release|Any CPU
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D}.Mono|x86.ActiveCfg = Release|Any CPU
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D}.Release|x86.ActiveCfg = Release|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.ClientProfiles|Any CPU.ActiveCfg = Release|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.ClientProfiles|Any CPU.Build.0 = Release|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.ClientProfiles|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.ClientProfiles|Mixed Platforms.Build.0 = Release|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.ClientProfiles|x86.ActiveCfg = Release|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.Mono|Any CPU.ActiveCfg = Release|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.Mono|Any CPU.Build.0 = Release|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.Mono|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.Mono|Mixed Platforms.Build.0 = Release|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.Mono|x86.ActiveCfg = Release|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E}.Release|x86.ActiveCfg = Release|Any CPU
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A}.ClientProfiles|Any CPU.ActiveCfg = Release|Any CPU
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A}.ClientProfiles|Any CPU.Build.0 = Release|Any CPU
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A}.ClientProfiles|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A}.ClientProfiles|Mixed Platforms.Build.0 = Release|Any CPU
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A}.ClientProfiles|x86.ActiveCfg = Release|Any CPU
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A}.Mono|Any CPU.ActiveCfg = Release|Any CPU
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A}.Mono|Any CPU.Build.0 = Release|Any CPU
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A}.Mono|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A}.Mono|Mixed Platforms.Build.0 = Release|Any CPU
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A}.Mono|x86.ActiveCfg = Release|Any CPU
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A}.Release|x86.ActiveCfg = Release|Any CPU
+ {80647B8C-E162-4E34-A758-590280F11B97}.ClientProfiles|Any CPU.ActiveCfg = Release|Any CPU
+ {80647B8C-E162-4E34-A758-590280F11B97}.ClientProfiles|Any CPU.Build.0 = Release|Any CPU
+ {80647B8C-E162-4E34-A758-590280F11B97}.ClientProfiles|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {80647B8C-E162-4E34-A758-590280F11B97}.ClientProfiles|Mixed Platforms.Build.0 = Release|Any CPU
+ {80647B8C-E162-4E34-A758-590280F11B97}.ClientProfiles|x86.ActiveCfg = Release|Any CPU
+ {80647B8C-E162-4E34-A758-590280F11B97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {80647B8C-E162-4E34-A758-590280F11B97}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {80647B8C-E162-4E34-A758-590280F11B97}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {80647B8C-E162-4E34-A758-590280F11B97}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {80647B8C-E162-4E34-A758-590280F11B97}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {80647B8C-E162-4E34-A758-590280F11B97}.Mono|Any CPU.ActiveCfg = Release|Any CPU
+ {80647B8C-E162-4E34-A758-590280F11B97}.Mono|Any CPU.Build.0 = Release|Any CPU
+ {80647B8C-E162-4E34-A758-590280F11B97}.Mono|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {80647B8C-E162-4E34-A758-590280F11B97}.Mono|Mixed Platforms.Build.0 = Release|Any CPU
+ {80647B8C-E162-4E34-A758-590280F11B97}.Mono|x86.ActiveCfg = Release|Any CPU
+ {80647B8C-E162-4E34-A758-590280F11B97}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {80647B8C-E162-4E34-A758-590280F11B97}.Release|Any CPU.Build.0 = Release|Any CPU
+ {80647B8C-E162-4E34-A758-590280F11B97}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {80647B8C-E162-4E34-A758-590280F11B97}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {80647B8C-E162-4E34-A758-590280F11B97}.Release|x86.ActiveCfg = Release|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.ClientProfiles|Any CPU.ActiveCfg = ClientProfiles|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.ClientProfiles|Any CPU.Build.0 = ClientProfiles|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.ClientProfiles|Mixed Platforms.ActiveCfg = ClientProfiles|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.ClientProfiles|Mixed Platforms.Build.0 = ClientProfiles|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.ClientProfiles|x86.ActiveCfg = ClientProfiles|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.Mono|Any CPU.ActiveCfg = ClientProfiles|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.Mono|Any CPU.Build.0 = ClientProfiles|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.Mono|Mixed Platforms.ActiveCfg = ClientProfiles|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.Mono|Mixed Platforms.Build.0 = ClientProfiles|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.Mono|x86.ActiveCfg = ClientProfiles|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}.Release|x86.ActiveCfg = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {6679078A-C585-4CB6-96E9-908DBDAA2716} = {0F12EB19-73E5-4F38-BEF2-070C625508B7}
+ {E0461346-CB62-489E-9893-CFEA249F8380} = {0F12EB19-73E5-4F38-BEF2-070C625508B7}
+ {0D6CBA8E-3846-4559-AA4E-AEE3373A03CB} = {0F12EB19-73E5-4F38-BEF2-070C625508B7}
+ {73015806-7BE4-4BAB-AA07-ACC719EFE85A} = {0F12EB19-73E5-4F38-BEF2-070C625508B7}
+ {2E420750-6124-473B-808D-41755C907648} = {0D6CBA8E-3846-4559-AA4E-AEE3373A03CB}
+ {CD569558-9092-466B-8670-EA1B151150E0} = {3FB92FF7-A9F8-4F15-864B-69E7EBC3E16B}
+ {487B7E3C-9689-47BC-8785-73CCD92A3749} = {3FB92FF7-A9F8-4F15-864B-69E7EBC3E16B}
+ {46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51} = {3FB92FF7-A9F8-4F15-864B-69E7EBC3E16B}
+ {7090D3D7-90C3-4EB1-BB62-716046673F29} = {3FB92FF7-A9F8-4F15-864B-69E7EBC3E16B}
+ {3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC} = {3FB92FF7-A9F8-4F15-864B-69E7EBC3E16B}
+ {5953279F-F478-4D5F-9906-03D56CE2DA2D} = {7090D3D7-90C3-4EB1-BB62-716046673F29}
+ {BF04A546-D681-4F5A-AC41-CFC67CAEC66E} = {7090D3D7-90C3-4EB1-BB62-716046673F29}
+ {80647B8C-E162-4E34-A758-590280F11B97} = {6052AEDE-F8B1-4E24-B791-DBB7FF9621D3}
+ EndGlobalSection
+EndGlobal
--- /dev/null
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle("Hammock.Mono")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion("1.0.*")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{C8371692-DA90-4437-BCB7-A5A2EF37B095}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <RootNamespace>Hammock.Mono</RootNamespace>
+ <AssemblyName>Hammock.Mono</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <SignAssembly>true</SignAssembly>
+ <AssemblyOriginatorKeyFile>..\..\net35\Hammock\key.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\bin\mono</OutputPath>
+ <DefineConstants>DEBUG,Mono,MONO</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>full</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\bin\mono</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ <DefineConstants>Mono,MONO</DefineConstants>
+ <DebugSymbols>true</DebugSymbols>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Web" />
+ <Reference Include="System.Xml.Linq">
+ </Reference>
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Runtime.Serialization">
+ </Reference>
+ <Reference Include="System.ServiceModel.Web">
+ </Reference>
+ <Reference Include="System.ServiceModel">
+ </Reference>
+ <Reference Include="System.Web.Extensions">
+ </Reference>
+ <Reference Include="System.Core">
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ <Reference Include="System.Security" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="AssemblyInfo.cs" />
+ <Compile Include="..\..\net35\Hammock\IRestClient.cs" />
+ <Compile Include="..\..\net35\Hammock\RestBase.cs" />
+ <Compile Include="..\..\net35\Hammock\RestCallback.cs" />
+ <Compile Include="..\..\net35\Hammock\RestClient.cs" />
+ <Compile Include="..\..\net35\Hammock\RestRequest.cs" />
+ <Compile Include="..\..\net35\Hammock\RestResponse.cs" />
+ <Compile Include="..\..\net35\Hammock\Attributes\INamedAttribute.cs" />
+ <Compile Include="..\..\net35\Hammock\Attributes\IValidatingAttribute.cs" />
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\EntityAttribute.cs" />
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\HeaderAttribute.cs" />
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\ParameterAttribute.cs">
+ <Link>Attributes\ParameterAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\UserAgentAttribute.cs">
+ <Link>Attributes\UserAgentAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\BooleanToIntegerAttribute.cs">
+ <Link>Attributes\BooleanToIntegerAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\DateTimeFormatAttribute.cs">
+ <Link>Attributes\DateTimeFormatAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\RequiredAttribute.cs">
+ <Link>Attributes\RequiredAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\SpecificationAttribute.cs">
+ <Link>Attributes\SpecificationAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\ValidationAttribute.cs" />
+ <Compile Include="..\..\net35\Hammock\Authentication\IWebCredentials.cs" />
+ <Compile Include="..\..\net35\Hammock\Authentication\Basic\BasicAuthCredentials.cs" />
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthCredentials.cs" />
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthParameterHandling.cs" />
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthSignatureMethod.cs" />
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthToken.cs" />
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthTools.cs" />
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthType.cs" />
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWebQuery.cs" />
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWebQueryInfo.cs" />
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWorkflow.cs" />
+ <Compile Include="..\..\net35\Hammock\Caching\AspNetCache.cs" />
+ <Compile Include="..\..\net35\Hammock\Caching\CacheFactory.cs" />
+ <Compile Include="..\..\net35\Hammock\Caching\CacheMode.cs" />
+ <Compile Include="..\..\net35\Hammock\Caching\CacheOptions.cs" />
+ <Compile Include="..\..\net35\Hammock\Caching\ICache.cs" />
+ <Compile Include="..\..\net35\Hammock\Caching\IDependencyCache.cs" />
+ <Compile Include="..\..\net35\Hammock\Caching\SimpleCache.cs" />
+ <Compile Include="..\..\net35\Hammock\Extensions\CollectionExtensions.cs" />
+ <Compile Include="..\..\net35\Hammock\Extensions\FormatExtensions.cs" />
+ <Compile Include="..\..\net35\Hammock\Extensions\OAuthExtensions.cs" />
+ <Compile Include="..\..\net35\Hammock\Extensions\ObjectExtensions.cs" />
+ <Compile Include="..\..\net35\Hammock\Extensions\ReflectionExtensions.cs" />
+ <Compile Include="..\..\net35\Hammock\Extensions\SpecificationExtensions.cs" />
+ <Compile Include="..\..\net35\Hammock\Extensions\StringExtensions.cs" />
+ <Compile Include="..\..\net35\Hammock\Extensions\TimeExtensions.cs" />
+ <Compile Include="..\..\net35\Hammock\Extensions\WebExtensions.cs" />
+ <Compile Include="..\..\net35\Hammock\Model\PropertyChangedBase.cs" />
+ <Compile Include="..\..\net35\Hammock\Retries\ConnectionClosed.cs" />
+ <Compile Include="..\..\net35\Hammock\Retries\IRetryCondition.cs" />
+ <Compile Include="..\..\net35\Hammock\Retries\NetworkError.cs" />
+ <Compile Include="..\..\net35\Hammock\Retries\RetryErrorCondition.cs" />
+ <Compile Include="..\..\net35\Hammock\Retries\RetryPolicy.cs" />
+ <Compile Include="..\..\net35\Hammock\Retries\Timeout.cs" />
+ <Compile Include="..\..\net35\Hammock\Serialization\HammockDataContractJsonSerializer.cs" />
+ <Compile Include="..\..\net35\Hammock\Serialization\HammockDataContractSerializer.cs" />
+ <Compile Include="..\..\net35\Hammock\Serialization\HammockJavaScriptSerializer.cs" />
+ <Compile Include="..\..\net35\Hammock\Serialization\HammockXmlSerializer.cs" />
+ <Compile Include="..\..\net35\Hammock\Serialization\IDeserializer.cs" />
+ <Compile Include="..\..\net35\Hammock\Serialization\ISerializer.cs" />
+ <Compile Include="..\..\net35\Hammock\Serialization\Utf8Serializer.cs" />
+ <Compile Include="..\..\net35\Hammock\Specifications\AndSpecification.cs">
+ <Link>Specifications\AndSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\CompositeSpecificationBase.cs" />
+ <Compile Include="..\..\net35\Hammock\Specifications\HammockSpecification.cs" />
+ <Compile Include="..\..\net35\Hammock\Specifications\ISpecification.cs" />
+ <Compile Include="..\..\net35\Hammock\Specifications\NotSpecification.cs" />
+ <Compile Include="..\..\net35\Hammock\Specifications\OrSpecification.cs" />
+ <Compile Include="..\..\net35\Hammock\Tasks\IRateLimitingRule.cs" />
+ <Compile Include="..\..\net35\Hammock\Tasks\ITaskOptions.cs" />
+ <Compile Include="..\..\net35\Hammock\Tasks\ITimedTask.cs" />
+ <Compile Include="..\..\net35\Hammock\Tasks\RateLimitingRule.cs" />
+ <Compile Include="..\..\net35\Hammock\Tasks\RateLimitType.cs" />
+ <Compile Include="..\..\net35\Hammock\Tasks\TaskOptions.cs" />
+ <Compile Include="..\..\net35\Hammock\Tasks\TimedTask.cs" />
+ <Compile Include="..\..\net35\Hammock\Validation\ValidationException.cs" />
+ <Compile Include="..\..\net35\Hammock\Validation\ValidEmailSpecification.cs">
+ <Link>Specifications\ValidEmailSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\BasicAuthWebQuery.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\GetOrDelete.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\HttpPostParameter.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\HttpPostParameterType.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\IWebQueryInfo.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\Pair.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\PostOrPut.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\Triplet.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\WebCallback.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\WebEntity.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\WebHeader.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\WebHeaderCollection.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\WebMethod.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\WebPair.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\WebPairCollection.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\WebParameter.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\WebParameterCollection.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\WebQuery.Async.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\WebQuery.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryAsyncResult.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryRequestEventArgs.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryResponseEventArgs.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryResult.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\IMockable.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\IWebResponse.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockHttpWebRequest.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockHttpWebResponse.cs" />
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockWebRequestFactory.cs" />
+ <Compile Include="..\..\net35\Hammock\Streaming\StreamOptions.cs" />
+ <Compile Include="..\..\net35\Hammock\Retries\IRetryCustomCondition.cs" />
+ <Compile Include="..\..\net35\Hammock\Retries\RetryCustomCondition.cs" />
+ <Compile Include="..\..\net35\Hammock\Retries\RetryResultCondition.cs" />
+ <Compile Include="..\..\net35\Hammock\Tasks\IRateLimitStatus.cs" />
+ <Compile Include="..\..\net35\Hammock\Tasks\ITaskState.cs" />
+ <Compile Include="..\..\net35\Hammock\Tasks\TaskState.cs" />
+ <Compile Include="..\..\net35\Hammock\Mono\HttpUtility.cs">
+ <Link>HttpUtility.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Mono\WebHeaderCollection.cs">
+ <Link>WebHeaderCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\HttpCookieParameter.cs">
+ <Link>HttpCookieParameter.cs</Link>
+ </Compile>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <ItemGroup>
+ <Folder Include="Specifications\" />
+ <Folder Include="Attributes\" />
+ </ItemGroup>
+</Project>
\ No newline at end of file
--- /dev/null
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hammock.Mono", "Hammock.Mono.csproj", "{C8371692-DA90-4437-BCB7-A5A2EF37B095}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C8371692-DA90-4437-BCB7-A5A2EF37B095}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C8371692-DA90-4437-BCB7-A5A2EF37B095}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C8371692-DA90-4437-BCB7-A5A2EF37B095}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C8371692-DA90-4437-BCB7-A5A2EF37B095}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ StartupItem = Hammock.Mono.csproj
+ EndGlobalSection
+EndGlobal
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>10.0.0</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{63A4D4F2-12EF-48CB-A2A7-2A9E9FF2730D}</ProjectGuid>
+ <ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <OutputType>Library</OutputType>
+ <RootNamespace>Hammock.MonoDroid</RootNamespace>
+ <MonoDroidResourcePrefix>Resources</MonoDroidResourcePrefix>
+ <AssemblyName>Hammock.MonoDroid</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\bin\mono</OutputPath>
+ <DefineConstants>DEBUG</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>none</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\bin\mono</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ <DefineConstants>Mono,MonoDroid,MonoTouch</DefineConstants>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Xml" />
+ <Reference Include="System.Core" />
+ <Reference Include="Mono.Android" />
+ </ItemGroup>
+ <Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
+ <ProjectExtensions>
+ <MonoDevelop>
+ <Properties InternalTargetFrameworkVersion="MonoDroid" />
+ </MonoDevelop>
+ </ProjectExtensions>
+ <ItemGroup>
+ <Folder Include="Attributes\" />
+ <Folder Include="Authentication\" />
+ <Folder Include="Authentication\Basic\" />
+ <Folder Include="Authentication\OAuth\" />
+ <Folder Include="Caching\" />
+ <Folder Include="Extensions\" />
+ <Folder Include="Model\" />
+ <Folder Include="Mono\" />
+ </ItemGroup>
+</Project>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">iPhoneSimulator</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{BB4BA4FD-691F-4E5B-B27D-1E9EC80072AB}</ProjectGuid>
+ <ProjectTypeGuids>{E613F3A2-FE9C-494F-B74E-F63BCB86FEA6};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <OutputType>Library</OutputType>
+ <RootNamespace>Hammock.MonoTouch</RootNamespace>
+ <MtouchMinimumOS>3.0</MtouchMinimumOS>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhoneSimulator' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\bin\mono</OutputPath>
+ <DefineConstants>DEBUG,MonoTouch</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ <MtouchLink>None</MtouchLink>
+ <MtouchDebug>True</MtouchDebug>
+ <AssemblyName>HammockMonoTouch</AssemblyName>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' ">
+ <DebugType>none</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\bin\mono</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <MtouchDebug>False</MtouchDebug>
+ <ConsolePause>false</ConsolePause>
+ <MtouchLink>None</MtouchLink>
+ <DefineConstants>MonoTouch</DefineConstants>
+ <AssemblyName>Hammock.MonoTouch</AssemblyName>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\iPhone\Debug</OutputPath>
+ <DefineConstants>DEBUG</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ <CodesignKey>iPhone Developer</CodesignKey>
+ <MtouchDebug>True</MtouchDebug>
+ <AssemblyName>HammockMonoTouch</AssemblyName>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' ">
+ <DebugType>none</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\iPhone\Release</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <MtouchDebug>False</MtouchDebug>
+ <ConsolePause>false</ConsolePause>
+ <CodesignKey>iPhone Developer</CodesignKey>
+ <AssemblyName>HammockMonoTouch</AssemblyName>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Xml" />
+ <Reference Include="System.Core" />
+ <Reference Include="monotouch" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <ProjectExtensions>
+ <MonoDevelop>
+ <Properties InternalTargetFrameworkVersion="IPhone" />
+ </MonoDevelop>
+ </ProjectExtensions>
+ <ItemGroup>
+ <Folder Include="Web\Mocks\" />
+ <Folder Include="Authentication\OAuth\" />
+ <Folder Include="Authentication\Basic\" />
+ <Folder Include="Attributes\Validation\" />
+ <Folder Include="Attributes\Specialized\" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\..\net35\Hammock\Serialization\HammockXmlSerializer.cs">
+ <Link>Serialization\HammockXmlSerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\IDeserializer.cs">
+ <Link>Serialization\IDeserializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\ISerializer.cs">
+ <Link>Serialization\ISerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\Utf8Serializer.cs">
+ <Link>Serialization\Utf8Serializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\AndSpecification.cs">
+ <Link>Specifications\AndSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\BasicAuthWebQuery.cs">
+ <Link>Web\BasicAuthWebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\GetOrDelete.cs">
+ <Link>Web\GetOrDelete.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebEntity.cs">
+ <Link>Web\WebEntity.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebHeader.cs">
+ <Link>Web\WebHeader.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebMethod.cs">
+ <Link>Web\WebMethod.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryRequestEventArgs.cs">
+ <Link>Web\WebQueryRequestEventArgs.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryResponseEventArgs.cs">
+ <Link>Web\WebQueryResponseEventArgs.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryResult.cs">
+ <Link>Web\WebQueryResult.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\IMockable.cs">
+ <Link>Web\Mocks\IMockable.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\IWebResponse.cs">
+ <Link>Web\Mocks\IWebResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockHttpWebRequest.cs">
+ <Link>Web\Mocks\MockHttpWebRequest.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockHttpWebResponse.cs">
+ <Link>Web\Mocks\MockHttpWebResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockWebRequestFactory.cs">
+ <Link>Web\Mocks\MockWebRequestFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TimedTask.cs">
+ <Link>Tasks\TimedTask.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TaskState.cs">
+ <Link>Tasks\TaskState.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TaskOptions.cs">
+ <Link>Tasks\TaskOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\RateLimitType.cs">
+ <Link>Tasks\RateLimitType.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\RateLimitingRule.cs">
+ <Link>Tasks\RateLimitingRule.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITimedTask.cs">
+ <Link>Tasks\ITimedTask.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITaskState.cs">
+ <Link>Tasks\ITaskState.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITaskOptions.cs">
+ <Link>Tasks\ITaskOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\IRateLimitStatus.cs">
+ <Link>Tasks\IRateLimitStatus.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\IRateLimitingRule.cs">
+ <Link>Tasks\IRateLimitingRule.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Validation\ValidEmailSpecification.cs">
+ <Link>Validation\ValidEmailSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Validation\ValidationException.cs">
+ <Link>Validation\ValidationException.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\IWebCredentials.cs">
+ <Link>Authentication\IWebCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\Basic\BasicAuthCredentials.cs">
+ <Link>Authentication\Basic\BasicAuthCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWorkflow.cs">
+ <Link>Authentication\OAuth\OAuthWorkflow.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWebQueryInfo.cs">
+ <Link>Authentication\OAuth\OAuthWebQueryInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWebQuery.cs">
+ <Link>Authentication\OAuth\OAuthWebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthType.cs">
+ <Link>Authentication\OAuth\OAuthType.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthTools.cs">
+ <Link>Authentication\OAuth\OAuthTools.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthToken.cs">
+ <Link>Authentication\OAuth\OAuthToken.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthSignatureMethod.cs">
+ <Link>Authentication\OAuth\OAuthSignatureMethod.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthParameterHandling.cs">
+ <Link>Authentication\OAuth\OAuthParameterHandling.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthCredentials.cs">
+ <Link>Authentication\OAuth\OAuthCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\Timeout.cs">
+ <Link>Retries\Timeout.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryResultCondition.cs">
+ <Link>Retries\RetryResultCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryPolicy.cs">
+ <Link>Retries\RetryPolicy.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryErrorCondition.cs">
+ <Link>Retries\RetryErrorCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryCustomCondition.cs">
+ <Link>Retries\RetryCustomCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryCondition.cs">
+ <Link>Retries\RetryCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\NetworkError.cs">
+ <Link>Retries\NetworkError.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\IRetryCustomCondition.cs">
+ <Link>Retries\IRetryCustomCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\IRetryCondition.cs">
+ <Link>Retries\IRetryCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\ConnectionClosed.cs">
+ <Link>Retries\ConnectionClosed.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\IValidatingAttribute.cs">
+ <Link>Attributes\IValidatingAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\INamedAttribute.cs">
+ <Link>Attributes\INamedAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\ValidationAttribute.cs">
+ <Link>Attributes\Validation\ValidationAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\SpecificationAttribute.cs">
+ <Link>Attributes\Validation\SpecificationAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\RequiredAttribute.cs">
+ <Link>Attributes\Validation\RequiredAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\DateTimeFormatAttribute.cs">
+ <Link>Attributes\Validation\DateTimeFormatAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\BooleanToIntegerAttribute.cs">
+ <Link>Attributes\Validation\BooleanToIntegerAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\UserAgentAttribute.cs">
+ <Link>Attributes\Specialized\UserAgentAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\ParameterAttribute.cs">
+ <Link>Attributes\Specialized\ParameterAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\HeaderAttribute.cs">
+ <Link>Attributes\Specialized\HeaderAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\EntityAttribute.cs">
+ <Link>Attributes\Specialized\EntityAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\SimpleCache.cs">
+ <Link>Caching\SimpleCache.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\ICache.cs">
+ <Link>Caching\ICache.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheOptions.cs">
+ <Link>Caching\CacheOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheMode.cs">
+ <Link>Caching\CacheMode.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheFactory.cs">
+ <Link>Caching\CacheFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Streaming\StreamOptions.cs">
+ <Link>Streaming\StreamOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\WebExtensions.cs">
+ <Link>Extensions\WebExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\TimeExtensions.cs">
+ <Link>Extensions\TimeExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\StringExtensions.cs">
+ <Link>Extensions\StringExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\SpecificationExtensions.cs">
+ <Link>Extensions\SpecificationExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\ReflectionExtensions.cs">
+ <Link>Extensions\ReflectionExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\ObjectExtensions.cs">
+ <Link>Extensions\ObjectExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\OAuthExtensions.cs">
+ <Link>Extensions\OAuthExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\FormatExtensions.cs">
+ <Link>Extensions\FormatExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\CollectionExtensions.cs">
+ <Link>Extensions\CollectionExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Model\PropertyChangedBase.cs">
+ <Link>Model\PropertyChangedBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Mono\HttpUtility.cs">
+ <Link>Mono\HttpUtility.cs</Link>
+ </Compile>
+ </ItemGroup>
+</Project>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{80647B8C-E162-4E34-A758-590280F11B97}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Hammock</RootNamespace>
+ <AssemblyName>Hammock</AssemblyName>
+ <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\bin\lib\2.0\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;NET20</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\bin\lib\net20\</OutputPath>
+ <DefineConstants>TRACE;NET20</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup>
+ <SignAssembly>true</SignAssembly>
+ </PropertyGroup>
+ <PropertyGroup>
+ <AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="LinqBridge">
+ <HintPath>..\..\..\lib\LinqBridge.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Web" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\..\net35\Hammock\Attributes\INamedAttribute.cs">
+ <Link>Attributes\INamedAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\IValidatingAttribute.cs">
+ <Link>Attributes\IValidatingAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\EntityAttribute.cs">
+ <Link>Attributes\Specialized\EntityAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\HeaderAttribute.cs">
+ <Link>Attributes\Specialized\HeaderAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\ParameterAttribute.cs">
+ <Link>Attributes\Specialized\ParameterAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\UserAgentAttribute.cs">
+ <Link>Attributes\Specialized\UserAgentAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\BooleanToIntegerAttribute.cs">
+ <Link>Attributes\Validation\BooleanToIntegerAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\DateTimeFormatAttribute.cs">
+ <Link>Attributes\Validation\DateTimeFormatAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\RequiredAttribute.cs">
+ <Link>Attributes\Validation\RequiredAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\SpecificationAttribute.cs">
+ <Link>Attributes\Validation\SpecificationAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\ValidationAttribute.cs">
+ <Link>Attributes\Validation\ValidationAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\Basic\BasicAuthCredentials.cs">
+ <Link>Authentication\Basic\BasicAuthCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\IWebCredentials.cs">
+ <Link>Authentication\IWebCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthCredentials.cs">
+ <Link>Authentication\OAuth\OAuthCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthParameterHandling.cs">
+ <Link>Authentication\OAuth\OAuthParameterHandling.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthSignatureMethod.cs">
+ <Link>Authentication\OAuth\OAuthSignatureMethod.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthToken.cs">
+ <Link>Authentication\OAuth\OAuthToken.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthTools.cs">
+ <Link>Authentication\OAuth\OAuthTools.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthType.cs">
+ <Link>Authentication\OAuth\OAuthType.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWebQuery.cs">
+ <Link>Authentication\OAuth\OAuthWebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWebQueryInfo.cs">
+ <Link>Authentication\OAuth\OAuthWebQueryInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWorkflow.cs">
+ <Link>Authentication\OAuth\OAuthWorkflow.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\AspNetCache.cs">
+ <Link>Caching\AspNetCache.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheFactory.cs">
+ <Link>Caching\CacheFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheMode.cs">
+ <Link>Caching\CacheMode.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheOptions.cs">
+ <Link>Caching\CacheOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\ICache.cs">
+ <Link>Caching\ICache.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\IDependencyCache.cs">
+ <Link>Caching\IDependencyCache.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\SimpleCache.cs">
+ <Link>Caching\SimpleCache.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\CollectionExtensions.cs">
+ <Link>Extensions\CollectionExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\FormatExtensions.cs">
+ <Link>Extensions\FormatExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\OAuthExtensions.cs">
+ <Link>Extensions\OAuthExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\ObjectExtensions.cs">
+ <Link>Extensions\ObjectExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\ReflectionExtensions.cs">
+ <Link>Extensions\ReflectionExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\SpecificationExtensions.cs">
+ <Link>Extensions\SpecificationExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\StringExtensions.cs">
+ <Link>Extensions\StringExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\TimeExtensions.cs">
+ <Link>Extensions\TimeExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\WebExtensions.cs">
+ <Link>Extensions\WebExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\IRestClient.cs">
+ <Link>IRestClient.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Model\PropertyChangedBase.cs">
+ <Link>Model\PropertyChangedBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Mono\HttpUtility.cs">
+ <Link>Mono\HttpUtility.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Mono\WebHeaderCollection.cs">
+ <Link>Mono\WebHeaderCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestBase.cs">
+ <Link>RestBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestCallback.cs">
+ <Link>RestCallback.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestClient.cs">
+ <Link>RestClient.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestRequest.cs">
+ <Link>RestRequest.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestResponse.cs">
+ <Link>RestResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\ConnectionClosed.cs">
+ <Link>Retries\ConnectionClosed.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\IRetryCondition.cs">
+ <Link>Retries\IRetryCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\IRetryCustomCondition.cs">
+ <Link>Retries\IRetryCustomCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\NetworkError.cs">
+ <Link>Retries\NetworkError.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryCondition.cs">
+ <Link>Retries\RetryCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryCustomCondition.cs">
+ <Link>Retries\RetryCustomCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryErrorCondition.cs">
+ <Link>Retries\RetryErrorCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryPolicy.cs">
+ <Link>Retries\RetryPolicy.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryResultCondition.cs">
+ <Link>Retries\RetryResultCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\Timeout.cs">
+ <Link>Retries\Timeout.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\HammockXmlSerializer.cs">
+ <Link>Serialization\HammockXmlSerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\IDeserializer.cs">
+ <Link>Serialization\IDeserializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\ISerializer.cs">
+ <Link>Serialization\ISerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\Utf8Serializer.cs">
+ <Link>Serialization\Utf8Serializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\AndSpecification.cs">
+ <Link>Specifications\AndSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\CompositeSpecificationBase.cs">
+ <Link>Specifications\CompositeSpecificationBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\HammockSpecification.cs">
+ <Link>Specifications\HammockSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\ISpecification.cs">
+ <Link>Specifications\ISpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\NotSpecification.cs">
+ <Link>Specifications\NotSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\OrSpecification.cs">
+ <Link>Specifications\OrSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Streaming\StreamOptions.cs">
+ <Link>Streaming\StreamOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\IRateLimitingRule.cs">
+ <Link>Tasks\IRateLimitingRule.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\IRateLimitStatus.cs">
+ <Link>Tasks\IRateLimitStatus.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITaskOptions.cs">
+ <Link>Tasks\ITaskOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITaskState.cs">
+ <Link>Tasks\ITaskState.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITimedTask.cs">
+ <Link>Tasks\ITimedTask.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\RateLimitingRule.cs">
+ <Link>Tasks\RateLimitingRule.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\RateLimitType.cs">
+ <Link>Tasks\RateLimitType.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TaskOptions.cs">
+ <Link>Tasks\TaskOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TaskState.cs">
+ <Link>Tasks\TaskState.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TimedTask.cs">
+ <Link>Tasks\TimedTask.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Validation\ValidationException.cs">
+ <Link>Validation\ValidationException.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Validation\ValidEmailSpecification.cs">
+ <Link>Validation\ValidEmailSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\BasicAuthWebQuery.cs">
+ <Link>Web\BasicAuthWebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\GetOrDelete.cs">
+ <Link>Web\GetOrDelete.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\HttpCookieParameter.cs">
+ <Link>Web\HttpCookieParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\HttpPostParameter.cs">
+ <Link>Web\HttpPostParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\HttpPostParameterType.cs">
+ <Link>Web\HttpPostParameterType.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\IWebQueryInfo.cs">
+ <Link>Web\IWebQueryInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\IMockable.cs">
+ <Link>Web\Mocks\IMockable.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\IWebResponse.cs">
+ <Link>Web\Mocks\IWebResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockHttpWebRequest.cs">
+ <Link>Web\Mocks\MockHttpWebRequest.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockHttpWebResponse.cs">
+ <Link>Web\Mocks\MockHttpWebResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockWebRequestFactory.cs">
+ <Link>Web\Mocks\MockWebRequestFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Pair.cs">
+ <Link>Web\Pair.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\PostOrPut.cs">
+ <Link>Web\PostOrPut.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Triplet.cs">
+ <Link>Web\Triplet.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebCallback.cs">
+ <Link>Web\WebCallback.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebEntity.cs">
+ <Link>Web\WebEntity.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebHeader.cs">
+ <Link>Web\WebHeader.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebHeaderCollection.cs">
+ <Link>Web\WebHeaderCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebMethod.cs">
+ <Link>Web\WebMethod.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebPair.cs">
+ <Link>Web\WebPair.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebPairCollection.cs">
+ <Link>Web\WebPairCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebParameter.cs">
+ <Link>Web\WebParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebParameterCollection.cs">
+ <Link>Web\WebParameterCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQuery.Async.cs">
+ <Link>Web\WebQuery.Async.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQuery.cs">
+ <Link>Web\WebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryAsyncResult.cs">
+ <Link>Web\WebQueryAsyncResult.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryRequestEventArgs.cs">
+ <Link>Web\WebQueryRequestEventArgs.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryResponseEventArgs.cs">
+ <Link>Web\WebQueryResponseEventArgs.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryResult.cs">
+ <Link>Web\WebQueryResult.cs</Link>
+ </Compile>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="key.snk" />
+ </ItemGroup>
+ <ItemGroup />
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
\ No newline at end of file
--- /dev/null
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Security;
+
+// 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("Hammock")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apitize")]
+[assembly: AssemblyProduct("Hammock")]
+[assembly: AssemblyCopyright("Copyright © 2010 Daniel Crenna and Jason Diller")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: AllowPartiallyTrustedCallers]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("b86616db-abb6-4989-9464-67b1e948fdd1")]
+
+// 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 Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null
+<!--This is the MSBuild script for TeamCity
+ It builds the windows dll and runs the primary unit tests-->
+<Project DefaultTargets="BuildAndTest" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration>Debug</Configuration>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <TestSetupFile></TestSetupFile>
+ </PropertyGroup>
+ <ItemGroup>
+ <TestAssemblies Include="$(MSBuildProjectDirectory)\Hammock.Tests\bin\Debug\Hammock.Tests.dll"/>
+ </ItemGroup>
+ <Target Name="BuildAndTest" DependsOnTargets="BuildTestProject">
+ <Exec Command="$(teamcity_dotnet_nunitlauncher) v2.0 x86 NUnit-2.5.0 @(TestAssemblies)" />
+ </Target>
+ <Target Name="BuildTestProject" DependsOnTargets="Build">
+ <MSBuild Projects="$(MSBuildProjectDirectory)\Hammock.Tests\Hammock.Tests.csproj"/>
+ </Target>
+ <Target Name="Build" DependsOnTargets="CopyTestSetup">
+ <MSBuild Projects="$(MSBuildProjectDirectory)\Hammock\Hammock.csproj"/>
+ </Target>
+ <Target Name="CopyTestSetup">
+ <Message Text="Copying test setup file..."/>
+ <Exec Command ="copy $(TestSetupFile) $(MSBuildProjectDirectory)\Hammock.Tests\app.config" />
+ </Target>
+</Project>
+
+
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{73015806-7BE4-4BAB-AA07-ACC719EFE85A}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Hammock</RootNamespace>
+ <AssemblyName>Hammock.ClientProfile</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <TargetFrameworkProfile>Client</TargetFrameworkProfile>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\bin\lib\3.5\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;ClientProfiles</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\bin\lib\net35-client\</OutputPath>
+ <DefineConstants>TRACE;NET35,ClientProfiles</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup>
+ <SignAssembly>true</SignAssembly>
+ </PropertyGroup>
+ <PropertyGroup>
+ <AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Runtime.Serialization" />
+ <Reference Include="System.Servicemodel.Web" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\Hammock\Attributes\INamedAttribute.cs">
+ <Link>Attributes\INamedAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Attributes\IValidatingAttribute.cs">
+ <Link>Attributes\IValidatingAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Attributes\Specialized\EntityAttribute.cs">
+ <Link>Attributes\Specialized\EntityAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Attributes\Specialized\HeaderAttribute.cs">
+ <Link>Attributes\Specialized\HeaderAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Attributes\Specialized\ParameterAttribute.cs">
+ <Link>Attributes\Specialized\ParameterAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Attributes\Specialized\UserAgentAttribute.cs">
+ <Link>Attributes\Specialized\UserAgentAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Attributes\Validation\BooleanToIntegerAttribute.cs">
+ <Link>Attributes\Validation\BooleanToIntegerAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Attributes\Validation\DateTimeFormatAttribute.cs">
+ <Link>Attributes\Validation\DateTimeFormatAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Attributes\Validation\RequiredAttribute.cs">
+ <Link>Attributes\Validation\RequiredAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Attributes\Validation\SpecificationAttribute.cs">
+ <Link>Attributes\Validation\SpecificationAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Attributes\Validation\ValidationAttribute.cs">
+ <Link>Attributes\Validation\ValidationAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\Basic\BasicAuthCredentials.cs">
+ <Link>Authentication\Basic\BasicAuthCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\IWebCredentials.cs">
+ <Link>Authentication\IWebCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\OAuth\OAuthCredentials.cs">
+ <Link>Authentication\OAuth\OAuthCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\OAuth\OAuthParameterHandling.cs">
+ <Link>Authentication\OAuth\OAuthParameterHandling.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\OAuth\OAuthSignatureMethod.cs">
+ <Link>Authentication\OAuth\OAuthSignatureMethod.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\OAuth\OAuthToken.cs">
+ <Link>Authentication\OAuth\OAuthToken.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\OAuth\OAuthTools.cs">
+ <Link>Authentication\OAuth\OAuthTools.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\OAuth\OAuthType.cs">
+ <Link>Authentication\OAuth\OAuthType.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\OAuth\OAuthWebQuery.cs">
+ <Link>Authentication\OAuth\OAuthWebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\OAuth\OAuthWebQueryInfo.cs">
+ <Link>Authentication\OAuth\OAuthWebQueryInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\OAuth\OAuthWorkflow.cs">
+ <Link>Authentication\OAuth\OAuthWorkflow.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Caching\CacheFactory.cs">
+ <Link>Caching\CacheFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Caching\CacheMode.cs">
+ <Link>Caching\CacheMode.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Caching\CacheOptions.cs">
+ <Link>Caching\CacheOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Caching\ICache.cs">
+ <Link>Caching\ICache.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Caching\SimpleCache.cs">
+ <Link>Caching\SimpleCache.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Extensions\CollectionExtensions.cs">
+ <Link>Extensions\CollectionExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Extensions\FormatExtensions.cs">
+ <Link>Extensions\FormatExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Extensions\OAuthExtensions.cs">
+ <Link>Extensions\OAuthExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Extensions\ObjectExtensions.cs">
+ <Link>Extensions\ObjectExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Extensions\ReflectionExtensions.cs">
+ <Link>Extensions\ReflectionExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Extensions\SpecificationExtensions.cs">
+ <Link>Extensions\SpecificationExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Extensions\StringExtensions.cs">
+ <Link>Extensions\StringExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Extensions\TimeExtensions.cs">
+ <Link>Extensions\TimeExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Extensions\WebExtensions.cs">
+ <Link>Extensions\WebExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\IRestClient.cs">
+ <Link>IRestClient.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Model\PropertyChangedBase.cs">
+ <Link>Model\PropertyChangedBase.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Mono\HttpUtility.cs">
+ <Link>Mono\HttpUtility.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Mono\WebHeaderCollection.cs">
+ <Link>Mono\WebHeaderCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\RestBase.cs">
+ <Link>RestBase.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\RestCallback.cs">
+ <Link>RestCallback.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\RestClient.cs">
+ <Link>RestClient.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\RestRequest.cs">
+ <Link>RestRequest.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\RestResponse.cs">
+ <Link>RestResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Retries\ConnectionClosed.cs">
+ <Link>Retries\ConnectionClosed.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Retries\IRetryCondition.cs">
+ <Link>Retries\IRetryCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Retries\IRetryCustomCondition.cs">
+ <Link>Retries\IRetryCustomCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Retries\NetworkError.cs">
+ <Link>Retries\NetworkError.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Retries\RetryCondition.cs">
+ <Link>Retries\RetryCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Retries\RetryCustomCondition.cs">
+ <Link>Retries\RetryCustomCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Retries\RetryErrorCondition.cs">
+ <Link>Retries\RetryErrorCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Retries\RetryPolicy.cs">
+ <Link>Retries\RetryPolicy.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Retries\RetryResultCondition.cs">
+ <Link>Retries\RetryResultCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Retries\Timeout.cs">
+ <Link>Retries\Timeout.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Serialization\DefaultJsonSerializer.cs">
+ <Link>Serialization\DefaultJsonSerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Serialization\HammockXmlSerializer.cs">
+ <Link>Serialization\HammockXmlSerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Serialization\IDeserializer.cs">
+ <Link>Serialization\IDeserializer.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Serialization\ISerializer.cs">
+ <Link>Serialization\ISerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Serialization\JsonParser.cs">
+ <Link>Serialization\JsonParser.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Serialization\Utf8Serializer.cs">
+ <Link>Serialization\Utf8Serializer.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Specifications\AndSpecification.cs">
+ <Link>Specifications\AndSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Specifications\CompositeSpecificationBase.cs">
+ <Link>Specifications\CompositeSpecificationBase.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Specifications\HammockSpecification.cs">
+ <Link>Specifications\HammockSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Specifications\ISpecification.cs">
+ <Link>Specifications\ISpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Specifications\NotSpecification.cs">
+ <Link>Specifications\NotSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Specifications\OrSpecification.cs">
+ <Link>Specifications\OrSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Streaming\StreamOptions.cs">
+ <Link>Streaming\StreamOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Tasks\IRateLimitingRule.cs">
+ <Link>Tasks\IRateLimitingRule.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Tasks\IRateLimitStatus.cs">
+ <Link>Tasks\IRateLimitStatus.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Tasks\ITaskOptions.cs">
+ <Link>Tasks\ITaskOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Tasks\ITaskState.cs">
+ <Link>Tasks\ITaskState.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Tasks\ITimedTask.cs">
+ <Link>Tasks\ITimedTask.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Tasks\RateLimitingRule.cs">
+ <Link>Tasks\RateLimitingRule.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Tasks\RateLimitType.cs">
+ <Link>Tasks\RateLimitType.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Tasks\TaskOptions.cs">
+ <Link>Tasks\TaskOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Tasks\TaskState.cs">
+ <Link>Tasks\TaskState.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Tasks\TimedTask.cs">
+ <Link>Tasks\TimedTask.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Validation\ValidationException.cs">
+ <Link>Validation\ValidationException.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Validation\ValidEmailSpecification.cs">
+ <Link>Validation\ValidEmailSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\BasicAuthWebQuery.cs">
+ <Link>Web\BasicAuthWebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\GetOrDelete.cs">
+ <Link>Web\GetOrDelete.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\HttpCookieParameter.cs">
+ <Link>Web\HttpCookieParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\HttpPostParameter.cs">
+ <Link>Web\HttpPostParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\HttpPostParameterType.cs">
+ <Link>Web\HttpPostParameterType.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\IWebQueryInfo.cs">
+ <Link>Web\IWebQueryInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\Mocks\IMockable.cs">
+ <Link>Web\Mocks\IMockable.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\Mocks\IWebResponse.cs">
+ <Link>Web\Mocks\IWebResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\Mocks\MockHttpWebRequest.cs">
+ <Link>Web\Mocks\MockHttpWebRequest.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\Mocks\MockHttpWebResponse.cs">
+ <Link>Web\Mocks\MockHttpWebResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\Mocks\MockWebRequestFactory.cs">
+ <Link>Web\Mocks\MockWebRequestFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\Pair.cs">
+ <Link>Web\Pair.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\PostOrPut.cs">
+ <Link>Web\PostOrPut.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\Triplet.cs">
+ <Link>Web\Triplet.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebCallback.cs">
+ <Link>Web\WebCallback.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebEntity.cs">
+ <Link>Web\WebEntity.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebHeader.cs">
+ <Link>Web\WebHeader.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebHeaderCollection.cs">
+ <Link>Web\WebHeaderCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebMethod.cs">
+ <Link>Web\WebMethod.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebPair.cs">
+ <Link>Web\WebPair.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebPairCollection.cs">
+ <Link>Web\WebPairCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebParameter.cs">
+ <Link>Web\WebParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebParameterCollection.cs">
+ <Link>Web\WebParameterCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebQuery.Async.cs">
+ <Link>Web\WebQuery.Async.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebQuery.cs">
+ <Link>Web\WebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebQueryAsyncResult.cs">
+ <Link>Web\WebQueryAsyncResult.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebQueryRequestEventArgs.cs">
+ <Link>Web\WebQueryRequestEventArgs.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebQueryResponseEventArgs.cs">
+ <Link>Web\WebQueryResponseEventArgs.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebQueryResult.cs">
+ <Link>Web\WebQueryResult.cs</Link>
+ </Compile>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="key.snk" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
\ No newline at end of file
--- /dev/null
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Security;
+
+// 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("Hammock")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apitize")]
+[assembly: AssemblyProduct("Hammock")]
+[assembly: AssemblyCopyright("Copyright © Daniel Crenna and Jason Diller")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: AllowPartiallyTrustedCallers]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("90025308-f836-49cd-865f-39e0ea20c096")]
+
+// 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 Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{3BB0DC97-ECE3-4AC8-B2D0-E4C14D600179}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Hammock.Extras</RootNamespace>
+ <AssemblyName>Hammock.Extras</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <SignAssembly>true</SignAssembly>
+ <AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>3.5</OldToolsVersion>
+ <UpgradeBackupLocation />
+ <PublishUrl>publish\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Disk</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <IsWebBootstrapper>false</IsWebBootstrapper>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\bin\lib\3.5\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;NET35</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\bin\lib\3.5\</OutputPath>
+ <DefineConstants>TRACE;NET35</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Newtonsoft.Json.Net35">
+ <HintPath>..\..\..\lib\Newtonsoft.Json.Net35.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Serialization\JsonConventionResolver.cs" />
+ <Compile Include="Serialization\JsonSerializer.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Serialization\SerializerBase.cs" />
+ <Compile Include="Serialization\XmlSerializer.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Hammock\Hammock.csproj">
+ <Project>{6679078A-C585-4CB6-96E9-908DBDAA2716}</Project>
+ <Name>Hammock %28.NET 3.5\Hammock%29</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="key.snk" />
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+ <Visible>False</Visible>
+ <ProductName>Windows Installer 3.1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
\ No newline at end of file
--- /dev/null
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 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("Hammock.Extras")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Hammock.Extras")]
+[assembly: AssemblyCopyright("Copyright © Daniel Crenna and Jason Diller")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("124ed3cb-d184-438b-be4b-38c240c929e7")]
+
+// 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 Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+using Newtonsoft.Json.Serialization;
+
+namespace Hammock.Extras.Serialization
+{
+ /// <summary>
+ /// Resolves all property names to JSON conventional standard,
+ /// i.e. JSON name "this_is_a_property" will map to the class property ThisIsAProperty.
+ /// Also finds any property names suffixed with "Attribute" and converts them
+ /// into @properties for XML serialization.
+ /// </summary>
+ public class JsonConventionResolver : DefaultContractResolver
+ {
+ public class ToStringComparer : IComparer
+ {
+ public int Compare(object x, object y)
+ {
+ return x.ToString().CompareTo(y.ToString());
+ }
+ }
+
+ protected override IList<JsonProperty> CreateProperties(Type type, Newtonsoft.Json.MemberSerialization memberSerialization)
+ {
+ var properties = base.CreateProperties(type, memberSerialization);
+
+ return CreatePropertiesImpl(properties);
+ }
+
+ private static IList<JsonProperty> CreatePropertiesImpl(IList<JsonProperty> properties)
+ {
+ foreach (var property in properties)
+ {
+ property.PropertyName = PascalCaseToElement(property.PropertyName);
+ }
+
+ // @'s must come first
+ var result = properties;
+
+ ArrayList.Adapter((IList)result).Sort(new ToStringComparer());
+
+ return result;
+ }
+
+ private static string PascalCaseToElement(string input)
+ {
+ if (string.IsNullOrEmpty(input))
+ {
+ return null;
+ }
+
+ var attributeForSerialization = input.EndsWith("Attribute");
+ if(attributeForSerialization)
+ {
+ input = input.Substring(0, input.LastIndexOf("Attribute"));
+ }
+
+ var result = new StringBuilder();
+ result.Append(char.ToLowerInvariant(input[0]));
+
+ for (var i = 1; i < input.Length; i++)
+ {
+ if (char.IsLower(input[i]))
+ {
+ result.Append(input[i]);
+ }
+ else
+ {
+ result.Append("_");
+ result.Append(char.ToLowerInvariant(input[i]));
+ }
+ }
+
+ return attributeForSerialization? string.Concat("@", result) : result.ToString();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using Hammock.Serialization;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+namespace Hammock.Extras.Serialization
+{
+ public class JsonSerializer : SerializerBase
+ {
+ public JsonSerializer()
+ {
+
+ }
+
+ public JsonSerializer(JsonSerializerSettings settings) : base(settings)
+ {
+
+ }
+
+#if NET40
+ public override dynamic DeserializeDynamic<T>(RestResponse<T> response)
+ {
+ var result = JsonParser.Deserialize(response.Content);
+ return result;
+ }
+#endif
+
+ public override T Deserialize<T>(RestResponse<T> response)
+ {
+ var token = JToken.FromObject(response.Content);
+
+ return token.Type == JTokenType.Array
+ ? DeserializeCollection<T>(token)
+ : DeserializeSingle<T>(response.Content);
+ }
+
+ private T DeserializeSingle<T>(string content)
+ {
+ var deserialized = DeserializeJson<T>(content);
+ return deserialized;
+ }
+
+ private T DeserializeCollection<T>(IEnumerable<JToken> array)
+ {
+ IList collection;
+ var type = ConstructCollection<T>(out collection);
+
+ try
+ {
+ var items = array.Select(item => item.ToString());
+ foreach (var d in items.Select(item => DeserializeJson(item, type)))
+ {
+ collection.Add(d);
+ }
+ var deserialized = (T)collection;
+ return deserialized;
+ }
+ catch (JsonReaderException) // <-- Likely unexpected content type
+ {
+ var deserialized = (T)collection;
+ return deserialized;
+ }
+ catch (Exception) // <-- Likely entity mismatch (error)
+ {
+ var deserialized = (T)collection;
+ return deserialized;
+ }
+ }
+
+ private static Type ConstructCollection<T>(out IList collection)
+ {
+ var args = typeof(T).GetGenericArguments();
+ var type = args.Length == 0 ? typeof (T) : args[0];
+ var collectionType = typeof(List<>).MakeGenericType(type);
+ collection = (IList)Activator.CreateInstance(collectionType);
+ return type;
+ }
+
+ public override object Deserialize(RestResponse response, Type type)
+ {
+ return DeserializeJson(response.Content, type);
+ }
+
+ public override string Serialize(object instance, Type type)
+ {
+ return SerializeJson(instance, type);
+ }
+
+ public override string ContentType
+ {
+ get { return "application/json"; }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+#if NET40
+using System.Dynamic;
+#endif
+using System.IO;
+using System.Xml;
+using Hammock.Serialization;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Formatting = Newtonsoft.Json.Formatting;
+
+namespace Hammock.Extras.Serialization
+{
+ public abstract class SerializerBase : Utf8Serializer, ISerializer, IDeserializer
+ {
+ private readonly Newtonsoft.Json.JsonSerializer _serializer;
+
+ protected SerializerBase()
+ : this(new JsonSerializerSettings
+ {
+ MissingMemberHandling = MissingMemberHandling.Ignore,
+ NullValueHandling = NullValueHandling.Ignore,
+ DefaultValueHandling = DefaultValueHandling.Include,
+ ContractResolver = new JsonConventionResolver()
+ })
+ {
+
+ }
+
+ protected SerializerBase(JsonSerializerSettings settings)
+ {
+ _serializer = new Newtonsoft.Json.JsonSerializer
+ {
+ ConstructorHandling = settings.ConstructorHandling,
+ ContractResolver = settings.ContractResolver,
+ ObjectCreationHandling = settings.ObjectCreationHandling,
+ MissingMemberHandling = settings.MissingMemberHandling,
+ DefaultValueHandling = settings.DefaultValueHandling,
+ NullValueHandling = settings.NullValueHandling
+ };
+
+ foreach (var converter in settings.Converters)
+ {
+ _serializer.Converters.Add(converter);
+ }
+ }
+
+ public abstract T Deserialize<T>(RestResponse<T> response);
+
+ public abstract object Deserialize(RestResponse response, Type type);
+
+#if NET40
+ public abstract dynamic DeserializeDynamic<T>(RestResponse<T> response) where T : DynamicObject;
+#endif
+
+ public virtual object DeserializeJson(string content, Type type)
+ {
+ using (var stringReader = new StringReader(content))
+ {
+ using (var jsonTextReader = new JsonTextReader(stringReader))
+ {
+ return _serializer.Deserialize(jsonTextReader, type);
+ }
+ }
+ }
+
+ public virtual T DeserializeJson<T>(string content)
+ {
+ using (var stringReader = new StringReader(content))
+ {
+ using (var jsonTextReader = new JsonTextReader(stringReader))
+ {
+ return _serializer.Deserialize<T>(jsonTextReader);
+ }
+ }
+ }
+
+ public virtual T DeserializeXml<T>(RestResponse response)
+ {
+ return (T)DeserializeXml(response, typeof(T));
+ }
+
+ public virtual object DeserializeXml(RestResponse response, Type type)
+ {
+ var element = LoadXmlElement(response.Content);
+
+ return DeserializeXmlImpl(element, type);
+ }
+
+ private object DeserializeXmlImpl(XmlNode node, Type type)
+ {
+ var json = JsonConvert.SerializeXmlNode(node);
+ var instance = DeserializeJson(json, type);
+ return instance;
+ }
+
+ private static XmlElement LoadXmlElement(string content)
+ {
+ var document = new XmlDocument();
+ document.Load(new StringReader(content));
+ return document.DocumentElement;
+ }
+
+ public virtual object DeserializeXmlWithRoot(string content, Type type, string root)
+ {
+ var source = LoadXmlElement(content);
+ var inner = source.FirstChild;
+
+ var document = new XmlDocument();
+ var outer = document.CreateNode(XmlNodeType.Element, root, source.NamespaceURI);
+ inner = document.ImportNode(inner, true);
+
+ foreach(XmlAttribute attribute in source.Attributes)
+ {
+ var attributeCopy = document.CreateAttribute(attribute.Name, attribute.LocalName, attribute.NamespaceURI);
+ attributeCopy.Value = attribute.Value;
+ if (outer.Attributes != null)
+ {
+ outer.Attributes.Append(attributeCopy);
+ }
+ }
+
+ outer.AppendChild(inner);
+ document.AppendChild(outer);
+
+ var json = JsonConvert.SerializeXmlNode(document);
+ var relevant = JObject.Parse(json)[root].ToString();
+ var instance = DeserializeJson(relevant, type);
+
+ return instance;
+ }
+
+ public virtual string SerializeJson(object instance, Type type)
+ {
+ using (var stringWriter = new StringWriter())
+ {
+ using (var jsonTextWriter = new JsonTextWriter(stringWriter))
+ {
+ jsonTextWriter.Formatting = Formatting.Indented;
+ jsonTextWriter.QuoteChar = '"';
+
+ _serializer.Serialize(jsonTextWriter, instance);
+
+ var result = stringWriter.ToString();
+ return result;
+ }
+ }
+ }
+
+ public virtual string SerializeXml(object instance, Type type)
+ {
+ var json = SerializeJson(instance, type);
+
+ var root = type.Name.ToLowerInvariant();
+
+ return SerializeXmlImpl(instance, type, json, root);
+ }
+
+ public virtual string SerializeXmlWithRoot(object instance, Type type, string root)
+ {
+ var json = SerializeJson(instance, type);
+
+ return SerializeXmlImpl(instance, type, json, root);
+ }
+
+ public virtual string SerializeXmlImpl(object instance, Type type, string json, string root)
+ {
+ // {"root":json }
+ json = string.Format("{{\"{0}\":{1} }}", root, json);
+
+ var document = JsonConvert.DeserializeXmlNode(json);
+
+ using (var stringWriter = new StringWriter())
+ {
+ using (var xmlTextWriter = new XmlTextWriter(stringWriter))
+ {
+ document.WriteTo(xmlTextWriter);
+
+ return stringWriter.ToString();
+ }
+ }
+ }
+
+ public abstract string Serialize(object instance, Type type);
+
+ public abstract string ContentType { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Hammock.Extras.Serialization
+{
+ public class XmlSerializer : SerializerBase
+ {
+ public override T Deserialize<T>(RestResponse<T> response)
+ {
+ var root = typeof (T).Name.ToLowerInvariant();
+
+ return (T)DeserializeXmlWithRoot(response.Content, typeof(T), root);
+ }
+
+#if NET40
+ public override dynamic DeserializeDynamic<T>(RestResponse<T> response)
+ {
+ var root = typeof(T).Name.ToLowerInvariant();
+
+ return DeserializeXmlWithRoot(response.Content, typeof(T), root);
+ }
+#endif
+
+ public override object Deserialize(RestResponse response, Type type)
+ {
+ var root = type.Name.ToLowerInvariant();
+
+ return DeserializeXmlWithRoot(response.Content, type, root);
+ }
+
+ public override string Serialize(object instance, Type type)
+ {
+ var root = type.Name.ToLowerInvariant();
+
+ return SerializeXmlWithRoot(instance, type, root);
+ }
+
+ public override string ContentType
+ {
+ get { return "text/xml"; }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+
+namespace Hammock.Silverlight.Caching
+{
+ public class IsolatedStorageCache
+ {
+
+ }
+}
--- /dev/null
+using System;
+
+namespace Hammock.Silverlight.Compat
+{
+ [Flags]
+ public enum DecompressionMethods
+ {
+ Deflate = 2,
+ GZip = 4,
+ None = 6
+ }
+}
--- /dev/null
+using System;
+using System.IO;
+using System.Net;
+using System.Text;
+using ICSharpCode.SharpZipLib.Silverlight.GZip;
+using ICSharpCode.SharpZipLib.Silverlight.Zip;
+
+namespace Hammock.Silverlight.Compat
+{
+ public class GzipHttpWebResponse : HttpWebResponse
+ {
+ private const int ChunkSize = 2048;
+
+ private readonly HttpWebResponse _response;
+
+ public override string Method
+ {
+ get { return _response.Method; }
+ }
+
+ public override HttpStatusCode StatusCode
+ {
+ get { return _response.StatusCode; }
+ }
+
+ public override string StatusDescription
+ {
+ get { return _response.StatusDescription; }
+ }
+
+ public GzipHttpWebResponse(HttpWebResponse response)
+ {
+ _response = response;
+ }
+
+ public override void Close()
+ {
+ _response.Close();
+ }
+
+ public override Stream GetResponseStream()
+ {
+ Stream compressed = null;
+
+ var responseStream = _response.GetResponseStream();
+
+#if !WindowsPhone
+ var contentEncoding = _response.Headers["Content-Encoding"];
+ if (contentEncoding != null && contentEncoding.Contains("gzip"))
+ {
+ compressed = new GZipInputStream(responseStream);
+ }
+ else if (contentEncoding != null && contentEncoding.Contains("deflate"))
+ {
+ compressed = new ZipInputStream(responseStream);
+ }
+#else
+ byte[] marker;
+ responseStream = ReadIntoMemoryStream(responseStream, out marker);
+ if (marker.Length > 2 && (marker[0] == 31 && marker[1] == 139))
+ {
+ compressed = new GZipInputStream(responseStream);
+ }
+#endif
+ if (compressed != null)
+ {
+ var decompressed = new MemoryStream();
+ var size = ChunkSize;
+ var buffer = new byte[ChunkSize];
+ while (true)
+ {
+ size = compressed.Read(buffer, 0, size);
+ if (size > 0)
+ {
+ decompressed.Write(buffer, 0, size);
+ }
+ else
+ {
+ break;
+ }
+ }
+ decompressed.Seek(0, SeekOrigin.Begin);
+ return decompressed;
+ }
+
+ return responseStream;
+ }
+
+ // [DC]: We have to read the entire stream in as HTTP response streams are read-once
+ private static MemoryStream ReadIntoMemoryStream(Stream stream, out byte[] marker)
+ {
+ var buffer = new byte[8192];
+ var ms = new MemoryStream();
+
+ int read;
+ while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
+ {
+ ms.Write(buffer, 0, read);
+ }
+
+ ms.Position = 0;
+ marker = new byte[2];
+ ms.Read(marker, 0, 2);
+ ms.Position = 0;
+
+ return ms;
+ }
+
+ public override long ContentLength
+ {
+ get { return _response.ContentLength; }
+ }
+
+ public override string ContentType
+ {
+ get { return _response.ContentType; }
+ }
+
+ public override WebHeaderCollection Headers
+ {
+ get { return _response.Headers; }
+ }
+
+ public override System.Uri ResponseUri
+ {
+ get { return _response.ResponseUri; }
+ }
+ }
+}
--- /dev/null
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Hammock.Silverlight.Compat
+{
+ public class NameValueCollection : List<KeyValuePair<string, string>>
+ {
+ public new string this[int index]
+ {
+ get
+ {
+ return base[index].Value;
+ }
+ }
+
+ public string this[string name]
+ {
+ get
+ {
+ return this.SingleOrDefault(kv => kv.Key.Equals(name)).Value;
+ }
+ }
+
+ public NameValueCollection()
+ {
+
+ }
+
+ public NameValueCollection(int capacity) : base(capacity)
+ {
+
+ }
+
+ public void Add(string name, string value)
+ {
+ List<KeyValuePair<string, string>> list = this;
+ for (int i = Count - 1; i >= 0; --i)
+ {
+ if (string.Equals(list[i].Key, name))
+ {
+ list[i] = new KeyValuePair<string, string>(name, list[i].Value + "," + value);
+ return;
+ }
+ }
+ Add(new KeyValuePair<string, string>(name, value));
+ }
+
+ public IEnumerable<string> AllKeys
+ {
+ get
+ {
+ return this.Select(pair => pair.Key);
+ }
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Diagnostics;
+using System.Text;
+
+namespace Hammock.Silverlight.Compat
+{
+ public class Trace
+ {
+ public static bool Enabled { get; set; }
+
+ static Trace()
+ {
+ Enabled = true;
+ }
+
+ public static void WriteLine(string message)
+ {
+ if (!Enabled)
+ {
+ return;
+ }
+
+ Debug.WriteLine(message);
+ }
+
+ public static void WriteLineIf(bool condition, string message)
+ {
+ if (!Enabled)
+ {
+ return;
+ }
+
+ if(condition)
+ {
+ Debug.WriteLine(message);
+ }
+ }
+
+ public static void WriteLine(string message, params object[] args)
+ {
+ if (!Enabled)
+ {
+ return;
+ }
+
+ Debug.WriteLine(message, args);
+ }
+
+ public static void WriteLine(StringBuilder sb)
+ {
+ if (!Enabled)
+ {
+ return;
+ }
+
+ Debug.WriteLine(sb.ToString());
+ }
+ }
+}
+
+
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Condition="'$(MSBuildToolsVersion)' == '3.5'">
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ </PropertyGroup>
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{E0461346-CB62-489E-9893-CFEA249F8380}</ProjectGuid>
+ <ProjectTypeGuids>{A1591282-1198-4647-A2B1-27E5FF5F6F3B};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Hammock.Silverlight</RootNamespace>
+ <AssemblyName>Hammock.Silverlight</AssemblyName>
+ <TargetFrameworkVersion>v3.0</TargetFrameworkVersion>
+ <SilverlightApplication>false</SilverlightApplication>
+ <ValidateXaml>true</ValidateXaml>
+ <ThrowErrorsInValidation>true</ThrowErrorsInValidation>
+ <SignAssembly>true</SignAssembly>
+ <AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
+ <TargetFrameworkIdentifier>Silverlight</TargetFrameworkIdentifier>
+ <SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>3.5</OldToolsVersion>
+ <UpgradeBackupLocation />
+ <PublishUrl>publish\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Disk</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <IsWebBootstrapper>false</IsWebBootstrapper>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\bin\lib\SL3\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;SILVERLIGHT,Silverlight,SL,SL3</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\bin\lib\sl3\</OutputPath>
+ <DefineConstants>TRACE;SILVERLIGHT,Silverlight,SL,SL3</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Mono|AnyCPU' ">
+ <OutputPath>..\..\..\bin\mono\</OutputPath>
+ <DefineConstants>TRACE;SILVERLIGHT,Silverlight,SL</DefineConstants>
+ <Optimize>true</Optimize>
+ <NoStdLib>true</NoStdLib>
+ <DebugType>pdbonly</DebugType>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+ <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+ <ErrorReport>prompt</ErrorReport>
+ <NoConfig>true</NoConfig>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System.Runtime.Serialization" />
+ <Reference Include="System.Runtime.Serialization.Json, Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
+ <Reference Include="System.ServiceModel.Web" />
+ <Reference Include="System.Windows" />
+ <Reference Include="mscorlib" />
+ <Reference Include="system" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml" />
+ <Reference Include="System.Net" />
+ <Reference Include="System.Windows.Browser" />
+ <Reference Include="System.Xml.Linq, Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\Hammock\Attributes\INamedAttribute.cs">
+ <Link>Attributes\INamedAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Attributes\IValidatingAttribute.cs">
+ <Link>Attributes\IValidatingAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Attributes\Specialized\EntityAttribute.cs">
+ <Link>Attributes\Specialized\EntityAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Attributes\Specialized\HeaderAttribute.cs">
+ <Link>Attributes\Specialized\HeaderAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Attributes\Specialized\ParameterAttribute.cs">
+ <Link>Attributes\Specialized\ParameterAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Attributes\Specialized\UserAgentAttribute.cs">
+ <Link>Attributes\Specialized\UserAgentAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Attributes\Validation\BooleanToIntegerAttribute.cs">
+ <Link>Attributes\Validation\BooleanToIntegerAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Attributes\Validation\DateTimeFormatAttribute.cs">
+ <Link>Attributes\Validation\DateTimeFormatAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Attributes\Validation\RequiredAttribute.cs">
+ <Link>Attributes\Validation\RequiredAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Attributes\Validation\SpecificationAttribute.cs">
+ <Link>Attributes\Validation\SpecificationAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Attributes\Validation\ValidationAttribute.cs">
+ <Link>Attributes\Validation\ValidationAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\Basic\BasicAuthCredentials.cs">
+ <Link>Authentication\Basic\BasicAuthCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\IWebCredentials.cs">
+ <Link>Authentication\IWebCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\OAuth\OAuthCredentials.cs">
+ <Link>Authentication\OAuth\OAuthCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\OAuth\OAuthParameterHandling.cs">
+ <Link>Authentication\OAuth\OAuthParameterHandling.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\OAuth\OAuthSignatureMethod.cs">
+ <Link>Authentication\OAuth\OAuthSignatureMethod.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\OAuth\OAuthToken.cs">
+ <Link>Authentication\OAuth\OAuthToken.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\OAuth\OAuthTools.cs">
+ <Link>Authentication\OAuth\OAuthTools.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\OAuth\OAuthType.cs">
+ <Link>Authentication\OAuth\OAuthType.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\OAuth\OAuthWebQuery.cs">
+ <Link>Authentication\OAuth\OAuthWebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\OAuth\OAuthWebQueryInfo.cs">
+ <Link>Authentication\OAuth\OAuthWebQueryInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Authentication\OAuth\OAuthWorkflow.cs">
+ <Link>Authentication\OAuth\OAuthWorkflow.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Caching\CacheFactory.cs">
+ <Link>Caching\CacheFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Caching\CacheMode.cs">
+ <Link>Caching\CacheMode.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Caching\CacheOptions.cs">
+ <Link>Caching\CacheOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Caching\ICache.cs">
+ <Link>Caching\ICache.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Caching\SimpleCache.cs">
+ <Link>Caching\SimpleCache.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Extensions\CollectionExtensions.cs">
+ <Link>Extensions\CollectionExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Extensions\FormatExtensions.cs">
+ <Link>Extensions\FormatExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Extensions\OAuthExtensions.cs">
+ <Link>Extensions\OAuthExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Extensions\ObjectExtensions.cs">
+ <Link>Extensions\ObjectExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Extensions\ReflectionExtensions.cs">
+ <Link>Extensions\ReflectionExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Extensions\SpecificationExtensions.cs">
+ <Link>Extensions\SpecificationExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Extensions\StringExtensions.cs">
+ <Link>Extensions\StringExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Extensions\TimeExtensions.cs">
+ <Link>Extensions\TimeExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Extensions\WebExtensions.cs">
+ <Link>Extensions\WebExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\IRestClient.cs">
+ <Link>IRestClient.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Model\PropertyChangedBase.cs">
+ <Link>Model\PropertyChangedBase.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\RestBase.cs">
+ <Link>RestBase.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\RestCallback.cs">
+ <Link>RestCallback.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\RestClient.cs">
+ <Link>RestClient.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\RestRequest.cs">
+ <Link>RestRequest.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\RestResponse.cs">
+ <Link>RestResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Retries\IRetryCondition.cs">
+ <Link>Retries\IRetryCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Retries\IRetryCustomCondition.cs">
+ <Link>Retries\IRetryCustomCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Retries\NetworkError.cs">
+ <Link>Retries\NetworkError.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Retries\RetryCustomCondition.cs">
+ <Link>Retries\RetryCustomCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Retries\RetryErrorCondition.cs">
+ <Link>Retries\RetryErrorCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Retries\RetryPolicy.cs">
+ <Link>Retries\RetryPolicy.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Retries\RetryResultCondition.cs">
+ <Link>Retries\RetryResultCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Serialization\HammockDataContractJsonSerializer.cs">
+ <Link>Serialization\HammockDataContractJsonSerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Serialization\HammockDataContractSerializer.cs">
+ <Link>Serialization\HammockDataContractSerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Serialization\IDeserializer.cs">
+ <Link>Serialization\IDeserializer.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Serialization\ISerializer.cs">
+ <Link>Serialization\ISerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Serialization\Utf8Serializer.cs">
+ <Link>Serialization\Utf8Serializer.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Specifications\AndSpecification.cs">
+ <Link>Specifications\AndSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Specifications\CompositeSpecificationBase.cs">
+ <Link>Specifications\CompositeSpecificationBase.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Specifications\HammockSpecification.cs">
+ <Link>Specifications\HammockSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Specifications\ISpecification.cs">
+ <Link>Specifications\ISpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Specifications\NotSpecification.cs">
+ <Link>Specifications\NotSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Specifications\OrSpecification.cs">
+ <Link>Specifications\OrSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Streaming\StreamOptions.cs">
+ <Link>Streaming\StreamOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Tasks\IRateLimitingRule.cs">
+ <Link>Tasks\IRateLimitingRule.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Tasks\IRateLimitStatus.cs">
+ <Link>Tasks\IRateLimitStatus.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Tasks\ITaskOptions.cs">
+ <Link>Tasks\ITaskOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Tasks\ITaskState.cs">
+ <Link>Tasks\ITaskState.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Tasks\ITimedTask.cs">
+ <Link>Tasks\ITimedTask.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Tasks\RateLimitingRule.cs">
+ <Link>Tasks\RateLimitingRule.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Tasks\RateLimitType.cs">
+ <Link>Tasks\RateLimitType.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Tasks\TaskOptions.cs">
+ <Link>Tasks\TaskOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Tasks\TaskState.cs">
+ <Link>Tasks\TaskState.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Tasks\TimedTask.cs">
+ <Link>Tasks\TimedTask.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Validation\ValidationException.cs">
+ <Link>Validation\ValidationException.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\BasicAuthWebQuery.cs">
+ <Link>Web\BasicAuthWebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\GetOrDelete.cs">
+ <Link>Web\GetOrDelete.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\HttpCookieParameter.cs">
+ <Link>Web\HttpCookieParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\HttpPostParameter.cs">
+ <Link>Web\HttpPostParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\HttpPostParameterType.cs">
+ <Link>Web\HttpPostParameterType.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\IWebQueryInfo.cs">
+ <Link>Web\IWebQueryInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\Mocks\IMockable.cs">
+ <Link>Web\Mocks\IMockable.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\Mocks\MockHttpWebRequest.cs">
+ <Link>Web\Mocks\MockHttpWebRequest.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\Mocks\MockHttpWebResponse.cs">
+ <Link>Web\Mocks\MockHttpWebResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\Mocks\MockWebRequestFactory.cs">
+ <Link>Web\Mocks\MockWebRequestFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\Pair.cs">
+ <Link>Web\Pair.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\PostOrPut.cs">
+ <Link>Web\PostOrPut.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\Triplet.cs">
+ <Link>Web\Triplet.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebCallback.cs">
+ <Link>Web\WebCallback.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebEntity.cs">
+ <Link>Web\WebEntity.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebHeader.cs">
+ <Link>Web\WebHeader.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebHeaderCollection.cs">
+ <Link>Web\WebHeaderCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebMethod.cs">
+ <Link>Web\WebMethod.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebPair.cs">
+ <Link>Web\WebPair.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebPairCollection.cs">
+ <Link>Web\WebPairCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebParameter.cs">
+ <Link>Web\WebParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebParameterCollection.cs">
+ <Link>Web\WebParameterCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebQuery.Async.cs">
+ <Link>Web\WebQuery.Async.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebQuery.cs">
+ <Link>Web\WebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebQueryAsyncResult.cs">
+ <Link>Web\WebQueryAsyncResult.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebQueryRequestEventArgs.cs">
+ <Link>Web\WebQueryRequestEventArgs.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebQueryResponseEventArgs.cs">
+ <Link>Web\WebQueryResponseEventArgs.cs</Link>
+ </Compile>
+ <Compile Include="..\Hammock\Web\WebQueryResult.cs">
+ <Link>Web\WebQueryResult.cs</Link>
+ </Compile>
+ <Compile Include="Caching\IsolatedStorageCache.cs" />
+ <Compile Include="Compat\DecompressionMethods.cs" />
+ <Compile Include="Compat\GzipHttpWebResponse.cs" />
+ <Compile Include="Compat\NameValueCollection.cs" />
+ <Compile Include="Compat\Trace.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="key.snk" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\ICSharpCode.SharpZipLib.Silverlight\ICSharpCode.SharpZipLib.Silverlight.csproj">
+ <Project>{2E420750-6124-473B-808D-41755C907648}</Project>
+ <Name>ICSharpCode.SharpZipLib.Silverlight %28.NET 3.5\SharpZipLib\ICSharpCode.SharpZipLib.Silverlight%29</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+ <Visible>False</Visible>
+ <ProductName>Windows Installer 3.1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\$(SilverlightVersion)\Microsoft.Silverlight.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+ <ProjectExtensions>
+ <VisualStudio>
+ <FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
+ <SilverlightProjectProperties />
+ </FlavorProperties>
+ </VisualStudio>
+ </ProjectExtensions>
+</Project>
\ No newline at end of file
--- /dev/null
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 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("Hammock.Silverlight")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Hammock.Silverlight")]
+[assembly: AssemblyCopyright("Copyright © Daniel Crenna and Jason Diller")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("e8d5be03-7069-4869-90d4-2e10d975991d")]
+
+// 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.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null
+using Hammock.Attributes.Specialized;
+using Hammock.Attributes.Validation;
+using Hammock.Web;
+using NUnit.Framework;
+
+namespace Hammock.Tests.Attributes.Validation
+{
+ [TestFixture]
+ public class BooleanToIntegerTests
+ {
+ public class BooleanToIntegerInfo : IWebQueryInfo
+ {
+ [BooleanToInteger]
+ [Parameter("Result")]
+ public bool IShouldBeANumber { get; set; }
+ }
+
+ [Test]
+ public void Can_use_boolean_to_integer_validation_to_transform_parameter_value()
+ {
+ var info = new BooleanToIntegerInfo {IShouldBeANumber = false};
+
+ var client = new RestClient
+ {
+ Authority = "http://nowhere.com",
+ Info = info
+ };
+
+ var request = new RestRequest
+ {
+ Path = "fast"
+ };
+
+ client.Request(request);
+ }
+ }
+}
--- /dev/null
+using System;
+using Hammock.Attributes.Specialized;
+using Hammock.Attributes.Validation;
+using Hammock.Web;
+using NUnit.Framework;
+
+namespace Hammock.Tests.Attributes.Validation
+{
+ [TestFixture]
+ public class DateTimeFormatTests
+ {
+ public class DateTimeFormatInfo : IWebQueryInfo
+ {
+ [DateTimeFormat("mmm-DD-yyyy")]
+ [Header("Anniversary")]
+ public DateTime IAmADate { get; set; }
+ }
+
+ [Test]
+ public void Can_use_date_time_validation_to_transform_header_value()
+ {
+ var info = new DateTimeFormatInfo {IAmADate = DateTime.Now };
+
+ var client = new RestClient
+ {
+ Authority = "http://nowhere.com",
+ Info = info
+ };
+
+ var request = new RestRequest
+ {
+ Path = "fast"
+ };
+
+ client.Request(request);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using Hammock.Attributes.Specialized;
+using Hammock.Attributes.Validation;
+using Hammock.Validation;
+using Hammock.Web;
+using NUnit.Framework;
+
+namespace Hammock.Tests.Attributes.Validation
+{
+ [TestFixture]
+ public class RequiredAttributeTests
+ {
+ public class RequiredInfo : IWebQueryInfo
+ {
+ [Required]
+ [Header("Result")]
+ public string ICantBeNull { get; set; }
+ }
+
+ [Test]
+ [ExpectedException(typeof(ValidationException))]
+ public void Can_use_required_validation_to_block_null_value()
+ {
+ var info = new RequiredInfo { ICantBeNull = null };
+
+ var client = new RestClient
+ {
+ Authority = "http://nowhere.com",
+ Info = info
+ };
+
+ var request = new RestRequest
+ {
+ Path = "fast"
+ };
+
+ client.Request(request);
+ }
+ }
+
+}
--- /dev/null
+using System;
+using Hammock.Attributes.Specialized;
+using Hammock.Attributes.Validation;
+using Hammock.Specifications;
+using Hammock.Validation;
+using Hammock.Web;
+using NUnit.Framework;
+
+namespace Hammock.Tests.Attributes.Validation
+{
+ [TestFixture]
+ public class SpecificationAttributeTests
+ {
+ public class DateTimeFormatInfo : IWebQueryInfo
+ {
+ [Specification(typeof(ValidEmailSpecification))]
+ [Parameter("Contact")]
+ public string Email { get; set; }
+ }
+
+ [Test]
+ [ExpectedException(typeof(ValidationException))]
+ public void Can_use_specification_validation_to_block_request()
+ {
+ var info = new DateTimeFormatInfo { Email = "nowhere" };
+
+ var client = new RestClient
+ {
+ Authority = "http://nowhere.com",
+ Info = info
+ };
+
+ var request = new RestRequest
+ {
+ Path = "fast"
+ };
+
+ client.Request(request);
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{960E427F-67E0-42A5-86ED-FC6A342CDCB2}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Hammock.Tests</RootNamespace>
+ <AssemblyName>Hammock.Tests</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <SignAssembly>true</SignAssembly>
+ <AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>3.5</OldToolsVersion>
+ <UpgradeBackupLocation />
+ <PublishUrl>publish\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Disk</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <IsWebBootstrapper>false</IsWebBootstrapper>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Mono|AnyCPU' ">
+ <OutputPath>bin\Mono\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <Optimize>true</Optimize>
+ <DebugType>pdbonly</DebugType>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+ <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Newtonsoft.Json, Version=3.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\..\..\lib\Newtonsoft.Json.dll</HintPath>
+ </Reference>
+ <Reference Include="Newtonsoft.Json.Net35">
+ <HintPath>..\..\..\lib\Newtonsoft.Json.Net35.dll</HintPath>
+ </Reference>
+ <Reference Include="nunit.framework, Version=2.5.1.9189, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\..\..\lib\nunit.framework.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.configuration" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Web" />
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Helpers\TimeExtensions.cs" />
+ <Compile Include="Postmark\Converters\NameValueCollectionConverter.cs" />
+ <Compile Include="Postmark\Converters\UnicodeJsonStringConverter.cs" />
+ <Compile Include="Helpers\TestExtensions.cs" />
+ <Compile Include="OAuth\OAuthToolsTests.cs" />
+ <Compile Include="Postmark\PostmarkMessage.cs" />
+ <Compile Include="Postmark\PostmarkResponse.cs" />
+ <Compile Include="Postmark\PostmarkStatus.cs" />
+ <Compile Include="RestClientTests.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Hammock\Hammock.csproj">
+ <Project>{6679078A-C585-4CB6-96E9-908DBDAA2716}</Project>
+ <Name>Hammock %28.NET 3.5\Hammock%29</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="app.config.example" />
+ <None Include="app.config" />
+ <None Include="key.snk" />
+ <Compile Include="Attributes\Validation\BooleanToIntegerTests.cs" />
+ <Compile Include="Attributes\Validation\DateTimeFormatTests.cs" />
+ <Compile Include="Attributes\Validation\RequiredAttributeTests.cs" />
+ <Compile Include="Attributes\Validation\SpecificationAttributeTests.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="_failwhale.jpg">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="_profile.jpg">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ </ItemGroup>
+ <ItemGroup>
+ <Folder Include="Attributes\Specialized\" />
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+ <Visible>False</Visible>
+ <ProductName>Windows Installer 3.1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
\ No newline at end of file
--- /dev/null
+using System;
+using System.IO;
+using System.Text;
+using System.Xml.Serialization;
+using NUnit.Framework;
+
+namespace RestCore.Tests.Helpers
+{
+ public static class TestExtensions
+ {
+#if !Smartphone
+ public static string GetDescription(this Enum value)
+ {
+ var field = value.GetType().GetField(value.ToString());
+ var attributes = (DescriptionAttribute[]) field.GetCustomAttributes(typeof (DescriptionAttribute), false);
+
+ return (attributes.Length > 0) ? attributes[0].Description : value.ToString();
+ }
+#endif
+
+ public static string ToXml<T>(this T instance)
+ {
+ var type = typeof (T);
+#if !Smartphone
+ if (!type.IsSerializable)
+ {
+ return String.Empty;
+ }
+#endif
+
+ var sb = new StringBuilder();
+ var serializer = new XmlSerializer(type);
+
+ using (var writer = new StringWriter(sb))
+ {
+ serializer.Serialize(writer, instance);
+ }
+
+ return sb.ToString();
+ }
+
+ public static T FromXml<T>(this string xml)
+ {
+ T type;
+
+ var serializer = new XmlSerializer(typeof (T));
+
+ using (var reader = new StringReader(xml))
+ {
+ type = (T) serializer.Deserialize(reader);
+ reader.Close();
+ }
+
+ return type;
+ }
+
+ public static Uri AsUri(this string url)
+ {
+ return new Uri(url);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Hammock.Tests.Helpers
+{
+ internal static class TimeExtensions
+ {
+ public static TimeSpan Hours(this int hours)
+ {
+ return new TimeSpan(0, hours, 0, 0);
+ }
+
+ public static TimeSpan Minutes(this int minutes)
+ {
+ return new TimeSpan(0, 0, minutes, 0);
+ }
+
+ public static TimeSpan Seconds(this int seconds)
+ {
+ return new TimeSpan(0, 0, 0, seconds);
+ }
+
+ public static TimeSpan Milliseconds(this int milliseconds)
+ {
+ return new TimeSpan(0, 0, 0, 0, milliseconds);
+ }
+
+ public static DateTime Ago(this TimeSpan value)
+ {
+ return DateTime.UtcNow.Add(value.Negate());
+ }
+
+ public static DateTime FromNow(this TimeSpan value)
+ {
+ return new DateTime((DateTime.Now + value).Ticks);
+ }
+
+ public static DateTime FromUnixTime(this long seconds)
+ {
+ var time = new DateTime(1970, 1, 1);
+ time = time.AddSeconds(seconds);
+
+ return time.ToLocalTime();
+ }
+
+ public static long ToUnixTime(this DateTime dateTime)
+ {
+ var timeSpan = (dateTime - new DateTime(1970, 1, 1));
+ var timestamp = (long)timeSpan.TotalSeconds;
+
+ return timestamp;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using Hammock.Authentication.OAuth;
+using Hammock.Web;
+using RestCore.Tests.Helpers;
+using NUnit.Framework;
+
+namespace Hammock.Tests.OAuth
+{
+ [TestFixture]
+ public class OAuthToolsTests
+ {
+ [Test]
+ public void Can_construct_http_request_url()
+ {
+ const string expected = "http://example.com/resource";
+ var input = "HTTP://Example.com:80/resource?id=123".AsUri();
+ var actual = OAuthTools.ConstructRequestUrl(input);
+
+ Assert.AreEqual(expected, actual);
+ Console.WriteLine(actual);
+ }
+
+ [Test]
+ public void Can_construct_https_request_url()
+ {
+ const string expected = "https://example.com/resource";
+ var input = "HTTPS://Example.com:443/resource?id=123".AsUri();
+ var actual = OAuthTools.ConstructRequestUrl(input);
+
+ Assert.AreEqual(expected, actual);
+ Console.WriteLine(actual);
+ }
+
+ [Test]
+ public void Can_construct_non_standard_port_http_request_url()
+ {
+ const string expected = "http://example.com:8080/resource";
+ var input = "HTTP://Example.com:8080/resource?id=123".AsUri();
+ var actual = OAuthTools.ConstructRequestUrl(input);
+
+ Assert.AreEqual(expected, actual);
+ Console.WriteLine(actual);
+ }
+
+ [Test]
+ public void Can_construct_non_standard_port_https_request_url()
+ {
+ const string expected = "https://example.com:8080/resource";
+ var input = "HTTPS://Example.com:8080/resource?id=123".AsUri();
+ var actual = OAuthTools.ConstructRequestUrl(input);
+
+ Assert.AreEqual(expected, actual);
+ Console.WriteLine(actual);
+ }
+
+ [Test]
+ public void Can_generate_nonce()
+ {
+ var nonce = OAuthTools.GetNonce();
+
+ Assert.IsNotNull(nonce);
+ Assert.IsTrue(nonce.Length == 16);
+ Console.WriteLine(nonce);
+
+ var next = OAuthTools.GetNonce();
+
+ Assert.AreNotEqual(nonce, next);
+ Console.WriteLine(next);
+ }
+
+ [Test]
+ public void Can_generate_timestamp()
+ {
+ var timestamp = OAuthTools.GetTimestamp();
+ Assert.IsNotNull(timestamp);
+ Assert.IsTrue(timestamp.Length == 10, "What century is this?");
+ Console.WriteLine(timestamp);
+ }
+
+ [Test]
+ public void Can_guarantee_random_nonces_in_succession()
+ {
+ var nonces = new List<string>();
+ for (var i = 0; i < 10000; i++)
+ {
+ var nonce = OAuthTools.GetNonce();
+ var timestamp = DateTime.Now;
+
+ Console.WriteLine(nonce + ":" + timestamp);
+
+ if (nonces.Contains(nonce))
+ {
+ Assert.Fail("non-unique nonce seed generated");
+ }
+ else
+ {
+ nonces.Add(nonce);
+ }
+ }
+ }
+#if !Smartphone
+ [Test]
+ public void Can_guarantee_random_nonces_in_succession_multithreaded()
+ {
+ const int threads = 16;
+ const int totalNonces = 30000;
+ const int noncesPerThread = totalNonces / threads;
+ var nonces = new List<string>();
+ var noncesLock = new object();
+ var dupes = new List<string>();
+ var dupesLock = new object();
+ var sem = new Semaphore(0, threads);
+ var ts = new ThreadStart(() =>
+ {
+ sem.WaitOne();
+ try
+ {
+ var localNonces = new List<string>();
+ for (var i = 0; i < noncesPerThread; i++)
+ {
+ var nonce = OAuthTools.GetNonce();
+ localNonces.Add(nonce);
+ }
+ lock (nonces)
+ {
+ var localDupes = from s in nonces
+ where localNonces.Contains(s)
+ select s;
+ if (localDupes.Any())
+ {
+ lock(dupesLock)
+ {
+ dupes.AddRange(localDupes);
+ }
+ }
+ nonces.AddRange(localNonces.Except(localDupes));
+ }
+ }
+ finally
+ {
+ sem.Release();
+ }
+ });
+ var workerThreads = new Thread[threads];
+ for (var i = 0; i < threads; i++)
+ {
+ workerThreads[i] = new Thread(ts) { IsBackground = false, Name = "thread" + i };
+ workerThreads[i].Start();
+ }
+
+ sem.Release(threads);
+ foreach (var t in workerThreads)
+ {
+ t.Join();
+ }
+ Assert.IsEmpty(dupes, "Found {0} duplicated nonces generated during test", dupes.Count);
+ lock (noncesLock)
+ {
+ Assert.AreEqual(totalNonces, nonces.Count);
+ }
+ }
+#endif
+
+ [Test]
+ public void Can_sort_and_normalize_parameters()
+ {
+ var input = new WebParameterCollection
+ {
+ {"a", "1"},
+ {"f", "50"},
+ {"f", "25"},
+ {"z", "t"},
+ {"f", "a"},
+ {"c", "hi there"},
+ {"z", "p"},
+ };
+
+ const string expected = "a=1&c=hi%20there&f=25&f=50&f=a&z=p&z=t";
+ var actual = OAuthTools.NormalizeRequestParameters(input);
+ Console.WriteLine(actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ public void Can_sort_and_normalize_parameters_excluding_signature()
+ {
+ var input = new WebParameterCollection
+ {
+ {"a", "1"},
+ {"f", "50"},
+ {"f", "25"},
+ {"z", "t"},
+ {"oauth_signature", "signature"},
+ {"f", "a"},
+ {"c", "hi there"},
+ {"z", "p"},
+ };
+
+ const string expected = "a=1&c=hi%20there&f=25&f=50&f=a&z=p&z=t";
+ var actual = OAuthTools.NormalizeRequestParameters(input);
+ Console.WriteLine(actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ public void Can_url_encode_with_uppercase_hexadecimals()
+ {
+ const string expected = "What%20century%20is%20this%3F";
+ var actual = OAuthTools.UrlEncodeRelaxed("What century is this?");
+
+ Assert.AreEqual(expected, actual);
+ Console.WriteLine(actual);
+ }
+
+ [Test]
+ public void Can_strict_url_encode_complex_string()
+ {
+ const string expected = "%21%3F%22%3B%3A%3C%3E%5C%5C%7C%60%23%24%25%5E%26%2A%2B-_%7B%7D%5B%5D";
+ const string sequence = @"!?"";:<>\\|`#$%^&*+-_{}[]";
+
+ var actual = OAuthTools.UrlEncodeStrict(sequence);
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ public void Can_relax_url_encode_complex_string()
+ {
+ // Doesn't URL encode ! or * in this sequence
+ const string expected = "!%3F%22%3B%3A%3C%3E%5C%5C%7C%60%23%24%25%5E%26*%2B-_%7B%7D%5B%5D";
+ const string sequence = @"!?"";:<>\\|`#$%^&*+-_{}[]";
+
+ var actual = OAuthTools.UrlEncodeRelaxed(sequence);
+ Assert.AreEqual(expected, actual);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Specialized;
+using System.Linq;
+using Newtonsoft.Json;
+
+namespace Hammock.Tests.Postmark.Converters
+{
+ internal class NameValuePair
+ {
+ public string Name { get; set; }
+ public string Value { get; set; }
+ }
+
+ internal class NameValueCollectionConverter : JsonConverter
+ {
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ {
+ if (!(value is NameValueCollection))
+ {
+ return;
+ }
+
+ var collection = (NameValueCollection)value;
+ var container = collection.AllKeys.Select(key => new NameValuePair
+ {
+ Name = key,
+ Value = collection[key]
+ }).ToList();
+
+ var serialized = JsonConvert.SerializeObject(container);
+
+ writer.WriteRawValue(serialized);
+ }
+
+ public override object ReadJson(JsonReader reader, Type objectType, object originalValue, JsonSerializer serializer)
+ {
+ return reader.Value;
+ }
+
+ public override bool CanConvert(Type objectType)
+ {
+ var t = (IsNullableType(objectType))
+ ? Nullable.GetUnderlyingType(objectType)
+ : objectType;
+
+ return typeof(NameValueCollection).IsAssignableFrom(t);
+ }
+
+ public static bool IsNullable(Type type)
+ {
+ return type != null && (!type.IsValueType || IsNullableType(type));
+ }
+
+ public static bool IsNullableType(Type type)
+ {
+ if (type == null)
+ {
+ return false;
+ }
+
+ return (type.IsGenericType &&
+ type.GetGenericTypeDefinition() == typeof(Nullable<>));
+ }
+ }
+}
+
+
--- /dev/null
+using System;
+using System.Text;
+using Newtonsoft.Json;
+
+namespace Hammock.Tests.Converters
+{
+ internal class UnicodeJsonStringConverter : JsonConverter
+ {
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ {
+ var buffer = new StringBuilder();
+ buffer.Append("\"");
+ var stringValue = (string)value;
+ foreach (var c in stringValue)
+ {
+ var code = (int)c;
+ switch (c)
+ {
+ case '\"':
+ buffer.Append("\\\"");
+ break;
+ case '\\':
+ buffer.Append("\\\\");
+ break;
+ default:
+ if (code > 127)
+ {
+ buffer.AppendFormat("\\u{0:x4}", code);
+ }
+ else
+ {
+ buffer.Append(c);
+ }
+ break;
+ }
+ }
+ buffer.Append("\"");
+
+ writer.WriteRawValue(buffer.ToString());
+ }
+
+ public override object ReadJson(JsonReader reader, Type objectType, object originalValue, JsonSerializer serializer)
+ {
+ return reader.Value;
+ }
+
+ public override bool CanConvert(Type objectType)
+ {
+ return objectType == typeof(string);
+ }
+ }
+}
+
+
--- /dev/null
+using System.Collections.Specialized;
+using System.Net.Mail;
+using System.Text;
+using System.Web;
+
+namespace Hammock.Tests.Postmark
+{
+ public class PostmarkMessage
+ {
+ public PostmarkMessage()
+ {
+ Headers = new NameValueCollection(0);
+ }
+
+ public PostmarkMessage(string from, string to, string subject, string body) : this(from, to, subject, body, null)
+ {
+
+ }
+
+ public PostmarkMessage(string from, string to, string subject, string body, NameValueCollection headers)
+ {
+ var isHtml = !body.Equals(HttpUtility.HtmlEncode(body));
+
+ From = from;
+ To = to;
+ Subject = subject;
+ TextBody = isHtml ? null : body;
+ HtmlBody = isHtml ? body : null;
+ Headers = headers ?? new NameValueCollection(0);
+ }
+
+ public PostmarkMessage(MailMessage message)
+ {
+ From = message.From.DisplayName;
+ To = message.To.Count > 0 ? message.To[0].DisplayName : null;
+ Subject = message.Subject;
+ HtmlBody = message.IsBodyHtml ? message.Body : null;
+ TextBody = message.IsBodyHtml ? null : message.Body;
+
+#if NET40
+ var sb = new StringBuilder();
+ var total = message.ReplyToList.Count;
+ var count = 0;
+ foreach(var replyTo in message.ReplyToList)
+ {
+ sb.Append(replyTo);
+ count++;
+ if(count < total)
+ {
+ sb.Append(",");
+ }
+ }
+ ReplyTo = sb.ToString();
+#else
+ ReplyTo = message.ReplyTo.ToString();
+#endif
+ Headers = message.Headers;
+ }
+
+ public string From { get; set; }
+ public string To { get; set; }
+ public string ReplyTo { get; set; }
+ public string Subject { get; set; }
+
+ public string HtmlBody { get; set; }
+ public string TextBody { get; set; }
+
+ public NameValueCollection Headers { get; set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Hammock.Tests.Postmark
+{
+ public class PostmarkResponse
+ {
+ public PostmarkStatus Status { get; set; }
+ public string Message { get; set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Hammock.Tests.Postmark
+{
+ public enum PostmarkStatus
+ {
+ Unknown = 0,
+ Success,
+ UserError,
+ ServerError
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 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("Hammock.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Hammock.Tests")]
+[assembly: AssemblyCopyright("Copyright © Daniel Crenna and Jason Diller")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. RetryIf you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("d631cb7a-6382-4c0c-be0d-119b7f13709e")]
+
+// 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 Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null
+using System;
+using System.Configuration;
+using System.Diagnostics;
+using System.Net;
+using System.Text;
+using Hammock.Authentication.OAuth;
+using Hammock.Web;
+using NUnit.Framework;
+
+namespace Hammock.Tests
+{
+ [TestFixture]
+ public class RestClientTests
+ {
+ private string _consumerKey;
+ private string _consumerSecret;
+ private string _accessToken;
+ private string _accessTokenSecret;
+ private string _twitPicKey;
+
+ [SetUp]
+ public void SetUp()
+ {
+ _consumerKey = ConfigurationManager.AppSettings["OAuthConsumerKey"];
+ _consumerSecret = ConfigurationManager.AppSettings["OAuthConsumerSecret"];
+ _accessToken = ConfigurationManager.AppSettings["OAuthAccessToken"];
+ _accessTokenSecret = ConfigurationManager.AppSettings["OAuthAccessTokenSecret"];
+ _twitPicKey = ConfigurationManager.AppSettings["TwitPicKey"];
+
+ ServicePointManager.Expect100Continue = false;
+ }
+
+ [Test]
+ public void Can_request_get()
+ {
+ var client = new RestClient
+ {
+ Authority = "https://api.twitter.com",
+ UserAgent = "Hammock"
+ };
+
+ var request = new RestRequest
+ {
+ Path = "statuses/public_timeline.json",
+ DecompressionMethods = DecompressionMethods.GZip |
+ DecompressionMethods.Deflate
+ };
+
+ var response = client.Request(request);
+
+ Assert.IsNotNull(response);
+ Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
+ }
+
+ [Test]
+ public void Can_request_get_with_header_on_client()
+ {
+ var client = new RestClient
+ {
+ Authority = "https://api.twitter.com",
+ UserAgent = "Hammock",
+ Path = "statuses/public_timeline.json",
+ DecompressionMethods = DecompressionMethods.GZip | DecompressionMethods.Deflate
+ };
+
+ client.AddHeader("Accept", "application/json");
+
+ var response = client.Request();
+
+ Assert.IsNotNull(response);
+ Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
+ }
+
+ [Test]
+ public void Can_get_oauth_request_token()
+ {
+ var client = new RestClient
+ {
+ Authority = "https://api.twitter.com",
+ UserAgent = "Hammock"
+ };
+
+ var request = new RestRequest
+ {
+ Path = "oauth/request_token",
+ Credentials = OAuthCredentials.ForRequestToken(_consumerKey, _consumerSecret)
+ };
+
+ var response = client.Request(request);
+ Assert.IsNotNull(response);
+ Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
+
+ Trace.WriteLine(response.Content);
+ }
+
+ [Test]
+ public void Can_post_to_protected_resource()
+ {
+ var client = new RestClient
+ {
+ Authority = "https://api.twitter.com",
+ VersionPath = "1",
+ UserAgent = "Hammock"
+ };
+
+ var request = new RestRequest
+ {
+ Method = WebMethod.Post,
+ Path = "statuses/update.json?status=" + DateTime.Now.Ticks,
+ Credentials = OAuthCredentials.ForProtectedResource(
+ _consumerKey, _consumerSecret, _accessToken, _accessTokenSecret
+ )
+ };
+
+ var response = client.Request(request);
+ Assert.IsNotNull(response);
+ Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
+ }
+
+ [Test]
+ public void Can_post_raw_content()
+ {
+ var client = new RestClient {Authority = "http://www.apitize.com"};
+ var request = new RestRequest();
+ request.AddPostContent(Encoding.UTF8.GetBytes("Babbabooey!"));
+
+ client.Request(request);
+ }
+
+ [Test]
+ public void Can_stream_photo_over_delegated_credentials()
+ {
+ var client = new RestClient
+ {
+ Authority = "http://api.twitpic.com",
+ VersionPath = "2",
+ UserAgent = "Hammock"
+ };
+
+ var request = PrepareEchoRequest();
+ request.Method = WebMethod.Get;
+ request.Path = "upload.xml";
+ request.AddField("key", _twitPicKey);
+ request.AddFile("media", "failwhale", "_failwhale.jpg", "image/jpeg");
+
+ var response = client.Request(request);
+ Assert.IsNotNull(response);
+ Console.WriteLine(response.Content);
+ }
+
+ [Test]
+ [Ignore("Makes a live status update")]
+ public void Can_prepare_oauth_with_url_parameters()
+ {
+ var client = new RestClient
+ {
+ Authority = "http://api.twitter.com",
+ UserAgent = "Hammock"
+ };
+
+ var credentials = OAuthCredentials.ForProtectedResource(_consumerKey, _consumerSecret, _accessToken, _accessTokenSecret);
+ credentials.ParameterHandling = OAuthParameterHandling.UrlOrPostParameters;
+
+ var request = new RestRequest
+ {
+ Path = "statuses/update.json",
+ Method = WebMethod.Post,
+ Credentials = credentials
+ };
+
+ request.AddParameter("status", DateTime.Now.Ticks.ToString());
+ request.AddParameter("test", "value");
+
+ var response = client.Request(request);
+ Assert.IsNotNull(response);
+
+ Console.WriteLine(response.Content);
+
+ Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
+ }
+
+#if NET40
+ [Test]
+ public void Can_make_dynamic_request_for_collection()
+ {
+ var client = new RestClient
+ {
+ Authority = "https://api.twitter.com",
+ UserAgent = "Hammock"
+ };
+
+ var request = new RestRequest
+ {
+ Path = "statuses/public_timeline.json",
+ Method = WebMethod.Get
+ };
+
+ var response = client.RequestDynamic(request);
+ Assert.IsNotNull(response);
+ foreach (var tweet in response.ContentEntity)
+ {
+ Assert.IsNotNull(tweet);
+ Assert.IsNotNullOrEmpty(tweet.Text);
+
+ Can_handle_nested_dynamic_json(tweet);
+
+ Console.WriteLine(tweet.Text);
+ }
+ }
+
+ private static void Can_handle_nested_dynamic_json(dynamic tweet)
+ {
+ var firstLevel = tweet.User;
+ Assert.IsNotNull(firstLevel);
+
+ var secondLevel = firstLevel.ScreenName;
+ Assert.IsNotNull(secondLevel);
+ }
+
+ [Test]
+ public void Can_make_dynamic_request_for_single()
+ {
+ var client = new RestClient
+ {
+ Authority = "https://api.twitter.com",
+ UserAgent = "Hammock"
+ };
+
+ var request = new RestRequest
+ {
+ Path = "users/show.json?screen_name=hammockrest",
+ Method = WebMethod.Get
+ };
+
+ var response = client.RequestDynamic(request).ContentEntity;
+ Assert.IsNotNull(response);
+ Assert.IsNotNull(response.ScreenName);
+ }
+#endif
+
+ public RestRequest PrepareEchoRequest()
+ {
+ var client = new RestClient
+ {
+ Authority = "https://api.twitter.com",
+ VersionPath = "1",
+ UserAgent = "TweetSharp"
+ };
+
+ var request = new RestRequest
+ {
+ Method = WebMethod.Get,
+ Path = "account/verify_credentials.json",
+ Credentials = OAuthCredentials.ForProtectedResource(
+ _consumerKey, _consumerSecret, _accessToken, _accessTokenSecret
+ )
+ };
+
+ return OAuthCredentials.DelegateWith(client, request);
+ }
+ }
+}
+
+
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+ <appSettings>
+ <clear/>
+ <add key="OAuthConsumerKey" value=""/>
+ <add key="OAuthConsumerSecret" value=""/>
+ <add key="OAuthAccessToken" value=""/>
+ <add key="OAuthAccessTokenSecret" value=""/>
+ <add key="TwitPicKey" value=""/>
+ </appSettings>
+</configuration>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+ <appSettings>
+ <clear/>
+ <add key="OAuthConsumerKey" value=""/>
+ <add key="OAuthConsumerSecret" value=""/>
+ <add key="OAuthAccessToken" value=""/>
+ <add key="OAuthAccessTokenSecret" value=""/>
+ <add key="TwitPicKey" value=""/>
+ </appSettings>
+</configuration>
\ No newline at end of file
--- /dev/null
+namespace Hammock.Attributes
+{
+ internal interface INamedAttribute
+ {
+ string Name { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Reflection;
+
+namespace Hammock.Attributes
+{
+ public interface IValidatingAttribute
+ {
+ string TransformValue(PropertyInfo property, object value);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Text;
+
+namespace Hammock.Attributes.Specialized
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
+ public class EntityAttribute : Attribute
+ {
+ public EntityAttribute()
+ {
+ ContentType = "text/xml";
+ ContentEncoding = Encoding.UTF8;
+ }
+
+ public virtual string ContentType { get; private set; }
+ public virtual Encoding ContentEncoding { get; set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Hammock.Attributes.Specialized
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
+ public class HeaderAttribute : Attribute, INamedAttribute
+ {
+ public HeaderAttribute(string name)
+ {
+ Name = name;
+ }
+
+ #region INamedAttribute Members
+
+ public virtual string Name { get; private set; }
+
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Hammock.Attributes.Specialized
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
+ public class ParameterAttribute : Attribute, INamedAttribute
+ {
+ public ParameterAttribute(string name)
+ {
+ Name = name;
+ }
+
+ #region INamedAttribute Members
+
+ public virtual string Name { get; private set; }
+
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Hammock.Attributes.Specialized
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
+ public class UserAgentAttribute : Attribute
+ {
+
+ }
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<ClassDiagram MajorVersion="1" MinorVersion="1">
+ <Class Name="Hammock.Attributes.Specialized.HeaderAttribute" BaseTypeListCollapsed="true">
+ <Position X="9.75" Y="2.5" Width="1.5" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Attributes\Specialized\HeaderAttribute.cs</FileName>
+ </TypeIdentifier>
+ <Lollipop Position="0.2" />
+ </Class>
+ <Class Name="Hammock.Attributes.Specialized.ParameterAttribute" BaseTypeListCollapsed="true">
+ <Position X="7.25" Y="2.5" Width="1.75" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Attributes\Specialized\ParameterAttribute.cs</FileName>
+ </TypeIdentifier>
+ <Lollipop Position="0.2" />
+ </Class>
+ <Class Name="Hammock.Attributes.Specialized.UserAgentAttribute" Collapsed="true">
+ <Position X="2.25" Y="2.5" Width="1.75" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Attributes\Specialized\UserAgentAttribute.cs</FileName>
+ </TypeIdentifier>
+ </Class>
+ <Class Name="Hammock.Attributes.Specialized.EntityAttribute">
+ <Position X="4.75" Y="2.5" Width="1.75" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAACA=</HashCode>
+ <FileName>Attributes\Specialized\EntityAttribute.cs</FileName>
+ </TypeIdentifier>
+ </Class>
+ <Class Name="System.Attribute" Collapsed="true">
+ <Position X="2.25" Y="1.25" Width="9" />
+ <TypeIdentifier />
+ <Lollipop Position="0.2" />
+ </Class>
+ <Interface Name="Hammock.Attributes.INamedAttribute">
+ <Position X="0.5" Y="1.25" Width="1.5" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Attributes\INamedAttribute.cs</FileName>
+ </TypeIdentifier>
+ </Interface>
+ <Font Name="Segoe UI" Size="9" />
+</ClassDiagram>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Reflection;
+
+namespace Hammock.Attributes.Validation
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class BooleanToIntegerAttribute : ValidationAttribute
+ {
+ public override string TransformValue(PropertyInfo property, object value)
+ {
+#if !Smartphone && !NETCF
+ bool result;
+ return bool.TryParse(value.ToString(), out result)
+ ? result ? "1" : "0"
+ : base.TransformValue(property, value);
+#else
+ try
+ {
+ var result = bool.Parse(value.ToString());
+ return result ? "1" : "0";
+ }
+ catch (Exception)
+ {
+ return base.TransformValue(property, value);
+ }
+#endif
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using Hammock.Extensions;
+
+namespace Hammock.Attributes.Validation
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class DateTimeFormatAttribute : ValidationAttribute
+ {
+ public DateTimeFormatAttribute(string format)
+ {
+ Format = format;
+ }
+
+ public string Format { get; private set; }
+
+ public override string TransformValue(System.Reflection.PropertyInfo property, object value)
+ {
+#if !Smartphone && !NETCF
+ DateTime result;
+ return DateTime.TryParse(value.ToString(), out result) && !Format.IsNullOrBlank()
+ ? result.ToString(Format)
+ : base.TransformValue(property, value);
+#else
+ try
+ {
+ var result = DateTime.Parse(value.ToString());
+ return Format.IsNullOrBlank()
+ ? result.ToString(Format)
+ : base.TransformValue(property, value);
+ }
+ catch (Exception)
+ {
+ return base.TransformValue(property, value);
+ }
+#endif
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using Hammock.Extensions;
+using Hammock.Validation;
+
+namespace Hammock.Attributes.Validation
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class RequiredAttribute : ValidationAttribute
+ {
+ public override string TransformValue(System.Reflection.PropertyInfo property, object value)
+ {
+ if(value == null)
+ {
+ var message = "The property {0} is required, but was null.".FormatWith(property.Name);
+ throw new ValidationException(message);
+ }
+ return base.TransformValue(property, value);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using Hammock.Extensions;
+using Hammock.Specifications;
+using Hammock.Validation;
+
+namespace Hammock.Attributes.Validation
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class SpecificationAttribute : ValidationAttribute
+ {
+ public SpecificationAttribute(Type specificationType)
+ {
+ if (!specificationType.Implements(typeof (ISpecification)))
+ {
+ throw new ValidationException("You must provide a valid specification type.");
+ }
+
+ SpecificationType = specificationType as ISpecification;
+ }
+
+ public ISpecification SpecificationType { get; private set; }
+
+ public override string TransformValue(System.Reflection.PropertyInfo property, object value)
+ {
+ if(SpecificationType != null && !value.Satisfies(SpecificationType))
+ {
+ var message =
+ "The value for '{0}' does not satisfy {1}."
+ .FormatWith(property.Name, SpecificationType);
+
+ throw new ValidationException(message);
+ }
+
+ return base.TransformValue(property, value);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Reflection;
+
+namespace Hammock.Attributes.Validation
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
+ public class ValidationAttribute : Attribute, IValidatingAttribute
+ {
+ public virtual string TransformValue(PropertyInfo property, object value)
+ {
+ return value.ToString();
+ }
+ }
+}
+
+
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<ClassDiagram MajorVersion="1" MinorVersion="1">
+ <Class Name="Hammock.Attributes.Validation.BooleanToIntegerAttribute" Collapsed="true">
+ <Position X="1.25" Y="3.25" Width="2.25" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Attributes\Validation\BooleanToIntegerAttribute.cs</FileName>
+ </TypeIdentifier>
+ </Class>
+ <Class Name="Hammock.Attributes.Validation.RequiredAttribute" Collapsed="true">
+ <Position X="7" Y="3.25" Width="2.5" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Attributes\Validation\RequiredAttribute.cs</FileName>
+ </TypeIdentifier>
+ </Class>
+ <Class Name="Hammock.Attributes.Validation.DateTimeFormatAttribute" Collapsed="true">
+ <Position X="9.75" Y="3.25" Width="2.25" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAACAAAAAAAAgAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Attributes\Validation\DateTimeFormatAttribute.cs</FileName>
+ </TypeIdentifier>
+ </Class>
+ <Class Name="Hammock.Attributes.Validation.SpecificationAttribute" Collapsed="true">
+ <Position X="4" Y="3.25" Width="2.25" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAI=</HashCode>
+ <FileName>Attributes\Validation\SpecificationAttribute.cs</FileName>
+ </TypeIdentifier>
+ </Class>
+ <Class Name="Hammock.Attributes.Validation.ValidationAttribute" Collapsed="true">
+ <Position X="1.25" Y="1.75" Width="10.75" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Attributes\Validation\ValidationAttribute.cs</FileName>
+ </TypeIdentifier>
+ <Lollipop Position="0.2" />
+ </Class>
+ <Font Name="Segoe UI" Size="9" />
+</ClassDiagram>
\ No newline at end of file
--- /dev/null
+using System;
+using Hammock.Extensions;
+using Hammock.Web;
+
+namespace Hammock.Authentication.Basic
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class BasicAuthCredentials : IWebCredentials
+ {
+ public virtual string Username { get; set; }
+ public virtual string Password { get; set; }
+
+ public WebQuery GetQueryFor(string url, RestBase request, IWebQueryInfo info, WebMethod method, bool enableTrace)
+ {
+ return GetQueryForImpl(info, enableTrace);
+ }
+
+ public WebQuery GetQueryFor(string url, WebParameterCollection parameters, IWebQueryInfo info, WebMethod method, bool enableTrace)
+ {
+ return GetQueryForImpl(info, enableTrace);
+ }
+
+ private WebQuery GetQueryForImpl(IWebQueryInfo info, bool enableTrace)
+ {
+ return HasAuth
+ ? new BasicAuthWebQuery(info, Username, Password, enableTrace)
+ : new BasicAuthWebQuery(info, enableTrace);
+ }
+
+ public virtual bool HasAuth
+ {
+ get
+ {
+ return !Username.IsNullOrBlank() && !Password.IsNullOrBlank();
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using Hammock.Web;
+
+namespace Hammock.Authentication
+{
+ public interface IWebCredentials
+ {
+ WebQuery GetQueryFor(string url,
+ RestBase request,
+ IWebQueryInfo info,
+ WebMethod method,
+ bool enableTrace);
+
+ WebQuery GetQueryFor(string url,
+ WebParameterCollection parameters,
+ IWebQueryInfo info,
+ WebMethod method,
+ bool enableTrace);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using Hammock.Web;
+
+#if SILVERLIGHT
+using Hammock.Silverlight.Compat;
+#endif
+
+namespace Hammock.Authentication.OAuth
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class OAuthCredentials : IWebCredentials
+ {
+ public virtual string ConsumerKey { get; set; }
+ public virtual string ConsumerSecret { get; set; }
+ public virtual OAuthParameterHandling ParameterHandling { get; set; }
+ public virtual OAuthSignatureMethod SignatureMethod { get; set; }
+ public virtual OAuthSignatureTreatment SignatureTreatment { get; set; }
+ public virtual OAuthType Type { get; set; }
+
+ public virtual string Token { get; set; }
+ public virtual string TokenSecret { get; set; }
+ public virtual string Verifier { get; set; }
+ public virtual string ClientUsername { get; set; }
+ public virtual string ClientPassword { get; set; }
+ public virtual string CallbackUrl { get; set; }
+ public virtual string Version { get; set; }
+ public virtual string SessionHandle { get; set; }
+
+ public static RestRequest DelegateWith(RestClient client, RestRequest request)
+ {
+ if(request == null)
+ {
+ throw new ArgumentNullException("request");
+ }
+
+ if(!request.Method.HasValue)
+ {
+ throw new ArgumentException("Request must specify a web method.");
+ }
+
+ var method = request.Method.Value;
+ var credentials = (OAuthCredentials)request.Credentials;
+ var url = request.BuildEndpoint(client).ToString();
+ var workflow = new OAuthWorkflow(credentials);
+ var uri = new Uri(client.Authority);
+ var realm = uri.Host;
+ var enableTrace = client.TraceEnabled || request.TraceEnabled;
+
+ var info = workflow.BuildProtectedResourceInfo(method, request.GetAllHeaders(), url);
+ var query = credentials.GetQueryFor(url, request, info, method, enableTrace);
+ ((OAuthWebQuery) query).Realm = realm;
+ var auth = query.GetAuthorizationContent();
+
+ var echo = new RestRequest();
+ echo.AddHeader("X-Auth-Service-Provider", url);
+ echo.AddHeader("X-Verify-Credentials-Authorization", auth);
+ return echo;
+ }
+
+ public static OAuthCredentials ForRequestToken(string consumerKey, string consumerSecret)
+ {
+ var credentials = new OAuthCredentials
+ {
+ Type = OAuthType.RequestToken,
+ ParameterHandling = OAuthParameterHandling.HttpAuthorizationHeader,
+ SignatureMethod = OAuthSignatureMethod.HmacSha1,
+ SignatureTreatment = OAuthSignatureTreatment.Escaped,
+ ConsumerKey = consumerKey,
+ ConsumerSecret = consumerSecret
+ };
+ return credentials;
+ }
+
+ public static OAuthCredentials ForRequestToken(string consumerKey, string consumerSecret, string callbackUrl)
+ {
+ var credentials = ForRequestToken(consumerKey, consumerSecret);
+ credentials.CallbackUrl = callbackUrl;
+ return credentials;
+ }
+
+ public static OAuthCredentials ForAccessToken(string consumerKey, string consumerSecret, string requestToken, string requestTokenSecret)
+ {
+ var credentials = new OAuthCredentials
+ {
+ Type = OAuthType.AccessToken,
+ ParameterHandling = OAuthParameterHandling.HttpAuthorizationHeader,
+ SignatureMethod = OAuthSignatureMethod.HmacSha1,
+ SignatureTreatment = OAuthSignatureTreatment.Escaped,
+ ConsumerKey = consumerKey,
+ ConsumerSecret = consumerSecret,
+ Token = requestToken,
+ TokenSecret = requestTokenSecret
+ };
+ return credentials;
+ }
+
+ public static OAuthCredentials ForAccessToken(string consumerKey, string consumerSecret, string requestToken, string requestTokenSecret, string verifier)
+ {
+ var credentials = ForAccessToken(consumerKey, consumerSecret, requestToken, requestTokenSecret);
+ credentials.Verifier = verifier;
+ return credentials;
+ }
+
+ public static OAuthCredentials ForAccessTokenRefresh(string consumerKey, string consumerSecret, string accessToken, string accessTokenSecret, string sessionHandle)
+ {
+ var credentials = ForAccessToken(consumerKey, consumerSecret, accessToken, accessTokenSecret);
+ credentials.SessionHandle = sessionHandle;
+ return credentials;
+ }
+
+ public static OAuthCredentials ForAccessTokenRefresh(string consumerKey, string consumerSecret, string accessToken, string accessTokenSecret, string sessionHandle, string verifier)
+ {
+ var credentials = ForAccessToken(consumerKey, consumerSecret, accessToken, accessTokenSecret);
+ credentials.SessionHandle = sessionHandle;
+ credentials.Verifier = verifier;
+ return credentials;
+ }
+
+ public static OAuthCredentials ForClientAuthentication(string consumerKey, string consumerSecret, string username, string password)
+ {
+ var credentials = new OAuthCredentials
+ {
+ Type = OAuthType.ClientAuthentication,
+ ParameterHandling = OAuthParameterHandling.HttpAuthorizationHeader,
+ SignatureMethod = OAuthSignatureMethod.HmacSha1,
+ SignatureTreatment = OAuthSignatureTreatment.Escaped,
+ ConsumerKey = consumerKey,
+ ConsumerSecret = consumerSecret,
+ ClientUsername = username,
+ ClientPassword = password
+ };
+
+ return credentials;
+ }
+
+ public static OAuthCredentials ForProtectedResource(string consumerKey, string consumerSecret, string accessToken, string accessTokenSecret)
+ {
+ var credentials = new OAuthCredentials
+ {
+ Type = OAuthType.ProtectedResource,
+ ParameterHandling = OAuthParameterHandling.HttpAuthorizationHeader,
+ SignatureMethod = OAuthSignatureMethod.HmacSha1,
+ SignatureTreatment = OAuthSignatureTreatment.Escaped,
+ ConsumerKey = consumerKey,
+ ConsumerSecret = consumerSecret,
+ Token = accessToken,
+ TokenSecret = accessTokenSecret
+ };
+ return credentials;
+ }
+
+ public virtual WebQuery GetQueryFor(string url,
+ WebParameterCollection parameters,
+ IWebQueryInfo info,
+ WebMethod method,
+ bool enableTrace)
+ {
+ OAuthWebQueryInfo oauth;
+
+ var workflow = new OAuthWorkflow
+ {
+ ConsumerKey = ConsumerKey,
+ ConsumerSecret = ConsumerSecret,
+ ParameterHandling = ParameterHandling,
+ SignatureMethod = SignatureMethod,
+ SignatureTreatment = SignatureTreatment,
+ CallbackUrl = CallbackUrl,
+ ClientPassword = ClientPassword,
+ ClientUsername = ClientUsername,
+ Verifier = Verifier,
+ Token = Token,
+ TokenSecret = TokenSecret,
+ Version = Version ?? "1.0",
+ SessionHandle = SessionHandle
+ };
+
+ switch (Type)
+ {
+ case OAuthType.RequestToken:
+ workflow.RequestTokenUrl = url;
+ oauth = workflow.BuildRequestTokenInfo(method, parameters);
+ break;
+ case OAuthType.AccessToken:
+ workflow.AccessTokenUrl = url;
+ oauth = workflow.BuildAccessTokenInfo(method, parameters);
+ break;
+ case OAuthType.ClientAuthentication:
+ method = WebMethod.Post;
+ workflow.AccessTokenUrl = url;
+ oauth = workflow.BuildClientAuthAccessTokenInfo(method, parameters);
+ break;
+ case OAuthType.ProtectedResource:
+ oauth = workflow.BuildProtectedResourceInfo(method, parameters, url);
+ oauth.FirstUse = true;
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+
+ return new OAuthWebQuery(oauth, enableTrace);
+ }
+
+ public virtual WebQuery GetQueryFor(string url, RestBase request, IWebQueryInfo info, WebMethod method, bool enableTrace)
+ {
+ var query = GetQueryFor(url, request.Parameters, info, method, enableTrace);
+ request.Method = method;
+ return query;
+ }
+ }
+}
+
+
--- /dev/null
+using System;
+using System.Runtime.Serialization;
+
+namespace Hammock.Authentication.OAuth
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public enum OAuthParameterHandling
+ {
+#if !SILVERLIGHT && !Smartphone && !ClientProfiles && !NET20 && !MonoTouch && !NETCF
+ [EnumMember] HttpAuthorizationHeader,
+ [EnumMember] UrlOrPostParameters
+#else
+ HttpAuthorizationHeader,
+ UrlOrPostParameters
+#endif
+ }
+
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public enum OAuthSignatureTreatment
+ {
+#if !SILVERLIGHT && !Smartphone && !ClientProfiles && !NET20 && !MonoTouch && !NETCF
+ [EnumMember]
+ Escaped,
+ [EnumMember]
+ Unescaped
+#else
+ Escaped,
+ Unescaped
+#endif
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.Serialization;
+
+namespace Hammock.Authentication.OAuth
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public enum OAuthSignatureMethod
+ {
+#if !SILVERLIGHT && !Smartphone && !ClientProfiles && !NET20 && !MonoTouch && !NETCF
+ [EnumMember] HmacSha1,
+ [EnumMember] PlainText,
+ [EnumMember] RsaSha1
+#else
+ HmacSha1,
+ PlainText,
+ RsaSha1
+#endif
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Hammock.Authentication.OAuth
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class OAuthToken
+ {
+ public virtual string Token { get; set; }
+ public virtual string TokenSecret { get; set; }
+ public virtual string Verifier { get; set; }
+ public virtual bool CallbackConfirmed { get; set; }
+ public virtual string UserId { get; set; }
+ public virtual string ScreenName { get; set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+using Hammock.Extensions;
+using Hammock.Web;
+
+#if NETCF
+using Hammock.Security.Cryptography;
+#endif
+
+namespace Hammock.Authentication.OAuth
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public static class OAuthTools
+ {
+ private const string AlphaNumeric = Upper + Lower + Digit;
+ private const string Digit = "1234567890";
+ private const string Lower = "abcdefghijklmnopqrstuvwxyz";
+ private const string Unreserved = AlphaNumeric + "-._~";
+ private const string Upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ private static readonly Random _random;
+ private static readonly object _randomLock = new object();
+
+#if !SILVERLIGHT
+ private static readonly RandomNumberGenerator _rng =
+ RandomNumberGenerator.Create();
+#endif
+
+ static OAuthTools()
+ {
+#if !SILVERLIGHT
+ var bytes = new byte[4];
+ _rng.GetNonZeroBytes(bytes);
+ _random = new Random(BitConverter.ToInt32(bytes, 0));
+#else
+ _random = new Random();
+#endif
+ }
+
+ /// <summary>
+ /// All text parameters are UTF-8 encoded (per section 5.1).
+ /// </summary>
+ /// <seealso cref="http://www.hueniverse.com/hueniverse/2008/10/beginners-gui-1.html"/>
+ private static readonly Encoding _encoding = Encoding.UTF8;
+
+ /// <summary>
+ /// Generates a random 16-byte lowercase alphanumeric string.
+ /// </summary>
+ /// <seealso cref="http://oauth.net/core/1.0#nonce"/>
+ /// <returns></returns>
+ public static string GetNonce()
+ {
+ const string chars = (Lower + Digit);
+
+ var nonce = new char[16];
+ lock (_randomLock)
+ {
+ for (var i = 0; i < nonce.Length; i++)
+ {
+ nonce[i] = chars[_random.Next(0, chars.Length)];
+ }
+ }
+ return new string(nonce);
+ }
+
+ /// <summary>
+ /// Generates a timestamp based on the current elapsed seconds since '01/01/1970 0000 GMT"
+ /// </summary>
+ /// <seealso cref="http://oauth.net/core/1.0#nonce"/>
+ /// <returns></returns>
+ public static string GetTimestamp()
+ {
+ return GetTimestamp(DateTime.UtcNow);
+ }
+
+ /// <summary>
+ /// Generates a timestamp based on the elapsed seconds of a given time since '01/01/1970 0000 GMT"
+ /// </summary>
+ /// <seealso cref="http://oauth.net/core/1.0#nonce"/>
+ /// <param name="dateTime">A specified point in time.</param>
+ /// <returns></returns>
+ public static string GetTimestamp(DateTime dateTime)
+ {
+ var timestamp = dateTime.ToUnixTime();
+ return timestamp.ToString();
+ }
+
+ /// <summary>
+ /// URL encodes a string based on section 5.1 of the OAuth spec.
+ /// Namely, percent encoding with [RFC3986], avoiding unreserved characters,
+ /// upper-casing hexadecimal characters, and UTF-8 encoding for text value pairs.
+ /// </summary>
+ /// <param name="value"></param>
+ /// <seealso cref="http://oauth.net/core/1.0#encoding_parameters" />
+ public static string UrlEncodeRelaxed(string value)
+ {
+ var escaped = Uri.EscapeDataString(value);
+
+ // LinkedIn users have problems because it requires escaping brackets
+ escaped = escaped.Replace("(", "(".PercentEncode())
+ .Replace(")", ")".PercentEncode());
+
+ return escaped;
+ }
+
+ /// <summary>
+ /// URL encodes a string based on section 5.1 of the OAuth spec.
+ /// Namely, percent encoding with [RFC3986], avoiding unreserved characters,
+ /// upper-casing hexadecimal characters, and UTF-8 encoding for text value pairs.
+ /// </summary>
+ /// <param name="value"></param>
+ /// <seealso cref="http://oauth.net/core/1.0#encoding_parameters" />
+ public static string UrlEncodeStrict(string value)
+ {
+ // [JD]: We need to escape the apostrophe as well or the signature will fail
+ var original = value;
+ var ret = original.Where(
+ c => !Unreserved.Contains(c) && c != '%').Aggregate(
+ value, (current, c) => current.Replace(
+ c.ToString(), c.ToString().PercentEncode()
+ ));
+
+ return ret.Replace("%%", "%25%"); // Revisit to encode actual %'s
+ }
+
+ /// <summary>
+ /// Sorts a collection of key-value pairs by name, and then value if equal,
+ /// concatenating them into a single string. This string should be encoded
+ /// prior to, or after normalization is run.
+ /// </summary>
+ /// <seealso cref="http://oauth.net/core/1.0#rfc.section.9.1.1"/>
+ /// <param name="parameters"></param>
+ /// <returns></returns>
+ public static string NormalizeRequestParameters(WebParameterCollection parameters)
+ {
+ var copy = SortParametersExcludingSignature(parameters);
+ var concatenated = copy.Concatenate("=", "&");
+ return concatenated;
+ }
+
+ /// <summary>
+ /// Sorts a <see cref="WebParameterCollection"/> by name, and then value if equal.
+ /// </summary>
+ /// <param name="parameters">A collection of parameters to sort</param>
+ /// <returns>A sorted parameter collection</returns>
+ public static WebParameterCollection SortParametersExcludingSignature(WebParameterCollection parameters)
+ {
+ var copy = new WebParameterCollection(parameters);
+ var exclusions = copy.Where(n => n.Name.EqualsIgnoreCase("oauth_signature"));
+
+ copy.RemoveAll(exclusions);
+ copy.ForEach(p => p.Value = UrlEncodeStrict(p.Value));
+ copy.Sort((x, y) => x.Name.Equals(y.Name) ? x.Value.CompareTo(y.Value) : x.Name.CompareTo(y.Name));
+ return copy;
+ }
+
+ /// <summary>
+ /// Creates a request URL suitable for making OAuth requests.
+ /// Resulting URLs must exclude port 80 or port 443 when accompanied by HTTP and HTTPS, respectively.
+ /// Resulting URLs must be lower case.
+ /// </summary>
+ /// <seealso cref="http://oauth.net/core/1.0#rfc.section.9.1.2"/>
+ /// <param name="url">The original request URL</param>
+ /// <returns></returns>
+ public static string ConstructRequestUrl(Uri url)
+ {
+ if (url == null)
+ {
+ throw new ArgumentNullException("url");
+ }
+
+ var sb = new StringBuilder();
+
+ var requestUrl = "{0}://{1}".FormatWith(url.Scheme, url.Host);
+ var qualified = ":{0}".FormatWith(url.Port);
+ var basic = url.Scheme == "http" && url.Port == 80;
+ var secure = url.Scheme == "https" && url.Port == 443;
+
+ sb.Append(requestUrl);
+ sb.Append(!basic && !secure ? qualified : "");
+ sb.Append(url.AbsolutePath);
+
+ return sb.ToString(); //.ToLower();
+ }
+
+ /// <summary>
+ /// Creates a request elements concatentation value to send with a request.
+ /// This is also known as the signature base.
+ /// </summary>
+ /// <seealso cref="http://oauth.net/core/1.0#rfc.section.9.1.3"/>
+ /// <seealso cref="http://oauth.net/core/1.0#sig_base_example"/>
+ /// <param name="method">The request's HTTP method type</param>
+ /// <param name="url">The request URL</param>
+ /// <param name="parameters">The request's parameters</param>
+ /// <returns>A signature base string</returns>
+ public static string ConcatenateRequestElements(WebMethod method, string url, WebParameterCollection parameters)
+ {
+ var sb = new StringBuilder();
+
+ // Separating &'s are not URL encoded
+ var requestMethod = method.ToUpper().Then("&");
+ var requestUrl = UrlEncodeRelaxed(ConstructRequestUrl(url.AsUri())).Then("&");
+ var requestParameters = UrlEncodeRelaxed(NormalizeRequestParameters(parameters));
+
+ sb.Append(requestMethod);
+ sb.Append(requestUrl);
+ sb.Append(requestParameters);
+
+ return sb.ToString();
+ }
+
+ /// <summary>
+ /// Creates a signature value given a signature base and the consumer secret.
+ /// This method is used when the token secret is currently unknown.
+ /// </summary>
+ /// <seealso cref="http://oauth.net/core/1.0#rfc.section.9.2"/>
+ /// <param name="signatureMethod">The hashing method</param>
+ /// <param name="signatureBase">The signature base</param>
+ /// <param name="consumerSecret">The consumer key</param>
+ /// <returns></returns>
+ public static string GetSignature(OAuthSignatureMethod signatureMethod,
+ string signatureBase,
+ string consumerSecret)
+ {
+ return GetSignature(signatureMethod, OAuthSignatureTreatment.Escaped, signatureBase, consumerSecret, null);
+ }
+
+ /// <summary>
+ /// Creates a signature value given a signature base and the consumer secret.
+ /// This method is used when the token secret is currently unknown.
+ /// </summary>
+ /// <seealso cref="http://oauth.net/core/1.0#rfc.section.9.2"/>
+ /// <param name="signatureMethod">The hashing method</param>
+ /// <param name="signatureTreatment">The treatment to use on a signature value</param>
+ /// <param name="signatureBase">The signature base</param>
+ /// <param name="consumerSecret">The consumer key</param>
+ /// <returns></returns>
+ public static string GetSignature(OAuthSignatureMethod signatureMethod,
+ OAuthSignatureTreatment signatureTreatment,
+ string signatureBase,
+ string consumerSecret)
+ {
+ return GetSignature(signatureMethod, signatureTreatment, signatureBase, consumerSecret, null);
+ }
+
+ /// <summary>
+ /// Creates a signature value given a signature base and the consumer secret and a known token secret.
+ /// </summary>
+ /// <seealso cref="http://oauth.net/core/1.0#rfc.section.9.2"/>
+ /// <param name="signatureMethod">The hashing method</param>
+ /// <param name="signatureBase">The signature base</param>
+ /// <param name="consumerSecret">The consumer secret</param>
+ /// <param name="tokenSecret">The token secret</param>
+ /// <returns></returns>
+ public static string GetSignature(OAuthSignatureMethod signatureMethod,
+ string signatureBase,
+ string consumerSecret,
+ string tokenSecret)
+ {
+ return GetSignature(signatureMethod, OAuthSignatureTreatment.Escaped, consumerSecret, tokenSecret);
+ }
+
+ /// <summary>
+ /// Creates a signature value given a signature base and the consumer secret and a known token secret.
+ /// </summary>
+ /// <seealso cref="http://oauth.net/core/1.0#rfc.section.9.2"/>
+ /// <param name="signatureMethod">The hashing method</param>
+ /// <param name="signatureTreatment">The treatment to use on a signature value</param>
+ /// <param name="signatureBase">The signature base</param>
+ /// <param name="consumerSecret">The consumer secret</param>
+ /// <param name="tokenSecret">The token secret</param>
+ /// <returns></returns>
+ public static string GetSignature(OAuthSignatureMethod signatureMethod,
+ OAuthSignatureTreatment signatureTreatment,
+ string signatureBase,
+ string consumerSecret,
+ string tokenSecret)
+ {
+ if (tokenSecret.IsNullOrBlank())
+ {
+ tokenSecret = String.Empty;
+ }
+
+ consumerSecret = UrlEncodeRelaxed(consumerSecret);
+ tokenSecret = UrlEncodeRelaxed(tokenSecret);
+
+ string signature;
+ switch (signatureMethod)
+ {
+ case OAuthSignatureMethod.HmacSha1:
+ {
+ var crypto = new HMACSHA1();
+ var key = "{0}&{1}".FormatWith(consumerSecret, tokenSecret);
+
+ crypto.Key = _encoding.GetBytes(key);
+ signature = signatureBase.HashWith(crypto);
+
+ break;
+ }
+ default:
+ throw new NotImplementedException("Only HMAC-SHA1 is currently supported.");
+ }
+
+ var result = signatureTreatment == OAuthSignatureTreatment.Escaped
+ ? UrlEncodeRelaxed(signature)
+ : signature;
+
+ return result;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.Serialization;
+
+namespace Hammock.Authentication.OAuth
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public enum OAuthType
+ {
+#if !SILVERLIGHT && !Smartphone && !ClientProfiles && !NET20 && !MonoTouch && !NETCF
+ [EnumMember] RequestToken,
+ [EnumMember] AccessToken,
+ [EnumMember] ProtectedResource,
+ [EnumMember] ClientAuthentication
+#else
+ RequestToken,
+ AccessToken,
+ ProtectedResource,
+ ClientAuthentication
+#endif
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Net;
+using System.Text;
+using Hammock.Caching;
+using Hammock.Extensions;
+using Hammock.Web;
+
+#if SILVERLIGHT
+using Hammock.Silverlight.Compat;
+#endif
+
+namespace Hammock.Authentication.OAuth
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class OAuthWebQuery : WebQuery
+ {
+ public virtual string Realm { get; set; }
+ public virtual OAuthParameterHandling ParameterHandling { get; private set; }
+ private bool _recalculate;
+
+ public OAuthWebQuery(OAuthWebQueryInfo info, bool enableTrace) : base(info, enableTrace)
+ {
+ Initialize(info);
+ }
+
+ private void Initialize(OAuthWebQueryInfo info)
+ {
+ Method = info.WebMethod;
+ ParameterHandling = info.ParameterHandling;
+ if(info.FirstUse)
+ {
+ _recalculate = false;
+ }
+ }
+
+ protected override Func<string, string> BeforeBuildPostOrPutFormWebRequest()
+ {
+ return post =>
+ {
+ post = AppendParameters(post);
+
+ return post;
+ };
+ }
+
+ protected override byte[] BuildPostOrPutContent(WebRequest request, string post)
+ {
+ var content = PostProcessPostParameters(request, post.AsUri());
+#if TRACE
+ Trace.WriteLineIf(TraceEnabled, string.Concat("\r\n", content));
+#endif
+ return content;
+ }
+
+ protected override Func<string, string> BeforeBuildGetDeleteHeadOptionsWebRequest()
+ {
+ return GetOAuthUrl;
+ }
+
+ protected override Func<string, string> BeforeBuildPostOrPutEntityWebRequest()
+ {
+ return GetOAuthUrl;
+ }
+
+ private string GetOAuthUrl(string url)
+ {
+ // [DC]: Prior to this call, there should be no parameter encoding
+ url = PreProcessPostParameters(url);
+
+ switch (ParameterHandling)
+ {
+ case OAuthParameterHandling.HttpAuthorizationHeader:
+ url = AppendParameters(url, true /* escape */, true /* skipOAuth */);
+ break;
+ case OAuthParameterHandling.UrlOrPostParameters:
+ url = GetAddressWithOAuthParameters(new Uri(url));
+ break;
+ }
+
+ return url;
+ }
+
+ protected override string AppendParameters(string url)
+ {
+ return AppendParameters(url, true /* escape */, false /* skipOAuth */);
+ }
+
+ protected virtual string AppendParameters(string url, bool escape, bool skipOAuth)
+ {
+ var parameters = 0;
+ foreach (var parameter in Parameters.Where(
+ parameter => !(parameter is HttpPostParameter) || Method == WebMethod.Post
+ ))
+ {
+ if (skipOAuth && parameter.Name.StartsWith("oauth_"))
+ {
+ continue;
+ }
+
+ var value = escape
+ ? OAuthTools.UrlEncodeStrict(parameter.Value)
+ : parameter.Value;
+
+ // GET parameters in URL
+ url = url.Then(parameters > 0 || url.Contains("?") ? "&" : "?");
+ url = url.Then("{0}={1}".FormatWith(parameter.Name, value));
+ parameters++;
+ }
+
+ return url;
+ }
+
+ private string GetAddressWithOAuthParameters(Uri address)
+ {
+ var sb = new StringBuilder("?");
+ var parameters = 0;
+ foreach (var parameter in Parameters)
+ {
+ if (parameter.Name.IsNullOrBlank() || parameter.Value.IsNullOrBlank())
+ {
+ continue;
+ }
+
+ parameters++;
+ var format = parameters < Parameters.Count ? "{0}={1}&" : "{0}={1}";
+ sb.Append(format.FormatWith(parameter.Name, parameter.Value));
+ }
+
+ return address + sb.ToString();
+ }
+
+ private byte[] PostProcessPostParameters(WebRequest request, Uri uri)
+ {
+ var body = "";
+ switch (ParameterHandling)
+ {
+ case OAuthParameterHandling.HttpAuthorizationHeader:
+ SetAuthorizationHeader(request, "Authorization");
+#if SILVERLIGHT
+ var postParameters = new WebParameterCollection(uri.Query.ParseQueryString());
+#else
+ var postParameters = new WebParameterCollection(uri.Query.ParseQueryString());
+#endif
+ // Only use the POST parameters that exist in the body
+ postParameters = new WebParameterCollection(postParameters.Where(p => !p.Name.StartsWith("oauth_")));
+
+ // Append any leftover values to the POST body
+ var nonAuthParameters = GetPostParametersValue(postParameters, true /* escapeParameters */);
+ if (body.IsNullOrBlank())
+ {
+ body = nonAuthParameters;
+ }
+ else
+ {
+ if (!nonAuthParameters.IsNullOrBlank())
+ {
+ body += "&".Then(nonAuthParameters);
+ }
+ }
+ break;
+ case OAuthParameterHandling.UrlOrPostParameters:
+ body = GetPostParametersValue(Parameters, false /* escapeParameters */);
+ break;
+ }
+
+ var content = Encoding.UTF8.GetBytes(body);
+ return content;
+ }
+
+ // Removes POST parameters from query
+ private static string PreProcessPostParameters(string url)
+ {
+ var uri = url.AsUri();
+ url = uri.Scheme.Then("://")
+#if !SILVERLIGHT
+ .Then(uri.Authority);
+#else
+ .Then(uri.Host);
+ if ((uri.Scheme.Equals("http") && uri.Port != 80) ||
+ (uri.Scheme.Equals("https") && uri.Port != 443))
+ {
+ url = url.Then(":" + uri.Port);
+ }
+#endif
+ url = url.Then(uri.AbsolutePath);
+ return url;
+ }
+
+ private static string GetPostParametersValue(ICollection<WebPair> postParameters, bool escapeParameters)
+ {
+ var body = "";
+ var count = 0;
+ var parameters = postParameters.Where(p => !p.Name.IsNullOrBlank() &&
+ !p.Value.IsNullOrBlank()).ToList();
+
+ foreach (var postParameter in parameters)
+ {
+ // [DC]: client_auth method does not function when these are escaped
+ var name = escapeParameters
+ ? OAuthTools.UrlEncodeStrict(postParameter.Name)
+ : postParameter.Name;
+ var value = escapeParameters
+ ? OAuthTools.UrlEncodeStrict(postParameter.Value)
+ : postParameter.Value;
+
+ var token = "{0}={1}".FormatWith(name, value);
+ body = body.Then(token);
+ count++;
+ if (count < postParameters.Count)
+ {
+ body = body.Then("&");
+ }
+ }
+ return body;
+ }
+
+ protected override void AuthenticateRequest(WebRequest request)
+ {
+ switch(ParameterHandling)
+ {
+ case OAuthParameterHandling.HttpAuthorizationHeader:
+ SetAuthorizationHeader(request, "Authorization");
+ break;
+ case OAuthParameterHandling.UrlOrPostParameters:
+ // [DC]: Handled in builder method
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+
+ public override string GetAuthorizationContent()
+ {
+ switch (ParameterHandling)
+ {
+ case OAuthParameterHandling.HttpAuthorizationHeader:
+ return BuildAuthorizationHeader();
+ case OAuthParameterHandling.UrlOrPostParameters:
+ return GetPostParametersValue(Parameters, false /* escapeParameters */);
+ default:
+ return "";
+ }
+ }
+
+ protected override void SetAuthorizationHeader(WebRequest request, string header)
+ {
+ request.Headers[header] = BuildAuthorizationHeader();
+ }
+
+ private string BuildAuthorizationHeader()
+ {
+ var sb = new StringBuilder("OAuth ");
+ if (!Realm.IsNullOrBlank())
+ {
+ sb.Append("realm=\"{0}\",".FormatWith(OAuthTools.UrlEncodeRelaxed(Realm)));
+ }
+
+ Parameters.Sort((l, r) => l.Name.CompareTo(r.Name));
+
+ var parameters = 0;
+ var pairs = Parameters.Where(parameter => !parameter.Name.IsNullOrBlank() && !parameter.Value.IsNullOrBlank() && parameter.Name.StartsWith("oauth_"));
+ foreach (var parameter in pairs)
+ {
+ parameters++;
+ var format = parameters < pairs.Count() ? "{0}=\"{1}\"," : "{0}=\"{1}\"";
+ sb.Append(format.FormatWith(parameter.Name, parameter.Value));
+ }
+
+ var authorization = sb.ToString();
+ return authorization;
+ }
+
+#if !SILVERLIGHT
+ public override void Request(string url, IEnumerable<HttpPostParameter> parameters, out WebException exception)
+ {
+ RecalculateProtectedResourceSignature(url);
+ base.Request(url, parameters, out exception);
+ }
+
+ public override void Request(string url, out WebException exception)
+ {
+ RecalculateProtectedResourceSignature(url);
+ url = RestoreUrlParams(url, Parameters);
+ base.Request(url, out exception);
+ }
+
+ public override void Request(string url, string key, ICache cache, out WebException exception)
+ {
+ RecalculateProtectedResourceSignature(url);
+ base.Request(url, key, cache, out exception);
+ }
+
+ public override void Request(string url, string key, ICache cache, DateTime absoluteExpiration, out WebException exception)
+ {
+ RecalculateProtectedResourceSignature(url);
+ base.Request(url, key, cache, absoluteExpiration, out exception);
+ }
+
+ public override void Request(string url, string key, ICache cache, TimeSpan slidingExpiration, out WebException exception)
+ {
+ RecalculateProtectedResourceSignature(url);
+ base.Request(url, key, cache, slidingExpiration, out exception);
+ }
+#endif
+
+#if !WindowsPhone
+ public override WebQueryAsyncResult RequestAsync(string url, IEnumerable<HttpPostParameter> parameters, object userState)
+ {
+ RecalculateProtectedResourceSignature(url);
+ return base.RequestAsync(url, parameters, userState);
+ }
+
+ public override WebQueryAsyncResult RequestAsync(string url, object userState)
+ {
+ RecalculateProtectedResourceSignature(url);
+ url = RestoreUrlParams(url, Parameters);
+ return base.RequestAsync(url, userState);
+ }
+
+ public override WebQueryAsyncResult RequestAsync(string url, string key, ICache cache, object userState)
+ {
+ RecalculateProtectedResourceSignature(url);
+ return base.RequestAsync(url, key, cache, userState);
+ }
+
+ public override WebQueryAsyncResult RequestAsync(string url, string key, ICache cache, DateTime absoluteExpiration, object userState)
+ {
+ RecalculateProtectedResourceSignature(url);
+ return base.RequestAsync(url, key, cache, absoluteExpiration, userState);
+ }
+
+ public override WebQueryAsyncResult RequestAsync(string url, string key, ICache cache, TimeSpan slidingExpiration, object userState)
+ {
+ RecalculateProtectedResourceSignature(url);
+ return base.RequestAsync(url, key, cache, slidingExpiration, userState);
+ }
+#else
+ public override void RequestAsync(string url, IEnumerable<HttpPostParameter> parameters, object userState)
+ {
+ RecalculateProtectedResourceSignature(url);
+ base.RequestAsync(url, parameters, userState);
+ }
+
+ public override void RequestAsync(string url, object userState)
+ {
+ RecalculateProtectedResourceSignature(url);
+ url = RestoreUrlParams(url, Parameters);
+ base.RequestAsync(url, userState);
+ }
+
+ public override void RequestAsync(string url, string key, ICache cache, object userState)
+ {
+ RecalculateProtectedResourceSignature(url);
+ base.RequestAsync(url, key, cache, userState);
+ }
+
+ public override void RequestAsync(string url, string key, ICache cache, DateTime absoluteExpiration, object userState)
+ {
+ RecalculateProtectedResourceSignature(url);
+ base.RequestAsync(url, key, cache, absoluteExpiration, userState);
+ }
+
+ public override void RequestAsync(string url, string key, ICache cache, TimeSpan slidingExpiration, object userState)
+ {
+ RecalculateProtectedResourceSignature(url);
+ base.RequestAsync(url, key, cache, slidingExpiration, userState);
+ }
+#endif
+
+ private string RestoreUrlParams(string url, IEnumerable<WebPair> parameters)
+ {
+ if (Method != WebMethod.Post && Method != WebMethod.Put)
+ {
+ var builder = new StringBuilder();
+ var first = true;
+ foreach (var param in parameters.Where(p => !p.Name.ToLower().StartsWith("oauth_")))
+ {
+ builder.Append(first ? "?" : "&");
+ first = false;
+ builder.Append(param.Name).Append('=').Append(param.Value);
+ }
+ url = url + builder;
+ }
+ return url;
+ }
+
+ private void RecalculateProtectedResourceSignature(string url)
+ {
+ if(!_recalculate)
+ {
+ _recalculate = true;
+ return; // <-- More efficient for unrecycled queries
+ }
+
+ var info = (OAuthWebQueryInfo) Info;
+
+ if(!info.ClientUsername.IsNullOrBlank() || !info.ClientPassword.IsNullOrBlank())
+ {
+ // Not a protected resource request
+ return;
+ }
+
+ if(!string.IsNullOrEmpty(info.Verifier))
+ {
+ // This is an access token request
+ return;
+ }
+
+ var oauth = new OAuthWorkflow
+ {
+ ConsumerKey = info.ConsumerKey,
+ ConsumerSecret = info.ConsumerSecret,
+ Token = info.Token,
+ TokenSecret = info.TokenSecret,
+ ClientUsername = info.ClientUsername,
+ ClientPassword = info.ClientPassword,
+ SignatureMethod = info.SignatureMethod.FromRequestValue(),
+ ParameterHandling = ParameterHandling,
+ CallbackUrl = info.Callback,
+ Verifier = info.Verifier
+ };
+
+ // [DC]: Add any non-oauth parameters back into the signature hash
+ var parameters = new WebParameterCollection();
+ var nonAuthParameters = Parameters.Where(p => !p.Name.StartsWith("oauth_"));
+ parameters.AddRange(nonAuthParameters);
+
+ // [DC]: Don't escape parameters again when calcing the signature
+ Info = oauth.BuildProtectedResourceInfo(Method, parameters, url);
+
+ // [DC]: Add any non-oauth parameters back into parameter bag
+ Parameters = ParseInfoParameters();
+ Parameters.AddRange(nonAuthParameters);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using Hammock.Attributes.Specialized;
+using Hammock.Web;
+
+namespace Hammock.Authentication.OAuth
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class OAuthWebQueryInfo : IWebQueryInfo
+ {
+ [Parameter("oauth_consumer_key")]
+ public virtual string ConsumerKey { get; set; }
+
+ [Parameter("oauth_token")]
+ public virtual string Token { get; set; }
+
+ [Parameter("oauth_nonce")]
+ public virtual string Nonce { get; set; }
+
+ [Parameter("oauth_timestamp")]
+ public virtual string Timestamp { get; set; }
+
+ [Parameter("oauth_signature_method")]
+ public virtual string SignatureMethod { get; set; }
+
+ [Parameter("oauth_signature")]
+ public virtual string Signature { get; set; }
+
+ [Parameter("oauth_version")]
+ public virtual string Version { get; set; }
+
+ [Parameter("oauth_callback")]
+ public virtual string Callback { get; set; }
+
+ [Parameter("oauth_verifier")]
+ public virtual string Verifier { get; set; }
+
+ [Parameter("x_auth_mode")]
+ public virtual string ClientMode { get; set; }
+
+ [Parameter("x_auth_username")]
+ public virtual string ClientUsername { get; set; }
+
+ [Parameter("x_auth_password")]
+ public virtual string ClientPassword { get; set; }
+
+ [UserAgent]
+ public virtual string UserAgent { get; set; }
+
+ public virtual WebMethod WebMethod { get; set; }
+
+ public virtual OAuthParameterHandling ParameterHandling { get; set; }
+
+ public virtual OAuthSignatureTreatment SignatureTreatment { get; set; }
+
+ internal virtual string ConsumerSecret { get; set; }
+
+ internal virtual string TokenSecret { get; set; }
+
+ internal virtual bool FirstUse { get; set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using Hammock.Extensions;
+using Hammock.Web;
+#if !SILVERLIGHT && !MonoTouch &&!NETCF
+using System.Web;
+#endif
+
+#if ClientProfiles
+using System.Compat.Web;
+#endif
+
+namespace Hammock.Authentication.OAuth
+{
+ /// <summary>
+ /// A class to encapsulate OAuth authentication flow.
+ /// <seealso cref="http://oauth.net/core/1.0#anchor9"/>
+ /// </summary>
+ public class OAuthWorkflow
+ {
+ public virtual string Version { get; set; }
+ public virtual string ConsumerKey { get; set; }
+ public virtual string ConsumerSecret { get; set; }
+ public virtual string Token { get; set; }
+ public virtual string TokenSecret { get; set; }
+ public virtual string CallbackUrl { get; set; }
+ public virtual string Verifier { get; set; }
+ public virtual string SessionHandle { get; set; }
+
+ public virtual OAuthSignatureMethod SignatureMethod { get; set; }
+ public virtual OAuthSignatureTreatment SignatureTreatment { get; set; }
+ public virtual OAuthParameterHandling ParameterHandling { get; set; }
+
+ public virtual string ClientUsername { get; set; }
+ public virtual string ClientPassword { get; set; }
+
+ /// <seealso cref="http://oauth.net/core/1.0#request_urls"/>
+ public virtual string RequestTokenUrl { get; set; }
+
+ /// <seealso cref="http://oauth.net/core/1.0#request_urls"/>
+ public virtual string AccessTokenUrl { get; set; }
+
+ /// <seealso cref="http://oauth.net/core/1.0#request_urls"/>
+ public virtual string AuthorizationUrl { get; set; }
+
+ /// <summary>
+ /// Generates a <see cref="OAuthWebQueryInfo"/> instance to pass to an
+ /// <see cref="OAuthWebQuery" /> for the purpose of requesting an
+ /// unauthorized request token.
+ /// </summary>
+ /// <param name="method">The HTTP method for the intended request</param>
+ /// <seealso cref="http://oauth.net/core/1.0#anchor9"/>
+ /// <returns></returns>
+ public OAuthWebQueryInfo BuildRequestTokenInfo(WebMethod method)
+ {
+ return BuildRequestTokenInfo(method, null);
+ }
+
+ public OAuthWorkflow()
+ {
+
+ }
+
+ /// <summary>
+ /// Creates a new instance of <see cref="OAuthWorkflow" /> using
+ /// an <see cref="OAuthCredentials" /> instance.
+ /// </summary>
+ /// <param name="credentials">The credentials to copy</param>
+ public OAuthWorkflow(OAuthCredentials credentials)
+ {
+ InitializeFromCredentials(credentials);
+ }
+
+ private void InitializeFromCredentials(OAuthCredentials credentials)
+ {
+ ConsumerKey = credentials.ConsumerKey;
+ ConsumerSecret = credentials.ConsumerSecret;
+ ParameterHandling = credentials.ParameterHandling;
+ SignatureMethod = credentials.SignatureMethod;
+ SignatureTreatment = credentials.SignatureTreatment;
+ Token = credentials.Token;
+ TokenSecret = credentials.TokenSecret;
+ Verifier = credentials.Verifier;
+ ClientUsername = credentials.ClientUsername;
+ ClientPassword = credentials.ClientPassword;
+ CallbackUrl = credentials.CallbackUrl;
+ Version = credentials.Version;
+ SessionHandle = credentials.SessionHandle;
+ }
+
+ /// <summary>
+ /// Generates a <see cref="OAuthWebQueryInfo"/> instance to pass to an
+ /// <see cref="OAuthWebQuery" /> for the purpose of requesting an
+ /// unauthorized request token.
+ /// </summary>
+ /// <param name="method">The HTTP method for the intended request</param>
+ /// <param name="parameters">Any existing, non-OAuth query parameters desired in the request</param>
+ /// <seealso cref="http://oauth.net/core/1.0#anchor9"/>
+ /// <returns></returns>
+ public virtual OAuthWebQueryInfo BuildRequestTokenInfo(WebMethod method, WebParameterCollection parameters)
+ {
+ ValidateTokenRequestState();
+
+ if (parameters == null)
+ {
+ parameters = new WebParameterCollection();
+ }
+
+ var timestamp = OAuthTools.GetTimestamp();
+ var nonce = OAuthTools.GetNonce();
+
+ AddAuthParameters(parameters, timestamp, nonce);
+
+ var signatureBase = OAuthTools.ConcatenateRequestElements(method, RequestTokenUrl, parameters);
+ var signature = OAuthTools.GetSignature(SignatureMethod, SignatureTreatment, signatureBase, ConsumerSecret);
+
+ var info = new OAuthWebQueryInfo
+ {
+ WebMethod = method,
+ ParameterHandling = ParameterHandling,
+ ConsumerKey = ConsumerKey,
+ SignatureMethod = SignatureMethod.ToRequestValue(),
+ SignatureTreatment = SignatureTreatment,
+ Signature = signature,
+ Timestamp = timestamp,
+ Nonce = nonce,
+ Version = Version,
+ Callback = OAuthTools.UrlEncodeRelaxed(CallbackUrl ?? ""),
+ UserAgent = "Hammock",
+ TokenSecret = TokenSecret,
+ ConsumerSecret = ConsumerSecret
+ };
+
+ return info;
+ }
+
+ /// <summary>
+ /// Generates a <see cref="OAuthWebQueryInfo"/> instance to pass to an
+ /// <see cref="OAuthWebQuery" /> for the purpose of exchanging a request token
+ /// for an access token authorized by the user at the Service Provider site.
+ /// </summary>
+ /// <param name="method">The HTTP method for the intended request</param>
+ /// <seealso cref="http://oauth.net/core/1.0#anchor9"/>
+ public virtual OAuthWebQueryInfo BuildAccessTokenInfo(WebMethod method)
+ {
+ return BuildAccessTokenInfo(method, null);
+ }
+
+ /// <summary>
+ /// Generates a <see cref="OAuthWebQueryInfo"/> instance to pass to an
+ /// <see cref="OAuthWebQuery" /> for the purpose of exchanging a request token
+ /// for an access token authorized by the user at the Service Provider site.
+ /// </summary>
+ /// <param name="method">The HTTP method for the intended request</param>
+ /// <seealso cref="http://oauth.net/core/1.0#anchor9"/>
+ /// <param name="parameters">Any existing, non-OAuth query parameters desired in the request</param>
+ public virtual OAuthWebQueryInfo BuildAccessTokenInfo(WebMethod method, WebParameterCollection parameters)
+ {
+ ValidateAccessRequestState();
+
+ if (parameters == null)
+ {
+ parameters = new WebParameterCollection();
+ }
+
+ var uri = new Uri(AccessTokenUrl);
+ var timestamp = OAuthTools.GetTimestamp();
+ var nonce = OAuthTools.GetNonce();
+
+ AddAuthParameters(parameters, timestamp, nonce);
+
+ var signatureBase = OAuthTools.ConcatenateRequestElements(method, uri.ToString(), parameters);
+ var signature = OAuthTools.GetSignature(SignatureMethod, SignatureTreatment, signatureBase, ConsumerSecret, TokenSecret);
+
+ var info = new OAuthWebQueryInfo
+ {
+ WebMethod = method,
+ ParameterHandling = ParameterHandling,
+ ConsumerKey = ConsumerKey,
+ Token = Token,
+ SignatureMethod = SignatureMethod.ToRequestValue(),
+ SignatureTreatment = SignatureTreatment,
+ Signature = signature,
+ Timestamp = timestamp,
+ Nonce = nonce,
+ Version = Version,
+ Verifier = Verifier,
+ Callback = CallbackUrl,
+ UserAgent = "Hammock",
+ TokenSecret = TokenSecret,
+ ConsumerSecret = ConsumerSecret,
+ };
+
+ return info;
+ }
+
+ /// <summary>
+ /// Generates a <see cref="OAuthWebQueryInfo"/> instance to pass to an
+ /// <see cref="OAuthWebQuery" /> for the purpose of exchanging user credentials
+ /// for an access token authorized by the user at the Service Provider site.
+ /// </summary>
+ /// <param name="method">The HTTP method for the intended request</param>
+ /// <seealso cref="http://tools.ietf.org/html/draft-dehora-farrell-oauth-accesstoken-creds-00#section-4"/>
+ /// <param name="parameters">Any existing, non-OAuth query parameters desired in the request</param>
+ public virtual OAuthWebQueryInfo BuildClientAuthAccessTokenInfo(WebMethod method, WebParameterCollection parameters)
+ {
+ ValidateClientAuthAccessRequestState();
+
+ if (parameters == null)
+ {
+ parameters = new WebParameterCollection();
+ }
+
+ var uri = new Uri(AccessTokenUrl);
+ var timestamp = OAuthTools.GetTimestamp();
+ var nonce = OAuthTools.GetNonce();
+
+ AddXAuthParameters(parameters, timestamp, nonce);
+
+ var signatureBase = OAuthTools.ConcatenateRequestElements(method, uri.ToString(), parameters);
+ var signature = OAuthTools.GetSignature(SignatureMethod, SignatureTreatment, signatureBase, ConsumerSecret);
+
+ var info = new OAuthWebQueryInfo
+ {
+ WebMethod = method,
+ ParameterHandling = ParameterHandling,
+ ClientMode = "client_auth",
+ ClientUsername = ClientUsername,
+ ClientPassword = ClientPassword,
+ ConsumerKey = ConsumerKey,
+ SignatureMethod = SignatureMethod.ToRequestValue(),
+ SignatureTreatment = SignatureTreatment,
+ Signature = signature,
+ Timestamp = timestamp,
+ Nonce = nonce,
+ Version = Version,
+ UserAgent = "Hammock",
+ TokenSecret = TokenSecret,
+ ConsumerSecret = ConsumerSecret
+ };
+
+ return info;
+ }
+
+ public virtual OAuthWebQueryInfo BuildProtectedResourceInfo(WebMethod method,
+ WebParameterCollection parameters,
+ string url)
+ {
+ ValidateProtectedResourceState();
+
+ if (parameters == null)
+ {
+ parameters = new WebParameterCollection();
+ }
+
+ // Include url parameters in query pool
+ var uri = new Uri(url);
+#if !SILVERLIGHT
+ var urlParameters = System.Compat.Web.HttpUtility.ParseQueryString(uri.Query);
+#else
+ var urlParameters = uri.Query.ParseQueryString();
+#endif
+
+#if !SILVERLIGHT
+ foreach (var parameter in urlParameters.AllKeys)
+#else
+ foreach (var parameter in urlParameters.Keys)
+#endif
+ {
+ switch (method)
+ {
+ case WebMethod.Post:
+ parameters.Add(new HttpPostParameter(parameter, urlParameters[parameter]));
+ break;
+ default:
+ parameters.Add(parameter, urlParameters[parameter]);
+ break;
+ }
+ }
+
+ var timestamp = OAuthTools.GetTimestamp();
+ var nonce = OAuthTools.GetNonce();
+
+ // [DC] Make a copy of the parameters so that the signature double-encode isn't used
+ var copy = new WebParameterCollection();
+ foreach(var parameter in parameters)
+ {
+ copy.Add(new WebPair(parameter.Name, parameter.Value));
+ }
+
+ AddAuthParameters(copy, timestamp, nonce);
+
+ // [DC] Escape parameters at this point; do not escape again if recalculating
+ var signatureBase = OAuthTools.ConcatenateRequestElements(method, url, copy);
+ var signature = OAuthTools.GetSignature(
+ SignatureMethod, SignatureTreatment, signatureBase, ConsumerSecret, TokenSecret
+ );
+
+ var info = new OAuthWebQueryInfo
+ {
+ WebMethod = method,
+ ParameterHandling = ParameterHandling,
+ ConsumerKey = ConsumerKey,
+ Token = Token,
+ SignatureMethod = SignatureMethod.ToRequestValue(),
+ SignatureTreatment = SignatureTreatment,
+ Signature = signature,
+ Timestamp = timestamp,
+ Nonce = nonce,
+ Version = Version ?? "1.0",
+ Callback = CallbackUrl,
+ UserAgent = "Hammock",
+ ConsumerSecret = ConsumerSecret,
+ TokenSecret = TokenSecret
+ };
+
+ return info;
+ }
+
+ private void ValidateTokenRequestState()
+ {
+ if (RequestTokenUrl.IsNullOrBlank())
+ {
+ throw new ArgumentException("You must specify a request token URL");
+ }
+
+ if (ConsumerKey.IsNullOrBlank())
+ {
+ throw new ArgumentException("You must specify a consumer key");
+ }
+
+ if (ConsumerSecret.IsNullOrBlank())
+ {
+ throw new ArgumentException("You must specify a consumer secret");
+ }
+ }
+
+ private void ValidateAccessRequestState()
+ {
+ if (AccessTokenUrl.IsNullOrBlank())
+ {
+ throw new ArgumentException("You must specify an access token URL");
+ }
+
+ if (ConsumerKey.IsNullOrBlank())
+ {
+ throw new ArgumentException("You must specify a consumer key");
+ }
+
+ if (ConsumerSecret.IsNullOrBlank())
+ {
+ throw new ArgumentException("You must specify a consumer secret");
+ }
+
+ if (Token.IsNullOrBlank())
+ {
+ throw new ArgumentException("You must specify a token");
+ }
+ }
+
+ private void ValidateClientAuthAccessRequestState()
+ {
+ if (AccessTokenUrl.IsNullOrBlank())
+ {
+ throw new ArgumentException("You must specify an access token URL");
+ }
+
+ if (ConsumerKey.IsNullOrBlank())
+ {
+ throw new ArgumentException("You must specify a consumer key");
+ }
+
+ if (ConsumerSecret.IsNullOrBlank())
+ {
+ throw new ArgumentException("You must specify a consumer secret");
+ }
+
+ if (ClientUsername.IsNullOrBlank() || ClientPassword.IsNullOrBlank())
+ {
+ throw new ArgumentException("You must specify user credentials");
+ }
+ }
+
+ private void ValidateProtectedResourceState()
+ {
+ if (ConsumerKey.IsNullOrBlank())
+ {
+ throw new ArgumentException("You must specify a consumer key");
+ }
+
+ if (ConsumerSecret.IsNullOrBlank())
+ {
+ throw new ArgumentException("You must specify a consumer secret");
+ }
+
+ /*
+ if (Token.IsNullOrBlank())
+ {
+ throw new ArgumentException("You must specify a token");
+ }
+
+ if (TokenSecret.IsNullOrBlank())
+ {
+ throw new ArgumentException("You must specify a token secret");
+ }
+ */
+ }
+
+ private void AddAuthParameters(ICollection<WebPair> parameters, string timestamp, string nonce)
+ {
+ var authParameters = new WebParameterCollection
+ {
+ new WebPair("oauth_consumer_key", ConsumerKey),
+ new WebPair("oauth_nonce", nonce),
+ new WebPair("oauth_signature_method", SignatureMethod.ToRequestValue()),
+ new WebPair("oauth_timestamp", timestamp),
+ new WebPair("oauth_version", Version ?? "1.0")
+ };
+
+ if (!Token.IsNullOrBlank())
+ {
+ authParameters.Add(new WebPair("oauth_token", Token));
+ }
+
+ if (!CallbackUrl.IsNullOrBlank())
+ {
+ authParameters.Add(new WebPair("oauth_callback", CallbackUrl));
+ }
+
+ if (!Verifier.IsNullOrBlank())
+ {
+ authParameters.Add(new WebPair("oauth_verifier", Verifier));
+ }
+
+ if(!SessionHandle.IsNullOrBlank())
+ {
+ authParameters.Add(new WebPair("oauth_session_handle", SessionHandle));
+ }
+
+ foreach (var authParameter in authParameters)
+ {
+ parameters.Add(authParameter);
+ }
+ }
+
+ private void AddXAuthParameters(ICollection<WebPair> parameters, string timestamp, string nonce)
+ {
+ var authParameters = new WebParameterCollection
+ {
+ new WebPair("x_auth_username", ClientUsername),
+ new WebPair("x_auth_password", ClientPassword),
+ new WebPair("x_auth_mode", "client_auth"),
+ new WebPair("oauth_consumer_key", ConsumerKey),
+ new WebPair("oauth_signature_method", SignatureMethod.ToRequestValue()),
+ new WebPair("oauth_timestamp", timestamp),
+ new WebPair("oauth_nonce", nonce),
+ new WebPair("oauth_version", Version ?? "1.0")
+ };
+
+ foreach (var authParameter in authParameters)
+ {
+ parameters.Add(authParameter);
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<ClassDiagram MajorVersion="1" MinorVersion="1">
+ <Class Name="Hammock.Authentication.OAuth.OAuthCredentials" BaseTypeListCollapsed="true">
+ <Position X="3.75" Y="2" Width="1.75" />
+ <TypeIdentifier>
+ <HashCode>AIAAABAAAAgQAAEAQQAAAgAAAAABIAQAAQAAAAABACQ=</HashCode>
+ <FileName>Authentication\OAuth\OAuthCredentials.cs</FileName>
+ </TypeIdentifier>
+ <ShowAsAssociation>
+ <Property Name="ParameterHandling" />
+ <Property Name="SignatureMethod" />
+ <Property Name="Type" />
+ </ShowAsAssociation>
+ <Lollipop Position="0.2" Collapsed="true" />
+ </Class>
+ <Class Name="Hammock.Authentication.OAuth.OAuthToken">
+ <Position X="10" Y="0.5" Width="1.75" />
+ <TypeIdentifier>
+ <HashCode>AAAAQAAAAAAAAAAAAAAAAAgACAAAIAAAAAAAAAABAAA=</HashCode>
+ <FileName>Authentication\OAuth\OAuthToken.cs</FileName>
+ </TypeIdentifier>
+ </Class>
+ <Class Name="Hammock.Authentication.OAuth.OAuthWebQueryInfo" BaseTypeListCollapsed="true">
+ <Position X="3.5" Y="8.75" Width="2" />
+ <TypeIdentifier>
+ <HashCode>IIAAABAAgAgQAAAAAQAKAgAAAAAAIAQAAAAAAAABSCE=</HashCode>
+ <FileName>Authentication\OAuth\OAuthWebQueryInfo.cs</FileName>
+ </TypeIdentifier>
+ <ShowAsAssociation>
+ <Property Name="ParameterHandling" />
+ </ShowAsAssociation>
+ <Lollipop Position="0.2" Collapsed="true" />
+ </Class>
+ <Class Name="Hammock.Authentication.OAuth.OAuthWorkflow">
+ <Position X="7.5" Y="3.75" Width="3" />
+ <TypeIdentifier>
+ <HashCode>AIAAABACBAgAAwEAQUBAAgAAAACDIAQAAIAAAAAJgCQ=</HashCode>
+ <FileName>Authentication\OAuth\OAuthWorkflow.cs</FileName>
+ </TypeIdentifier>
+ <ShowAsAssociation>
+ <Property Name="SignatureMethod" />
+ <Property Name="ParameterHandling" />
+ </ShowAsAssociation>
+ </Class>
+ <Class Name="Hammock.OAuth.OAuthTools">
+ <Position X="7.5" Y="9.75" Width="3" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAIAQEAgAAQgQABEAAAoAgBEAAABAAgAAIAAAE=</HashCode>
+ <FileName>Authentication\OAuth\OAuthTools.cs</FileName>
+ </TypeIdentifier>
+ </Class>
+ <Class Name="Hammock.Web.Query.OAuth.OAuthWebQuery">
+ <Position X="0.5" Y="4.75" Width="2" />
+ <TypeIdentifier>
+ <HashCode>AAAgBAAAAAAAAAUAAQAAAAAAAAAAgAQQARAQAQAAABA=</HashCode>
+ <FileName>Authentication\OAuth\OAuthWebQuery.cs</FileName>
+ </TypeIdentifier>
+ <ShowAsAssociation>
+ <Property Name="ParameterHandling" />
+ </ShowAsAssociation>
+ </Class>
+ <Enum Name="Hammock.Authentication.OAuth.OAuthParameterHandling">
+ <Position X="4" Y="6" Width="2" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAA=</HashCode>
+ <FileName>Authentication\OAuth\OAuthParameterHandling.cs</FileName>
+ </TypeIdentifier>
+ </Enum>
+ <Enum Name="Hammock.Authentication.OAuth.OAuthType">
+ <Position X="0.5" Y="2" Width="2" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAQAAAAAAAgAAAAEIAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Authentication\OAuth\OAuthType.cs</FileName>
+ </TypeIdentifier>
+ </Enum>
+ <Enum Name="Hammock.OAuth.OAuthSignatureMethod">
+ <Position X="7.5" Y="0.5" Width="2" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAAAAAAAIAIAAAEAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Authentication\OAuth\OAuthSignatureMethod.cs</FileName>
+ </TypeIdentifier>
+ </Enum>
+ <Font Name="Segoe UI" Size="9" />
+</ClassDiagram>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<ClassDiagram MajorVersion="1" MinorVersion="1">
+ <Class Name="Hammock.Authentication.OAuth.OAuthCredentials">
+ <Position X="6.75" Y="2.5" Width="2.25" />
+ <TypeIdentifier>
+ <HashCode>AIAAABAAAAgQAAEAQQAAAgAAAAABIAQAAQAAAAABACQ=</HashCode>
+ <FileName>Authentication\OAuth\OAuthCredentials.cs</FileName>
+ </TypeIdentifier>
+ <Lollipop Position="0.2" />
+ </Class>
+ <Class Name="Hammock.Authentication.Basic.BasicAuthCredentials">
+ <Position X="3" Y="2.5" Width="1.75" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAQAAAAAQAAAgAAAAAAAAACAAAAAAAAAAA=</HashCode>
+ <FileName>Authentication\Basic\BasicAuthCredentials.cs</FileName>
+ </TypeIdentifier>
+ <Lollipop Position="0.2" />
+ </Class>
+ <Interface Name="Hammock.Authentication.IWebCredentials">
+ <Position X="5" Y="1.5" Width="1.5" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Authentication\IWebCredentials.cs</FileName>
+ </TypeIdentifier>
+ </Interface>
+ <Font Name="Segoe UI" Size="9" />
+</ClassDiagram>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Web;
+
+#if !ClientProfiles
+using System.Web.Caching;
+#endif
+
+namespace Hammock.Caching
+{
+#if !ClientProfiles
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class AspNetCache : IDependencyCache
+ {
+ #region IDependencyCache Members
+
+ public virtual int Count
+ {
+ get { return HttpRuntime.Cache.Count; }
+ }
+
+ public virtual void Add(string key, object value, CacheDependency dependency, DateTime absoluteExpiration,
+ TimeSpan slidingExpiration, CacheItemPriority priority,
+ CacheItemRemovedCallback onRemoveCallback)
+ {
+ HttpRuntime.Cache.Add(key, value, dependency, absoluteExpiration, Cache.NoSlidingExpiration, priority,
+ onRemoveCallback);
+ }
+
+ public virtual void Insert(string key, object value)
+ {
+ HttpRuntime.Cache.Insert(key, value);
+ }
+
+ public virtual void Insert(string key, object value, DateTime absoluteExpiration)
+ {
+ HttpRuntime.Cache.Insert(key, value, null, absoluteExpiration, Cache.NoSlidingExpiration);
+ }
+
+ public virtual void Insert(string key, object value, TimeSpan slidingExpiration)
+ {
+ HttpRuntime.Cache.Insert(key, value, null, Cache.NoAbsoluteExpiration, slidingExpiration);
+ }
+
+ public virtual void Insert(string key, object value, CacheDependency dependencies)
+ {
+ HttpRuntime.Cache.Insert(key, value, dependencies, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration);
+ }
+
+ public virtual void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration)
+ {
+ HttpRuntime.Cache.Insert(key, value, dependencies, absoluteExpiration, Cache.NoSlidingExpiration);
+ }
+
+ public virtual void Insert(string key, object value, CacheDependency dependencies, TimeSpan slidingExpiration)
+ {
+ HttpRuntime.Cache.Insert(key, value, dependencies, Cache.NoAbsoluteExpiration, slidingExpiration);
+ }
+
+ public virtual void Insert(string key, object value, CacheDependency dependencies, TimeSpan slidingExpiration,
+ CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback)
+ {
+ HttpRuntime.Cache.Insert(key, value, dependencies, Cache.NoAbsoluteExpiration, slidingExpiration, priority,
+ onRemoveCallback);
+ }
+
+ public virtual void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration,
+ CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback)
+ {
+ HttpRuntime.Cache.Insert(key, value, dependencies, absoluteExpiration, Cache.NoSlidingExpiration, priority,
+ onRemoveCallback);
+ }
+
+ public virtual void Insert(string key, object value, CacheDependency dependencies, TimeSpan slidingExpiration,
+ CacheItemUpdateCallback onUpdateCallback)
+ {
+ HttpRuntime.Cache.Insert(key, value, dependencies, Cache.NoAbsoluteExpiration, slidingExpiration,
+ onUpdateCallback);
+ }
+
+ public virtual void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration,
+ CacheItemUpdateCallback onUpdateCallback)
+ {
+ HttpRuntime.Cache.Insert(key, value, dependencies, absoluteExpiration, Cache.NoSlidingExpiration,
+ onUpdateCallback);
+ }
+
+ public virtual void Clear()
+ {
+ var keys = new List<string>();
+ var enumerator = HttpRuntime.Cache.GetEnumerator();
+
+ while (enumerator.MoveNext())
+ {
+ var key = enumerator.Key.ToString();
+ keys.Add(key);
+ }
+
+ foreach (var key in keys)
+ {
+ HttpRuntime.Cache.Remove(key);
+ }
+ }
+
+ public virtual T Get<T>(string key)
+ {
+ return (T) HttpRuntime.Cache.Get(key);
+ }
+
+ public virtual void Remove(string key)
+ {
+ HttpRuntime.Cache.Remove(key);
+ }
+
+ public virtual IEnumerable<string> Keys
+ {
+ get
+ {
+ var enumerator = HttpRuntime.Cache.GetEnumerator();
+ while (enumerator.MoveNext())
+ {
+ yield return enumerator.Key.ToString();
+ }
+ }
+ }
+
+ #endregion
+ }
+#endif
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Hammock.Caching
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public static class CacheFactory
+ {
+#if !Smartphone && !Silverlight && !ClientProfiles && !MonoTouch && !NETCF
+ public static IDependencyCache AspNetCache
+ {
+ get { return new AspNetCache(); }
+ }
+#endif
+
+ public static ICache InMemoryCache
+ {
+ get { return new SimpleCache(); }
+ }
+
+#if SILVERLIGHT
+ public static ICache IsolatedStorageCache
+ {
+ get { throw new NotImplementedException(); }
+ }
+#endif
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.Serialization;
+
+namespace Hammock.Caching
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public enum CacheMode
+ {
+#if !SILVERLIGHT && !Smartphone && !ClientProfiles && !NET20 && !MonoTouch && !NETCF
+ [EnumMember] NoExpiration,
+ [EnumMember] AbsoluteExpiration,
+ [EnumMember] SlidingExpiration
+#else
+ NoExpiration,
+ AbsoluteExpiration,
+ SlidingExpiration
+#endif
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Hammock.Caching
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class CacheOptions
+ {
+ public virtual CacheMode Mode { get; set; }
+ public virtual TimeSpan Duration { get; set; }
+ }
+}
--- /dev/null
+using System;
+
+namespace Hammock.Caching
+{
+ public interface ICache
+ {
+ void Insert(string key, object value);
+ void Insert(string key, object value, DateTime absoluteExpiration);
+ void Insert(string key, object value, TimeSpan slidingExpiration);
+
+ T Get<T>(string key);
+ void Remove(string key);
+ }
+}
\ No newline at end of file
--- /dev/null
+#if !ClientProfiles
+using System;
+using System.Web.Caching;
+
+namespace Hammock.Caching
+{
+ public interface IDependencyCache : ICache
+ {
+ void Add(string key, object value, CacheDependency dependency, DateTime absoluteExpiration,
+ TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback removedCallback);
+
+ void Insert(string key, object value, CacheDependency dependencies);
+ void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration);
+ void Insert(string key, object value, CacheDependency dependencies, TimeSpan slidingExpiration);
+
+#if !Mono
+ void Insert(string key, object value, CacheDependency dependencies, TimeSpan slidingExpiration,
+ CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback);
+
+ void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration,
+ CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback);
+
+ void Insert(string key, object value, CacheDependency dependencies, TimeSpan slidingExpiration,
+ CacheItemUpdateCallback onUpdateCallback);
+
+ void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration,
+ CacheItemUpdateCallback onUpdateCallback);
+#endif
+ void Clear();
+ }
+}
+#endif
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+
+namespace Hammock.Caching
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class SimpleCache : ICache
+ {
+ private const string NotSupportedMessage = "This simple cache does not support expiration.";
+
+ private static readonly IDictionary<string, object> _cache = new Dictionary<string, object>(0);
+
+ public virtual int Count
+ {
+ get { return _cache.Count; }
+ }
+
+ public virtual IEnumerable<string> Keys
+ {
+ get { return _cache.Keys; }
+ }
+
+ #region ICache Members
+
+ public virtual void Insert(string key, object value)
+ {
+ if (!_cache.ContainsKey(key))
+ {
+ _cache.Add(key, value);
+ }
+ else
+ {
+ _cache[key] = value;
+ }
+ }
+
+ public virtual void Insert(string key, object value, DateTime absoluteExpiration)
+ {
+ throw new NotSupportedException(NotSupportedMessage);
+ }
+
+ public virtual void Insert(string key, object value, TimeSpan slidingExpiration)
+ {
+ throw new NotSupportedException(NotSupportedMessage);
+ }
+
+ public virtual T Get<T>(string key)
+ {
+ if (_cache.ContainsKey(key))
+ {
+ return (T)_cache[key];
+ }
+ return default(T);
+ }
+
+ public virtual void Remove(string key)
+ {
+ if (_cache.ContainsKey(key))
+ {
+ _cache.Remove(key);
+ }
+ }
+
+ #endregion
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<ClassDiagram MajorVersion="1" MinorVersion="1">
+ <Class Name="Hammock.Caching.AspNetCache">
+ <Position X="6.75" Y="3.25" Width="1.75" />
+ <TypeIdentifier>
+ <HashCode>AAIAAEAAAAAAAABACAAABAQAAAAAAAAAAAAAAABAAAA=</HashCode>
+ <FileName>Caching\AspNetCache.cs</FileName>
+ </TypeIdentifier>
+ <Lollipop Position="0.2" />
+ </Class>
+ <Class Name="Hammock.Caching.SimpleCache">
+ <Position X="4" Y="3.25" Width="1.75" />
+ <Members>
+ <Field Name="_cache" Hidden="true" />
+ <Field Name="NOT_SUPPORTED_MESSAGE" Hidden="true" />
+ </Members>
+ <TypeIdentifier>
+ <HashCode>AAAAAEAAAJAAAABACAAABAQAAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Caching\SimpleCache.cs</FileName>
+ </TypeIdentifier>
+ <Lollipop Position="0.2" />
+ </Class>
+ <Class Name="Hammock.Caching.CacheOptions">
+ <Position X="9.25" Y="1.25" Width="1.5" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAIACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Caching\CacheOptions.cs</FileName>
+ </TypeIdentifier>
+ <ShowAsAssociation>
+ <Property Name="Mode" />
+ </ShowAsAssociation>
+ </Class>
+ <Interface Name="Hammock.Caching.ICache">
+ <Position X="4" Y="1.25" Width="1.75" />
+ <TypeIdentifier>
+ <HashCode>AAAAAEAAAAAAAABAAAAABAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Caching\ICache.cs</FileName>
+ </TypeIdentifier>
+ </Interface>
+ <Interface Name="Hammock.Caching.IDependencyCache">
+ <Position X="6.75" Y="1.25" Width="1.75" />
+ <TypeIdentifier>
+ <HashCode>AAIAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAA=</HashCode>
+ <FileName>Caching\IDependencyCache.cs</FileName>
+ </TypeIdentifier>
+ </Interface>
+ <Enum Name="Hammock.Caching.CacheMode">
+ <Position X="11.75" Y="1.25" Width="1.5" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAACAAAAAABAQAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Caching\CacheMode.cs</FileName>
+ </TypeIdentifier>
+ </Enum>
+ <Font Name="Segoe UI" Size="9" />
+</ClassDiagram>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Hammock.Web;
+
+#if SILVERLIGHT
+using Hammock.Silverlight.Compat;
+#else
+using System.Collections.Specialized;
+#endif
+
+namespace Hammock.Extensions
+{
+ internal static class CollectionExtensions
+ {
+ public static IEnumerable<T> AsEnumerable<T>(this T item)
+ {
+ return new[] {item};
+ }
+
+ public static IEnumerable<T> And<T>(this T item, T other)
+ {
+ return new[] {item, other};
+ }
+
+ public static IEnumerable<T> And<T>(this IEnumerable<T> items, T item)
+ {
+ foreach (var i in items)
+ {
+ yield return i;
+ }
+
+ yield return item;
+ }
+
+ public static K TryWithKey<T, K>(this IDictionary<T, K> dictionary, T key)
+ {
+ return dictionary.ContainsKey(key) ? dictionary[key] : default(K);
+ }
+
+ public static IEnumerable<T> ToEnumerable<T>(this object[] items) where T : class
+ {
+ foreach (var item in items)
+ {
+ var record = item as T;
+ yield return record;
+ }
+ }
+
+ public static void ForEach<T>(this IEnumerable<T> items, Action<T> action)
+ {
+ foreach (var item in items)
+ {
+ action(item);
+ }
+ }
+
+ public static void AddRange(this IDictionary<string, string> collection, NameValueCollection range)
+ {
+ foreach(string key in range.AllKeys)
+ {
+ collection.Add(key, range[key]);
+ }
+ }
+
+ public static string ToQueryString(this NameValueCollection collection)
+ {
+ var sb = new StringBuilder();
+ if (collection.Count > 0)
+ {
+ sb.Append("?");
+ }
+
+ var count = 0;
+ foreach(var key in collection.AllKeys)
+ {
+ sb.AppendFormat("{0}={1}", key, collection[key].UrlEncode());
+ count++;
+
+ if (count >= collection.Count)
+ {
+ continue;
+ }
+ sb.Append("&");
+ }
+ return sb.ToString();
+ }
+
+ public static string Concatenate(this WebParameterCollection collection, string separator, string spacer)
+ {
+ var sb = new StringBuilder();
+
+ var total = collection.Count;
+ var count = 0;
+
+ foreach (var item in collection)
+ {
+ sb.Append(item.Name);
+ sb.Append(separator);
+ sb.Append(item.Value);
+
+ count++;
+ if (count < total)
+ {
+ sb.Append(spacer);
+ }
+ }
+
+ return sb.ToString();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Hammock.Extensions
+{
+ internal static class FormatExtensions
+ {
+ // todo find an Invariant alternative for CE
+ public static string ToLower(this Enum type)
+ {
+ return type.ToString().ToLower();
+ }
+
+ public static string ToUpper(this Enum type)
+ {
+ return type.ToString().ToUpper();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Security.Cryptography;
+using System.Text;
+using Hammock.Authentication.OAuth;
+
+namespace Hammock.Extensions
+{
+ internal static class OAuthExtensions
+ {
+ public static string ToRequestValue(this OAuthSignatureMethod signatureMethod)
+ {
+ var value = signatureMethod.ToString().ToUpper();
+ var shaIndex = value.IndexOf("SHA1");
+ return shaIndex > -1 ? value.Insert(shaIndex, "-") : value;
+ }
+
+ public static OAuthSignatureMethod FromRequestValue(this string signatureMethod)
+ {
+ switch(signatureMethod)
+ {
+ case "HMAC-SHA1":
+ return OAuthSignatureMethod.HmacSha1;
+ case "RSA-SHA1":
+ return OAuthSignatureMethod.RsaSha1;
+ default:
+ return OAuthSignatureMethod.PlainText;
+ }
+ }
+
+ public static string HashWith(this string input, HashAlgorithm algorithm)
+ {
+ var data = Encoding.UTF8.GetBytes(input);
+ var hash = algorithm.ComputeHash(data);
+ return Convert.ToBase64String(hash);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+#if NETCF
+using System.Linq;
+#endif
+
+namespace Hammock.Extensions
+{
+ internal static class ObjectExtensions
+ {
+ public static bool Implements(this object instance, Type interfaceType)
+ {
+ return interfaceType.IsGenericTypeDefinition
+ ? instance.ImplementsGeneric(interfaceType)
+ : interfaceType.IsAssignableFrom(instance.GetType());
+ }
+
+ private static bool ImplementsGeneric(this Type type, Type targetType)
+ {
+ var interfaceTypes = type.GetInterfaces();
+ foreach (var interfaceType in interfaceTypes)
+ {
+ if (!interfaceType.IsGenericType)
+ {
+ continue;
+ }
+
+ if (interfaceType.GetGenericTypeDefinition() == targetType)
+ {
+ return true;
+ }
+ }
+
+ var baseType = type.BaseType;
+ if (baseType == null)
+ {
+ return false;
+ }
+
+ return baseType.IsGenericType
+ ? baseType.GetGenericTypeDefinition() == targetType
+ : baseType.ImplementsGeneric(targetType);
+ }
+
+ private static bool ImplementsGeneric(this object instance, Type targetType)
+ {
+ return instance.GetType().ImplementsGeneric(targetType);
+ }
+
+ public static Type GetDeclaredTypeForGeneric(this object instance, Type interfaceType)
+ {
+ return instance.GetType().GetDeclaredTypeForGeneric(interfaceType);
+ }
+
+ public static Type GetDeclaredTypeForGeneric(this Type baseType, Type interfaceType)
+ {
+ var type = default(Type);
+
+ if (baseType.ImplementsGeneric(interfaceType))
+ {
+#if NETCF
+ var generic = baseType.GetInterfaces()
+ .Single(i => i.FullName.Equals(interfaceType.FullName));
+#else
+ var generic = baseType.GetInterface(interfaceType.FullName, true);
+#endif
+ if (generic.IsGenericType)
+ {
+ var args = generic.GetGenericArguments();
+ if (args.Length == 1)
+ {
+ type = args[0];
+ }
+ }
+ }
+
+ return type;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace Hammock.Extensions
+{
+ internal static class ReflectionExtensions
+ {
+ public static IEnumerable<T> GetCustomAttributes<T>(this PropertyInfo info, bool inherit)
+ where T : class
+ {
+ var attributes = info.GetCustomAttributes(typeof (T), inherit);
+ return attributes.ToEnumerable<T>();
+ }
+
+ public static object GetValue(this object instance, string property)
+ {
+ var info = instance.GetType().GetProperty(property);
+ if (info != null)
+ {
+ var value = info.GetValue(instance, null);
+ return value;
+ }
+ return null;
+ }
+
+ public static void SetValue(this object instance, string property, object value)
+ {
+ var info = instance.GetType().GetProperty(property);
+ info.SetValue(instance, value, null);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using Hammock.Specifications;
+
+namespace Hammock.Extensions
+{
+ internal static class SpecificationExtensions
+ {
+ public static bool Satisfies<T>(this object instance) where T : ISpecification
+ {
+ var marker = Activator.CreateInstance<T>();
+ var type = typeof (ISpecification<>).MakeGenericType(instance.GetType());
+ var match = marker.Implements(type);
+
+ if (!match)
+ {
+ return false;
+ }
+
+ var method = type.GetMethod("IsSatisfiedBy");
+ var result = method.Invoke(marker, new[] {instance});
+
+ return (bool) result;
+ }
+
+ public static bool Satisfies(this object instance, ISpecification specificationType)
+ {
+ var type = typeof (ISpecification<>).MakeGenericType(instance.GetType());
+ var match = specificationType.Implements(type);
+
+ if (!match)
+ {
+ return false;
+ }
+
+ var method = type.GetMethod("IsSatisfiedBy");
+ var result = method.Invoke(specificationType, new[] {instance});
+
+ return (bool) result;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+#if SILVERLIGHT && !WindowsPhone
+using System.Windows.Browser;
+#endif
+
+#if WindowsPhone
+using System.Web;
+#endif
+
+#if !SILVERLIGHT && !MonoTouch && !NETCF
+using System.Web;
+#endif
+
+namespace Hammock.Extensions
+{
+ internal static class StringExtensions
+ {
+ public static bool IsNullOrBlank(this string value)
+ {
+ return String.IsNullOrEmpty(value) ||
+ (!String.IsNullOrEmpty(value) && value.Trim() == String.Empty);
+ }
+
+ public static bool EqualsIgnoreCase(this string left, string right)
+ {
+ return String.Compare(left, right, StringComparison.InvariantCultureIgnoreCase) == 0;
+ }
+
+ public static bool EqualsAny(this string input, params string[] args)
+ {
+ return args.Aggregate(false, (current, arg) => current | input.Equals(arg));
+ }
+
+ public static string FormatWith(this string format, params object[] args)
+ {
+ return String.Format(format, args);
+ }
+
+ public static string FormatWithInvariantCulture(this string format, params object[] args)
+ {
+ return String.Format(CultureInfo.InvariantCulture, format, args);
+ }
+
+ public static string Then(this string input, string value)
+ {
+ return String.Concat(input, value);
+ }
+
+ public static string UrlEncode(this string value)
+ {
+ // [DC] This is more correct than HttpUtility; it escapes spaces as %20, not +
+ return Uri.EscapeDataString(value);
+ }
+
+ public static string UrlDecode(this string value)
+ {
+ return Uri.UnescapeDataString(value);
+ }
+
+ public static Uri AsUri(this string value)
+ {
+ return new Uri(value);
+ }
+
+ public static string ToBase64String(this byte[] input)
+ {
+ return Convert.ToBase64String(input);
+ }
+
+ public static byte[] GetBytes(this string input)
+ {
+ return Encoding.UTF8.GetBytes(input);
+ }
+
+ public static string PercentEncode(this string s)
+ {
+ var bytes = s.GetBytes();
+ var sb = new StringBuilder();
+ foreach (var b in bytes)
+ {
+ // [DC]: Support proper encoding of special characters (\n\r\t\b)
+ if((b > 7 && b < 11) || b == 13)
+ {
+ sb.Append(string.Format("%0{0:X}", b));
+ }
+ else
+ {
+ sb.Append(string.Format("%{0:X}", b));
+ }
+ }
+ return sb.ToString();
+ }
+
+ public static IDictionary<string, string> ParseQueryString(this string query)
+ {
+ // [DC]: This method does not URL decode, and cannot handle decoded input
+ if (query.StartsWith("?")) query = query.Substring(1);
+
+ if(query.Equals(string.Empty))
+ {
+ return new Dictionary<string, string>();
+ }
+
+ var parts = query.Split(new[] { '&' });
+
+ return parts.Select(
+ part => part.Split(new[] { '=' })).ToDictionary(
+ pair => pair[0], pair => pair[1]
+ );
+ }
+
+ public static bool TryParse(this string value, out double number)
+ {
+ try
+ {
+ number = double.Parse(value);
+ return true;
+ }
+ catch
+ {
+ number = 0;
+ return false;
+ }
+ }
+
+ private const RegexOptions Options =
+#if !SILVERLIGHT && !MonoTouch
+ RegexOptions.Compiled | RegexOptions.IgnoreCase;
+#else
+ RegexOptions.IgnoreCase;
+#endif
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Hammock.Extensions
+{
+ internal static class TimeExtensions
+ {
+ public static DateTime FromNow(this TimeSpan value)
+ {
+ return new DateTime((DateTime.Now + value).Ticks);
+ }
+
+ public static DateTime FromUnixTime(this long seconds)
+ {
+ var time = new DateTime(1970, 1, 1);
+ time = time.AddSeconds(seconds);
+
+ return time.ToLocalTime();
+ }
+
+ public static long ToUnixTime(this DateTime dateTime)
+ {
+ var timeSpan = (dateTime - new DateTime(1970, 1, 1));
+ var timestamp = (long)timeSpan.TotalSeconds;
+
+ return timestamp;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+using Hammock.Attributes;
+using Hammock.Attributes.Validation;
+using Hammock.Web;
+
+namespace Hammock.Extensions
+{
+ internal static class WebExtensions
+ {
+ public static void ParseNamedAttributes<T>(this IWebQueryInfo info,
+ IEnumerable<PropertyInfo> properties,
+ IDictionary<string, string> transforms,
+ IDictionary<string, string> collection)
+ where T : Attribute, INamedAttribute
+ {
+ foreach (var property in properties)
+ {
+ var attributes = property.GetCustomAttributes<T>(true);
+
+ foreach (var attribute in attributes)
+ {
+ var value = transforms.ContainsKey(property.Name)
+ ? transforms[property.Name]
+ : property.GetValue(info, null);
+
+ if (value == null)
+ {
+ continue;
+ }
+
+ var header = value.ToString();
+ if (!header.IsNullOrBlank())
+ {
+ collection.Add(attribute.Name, header);
+ }
+ }
+ }
+ }
+
+ public static Uri UriMinusQuery(this Uri uri, out WebParameterCollection parameters)
+ {
+ var sb = new StringBuilder();
+
+ parameters = new WebParameterCollection();
+ var query = uri.Query.ParseQueryString();
+ foreach(var key in query.Keys)
+ {
+ parameters.Add(key, query[key].UrlDecode());
+ }
+
+ var port = uri.Scheme.Equals("http") && uri.Port != 80 ||
+ uri.Scheme.Equals("https") && uri.Port != 443 ?
+ ":" + uri.Port : "";
+
+ sb.Append(uri.Scheme)
+ .Append("://")
+ .Append(uri.Host)
+ .Append(port)
+ .Append(uri.AbsolutePath);
+
+ return new Uri(sb.ToString());
+ }
+
+ public static string ToBasicAuthorizationHeader(string username, string password)
+ {
+ var token = "{0}:{1}".FormatWith(username, password).GetBytes().ToBase64String();
+ return "Basic {0}".FormatWith(token);
+ }
+
+ public static void ParseValidationAttributes(this IWebQueryInfo info,
+ IEnumerable<PropertyInfo> properties,
+ IDictionary<string, string> collection)
+ {
+ foreach (var property in properties)
+ {
+ var attributes = property.GetCustomAttributes<ValidationAttribute>(true);
+
+ foreach (var attribute in attributes)
+ {
+ // Support multiple transforms
+ var value = collection.ContainsKey(property.Name)
+ ? collection[property.Name]
+ : property.GetValue(info, null);
+
+ var transformed = attribute.TransformValue(property, value);
+ if (transformed.IsNullOrBlank())
+ {
+ continue;
+ }
+
+ if(collection.ContainsKey(property.Name))
+ {
+ collection[property.Name] = transformed;
+ }
+ else
+ {
+ collection.Add(property.Name, transformed);
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{6679078A-C585-4CB6-96E9-908DBDAA2716}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Hammock</RootNamespace>
+ <AssemblyName>Hammock</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <SignAssembly>true</SignAssembly>
+ <AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>3.5</OldToolsVersion>
+ <UpgradeBackupLocation />
+ <PublishUrl>publish\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Disk</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <IsWebBootstrapper>false</IsWebBootstrapper>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ <TargetFrameworkProfile>
+ </TargetFrameworkProfile>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\bin\lib\3.5\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;NET35</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\bin\lib\net35\</OutputPath>
+ <DefineConstants>TRACE;NET35</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Mono|AnyCPU' ">
+ <OutputPath>..\..\..\bin\mono\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <Optimize>true</Optimize>
+ <DebugType>pdbonly</DebugType>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+ <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Runtime.Serialization">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Security" />
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.ServiceModel.Web">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Web" />
+ <Reference Include="System.Web.Extensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Authentication\IWebCredentials.cs" />
+ <Compile Include="Extensions\OAuthExtensions.cs" />
+ <Compile Include="Mono\HttpUtility.cs" />
+ <Compile Include="Mono\WebHeaderCollection.cs" />
+ <Compile Include="Serialization\DefaultJsonSerializer.cs" />
+ <Compile Include="Serialization\JsonParser.cs" />
+ <Compile Include="Web\HttpCookieParameter.cs" />
+ <Compile Include="Web\Mocks\IMockable.cs" />
+ <Compile Include="Authentication\OAuth\OAuthToken.cs" />
+ <Compile Include="Model\PropertyChangedBase.cs" />
+ <Compile Include="Authentication\OAuth\OAuthParameterHandling.cs" />
+ <Compile Include="Authentication\OAuth\OAuthSignatureMethod.cs" />
+ <Compile Include="Authentication\OAuth\OAuthTools.cs" />
+ <Compile Include="Extensions\CollectionExtensions.cs" />
+ <Compile Include="Extensions\ObjectExtensions.cs" />
+ <Compile Include="Extensions\SpecificationExtensions.cs" />
+ <Compile Include="Extensions\StringExtensions.cs" />
+ <Compile Include="Extensions\TimeExtensions.cs" />
+ <Compile Include="Extensions\WebExtensions.cs" />
+ <Compile Include="IRestClient.cs" />
+ <Compile Include="RestClient.cs" />
+ <Compile Include="RestRequest.cs" />
+ <Compile Include="RestResponse.cs" />
+ <Compile Include="Serialization\ISerializer.cs" />
+ <Compile Include="Specifications\AndSpecification.cs" />
+ <Compile Include="Specifications\CompositeSpecificationBase.cs" />
+ <Compile Include="Specifications\ISpecification.cs" />
+ <Compile Include="Specifications\NotSpecification.cs" />
+ <Compile Include="Specifications\OrSpecification.cs" />
+ <Compile Include="Specifications\HammockSpecification.cs" />
+ <Compile Include="Validation\ValidationException.cs" />
+ <Compile Include="Attributes\Specialized\HeaderAttribute.cs" />
+ <Compile Include="Attributes\INamedAttribute.cs" />
+ <Compile Include="Attributes\Specialized\ParameterAttribute.cs" />
+ <Compile Include="Attributes\Validation\RequiredAttribute.cs" />
+ <Compile Include="Attributes\Validation\SpecificationAttribute.cs" />
+ <Compile Include="Attributes\Specialized\UserAgentAttribute.cs" />
+ <Compile Include="Attributes\Specialized\EntityAttribute.cs" />
+ <Compile Include="Caching\AspNetCache.cs" />
+ <Compile Include="Caching\CacheFactory.cs" />
+ <Compile Include="Caching\ICache.cs" />
+ <Compile Include="Extensions\ReflectionExtensions.cs" />
+ <Compile Include="Web\HttpPostParameter.cs" />
+ <Compile Include="Web\HttpPostParameterType.cs" />
+ <Compile Include="Web\Mocks\IWebResponse.cs" />
+ <Compile Include="Web\Mocks\MockHttpWebRequest.cs" />
+ <Compile Include="Web\Mocks\MockHttpWebResponse.cs" />
+ <Compile Include="Web\Pair.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Web\BasicAuthWebQuery.cs" />
+ <Compile Include="Web\GetOrDelete.cs" />
+ <Compile Include="Web\IWebQueryInfo.cs" />
+ <Compile Include="Authentication\OAuth\OAuthWorkflow.cs" />
+ <Compile Include="Authentication\OAuth\OAuthWebQuery.cs" />
+ <Compile Include="Authentication\OAuth\OAuthWebQueryInfo.cs" />
+ <Compile Include="Web\PostOrPut.cs" />
+ <Compile Include="Web\WebEntity.cs" />
+ <Compile Include="Web\WebQuery.cs" />
+ <Compile Include="Web\Triplet.cs" />
+ <Compile Include="Web\WebCallback.cs" />
+ <Compile Include="Authentication\Basic\BasicAuthCredentials.cs" />
+ <Compile Include="Web\WebMethod.cs" />
+ <Compile Include="Web\WebParameter.cs" />
+ <Compile Include="Web\WebParameterCollection.cs" />
+ <Compile Include="Web\WebQueryRequestEventArgs.cs" />
+ <Compile Include="Web\WebQueryResponseEventArgs.cs" />
+ <Compile Include="Web\WebQueryResult.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Attributes\Validation\BooleanToIntegerAttribute.cs" />
+ <Compile Include="Attributes\Validation\DateTimeFormatAttribute.cs" />
+ <Compile Include="Attributes\IValidatingAttribute.cs" />
+ <Compile Include="Attributes\Validation\ValidationAttribute.cs" />
+ <Compile Include="Authentication\OAuth\OAuthCredentials.cs" />
+ <Compile Include="Authentication\OAuth\OAuthType.cs" />
+ <Compile Include="Caching\CacheMode.cs" />
+ <Compile Include="Caching\CacheOptions.cs" />
+ <Compile Include="Caching\IDependencyCache.cs" />
+ <Compile Include="Caching\SimpleCache.cs" />
+ <Compile Include="Extensions\FormatExtensions.cs" />
+ <Compile Include="RestBase.cs" />
+ <Compile Include="RestCallback.cs" />
+ <Compile Include="Retries\ConnectionClosed.cs" />
+ <Compile Include="Retries\IRetryCondition.cs" />
+ <Compile Include="Retries\IRetryCustomCondition.cs" />
+ <Compile Include="Retries\NetworkError.cs" />
+ <Compile Include="Retries\RetryCondition.cs" />
+ <Compile Include="Retries\RetryCustomCondition.cs" />
+ <Compile Include="Retries\RetryErrorCondition.cs" />
+ <Compile Include="Retries\RetryPolicy.cs" />
+ <Compile Include="Retries\RetryResultCondition.cs" />
+ <Compile Include="Retries\Timeout.cs" />
+ <Compile Include="Serialization\HammockDataContractJsonSerializer.cs" />
+ <Compile Include="Serialization\IDeserializer.cs" />
+ <Compile Include="Serialization\HammockDataContractSerializer.cs" />
+ <Compile Include="Serialization\HammockJavaScriptSerializer.cs" />
+ <Compile Include="Serialization\HammockXmlSerializer.cs" />
+ <Compile Include="Serialization\Utf8Serializer.cs" />
+ <Compile Include="Streaming\StreamOptions.cs" />
+ <Compile Include="Tasks\IRateLimitingRule.cs" />
+ <Compile Include="Tasks\IRateLimitStatus.cs" />
+ <Compile Include="Tasks\ITaskOptions.cs" />
+ <Compile Include="Tasks\ITaskState.cs" />
+ <Compile Include="Tasks\ITimedTask.cs" />
+ <Compile Include="Tasks\RateLimitingRule.cs" />
+ <Compile Include="Tasks\RateLimitType.cs" />
+ <Compile Include="Tasks\TaskOptions.cs" />
+ <Compile Include="Tasks\TaskState.cs" />
+ <Compile Include="Tasks\TimedTask.cs" />
+ <Compile Include="Validation\ValidEmailSpecification.cs" />
+ <Compile Include="Web\Mocks\MockWebRequestFactory.cs" />
+ <Compile Include="Web\WebHeader.cs" />
+ <Compile Include="Web\WebHeaderCollection.cs" />
+ <Compile Include="Web\WebPair.cs" />
+ <Compile Include="Web\WebPairCollection.cs" />
+ <Compile Include="Web\WebQuery.Async.cs" />
+ <Compile Include="Web\WebQueryAsyncResult.cs" />
+ <None Include="Attributes\Specialized\_Specialized.cd" />
+ <None Include="Attributes\Validation\_Validation.cd" />
+ <None Include="Authentication\OAuth\_OAuth.cd" />
+ <None Include="Authentication\_Authentication.cd" />
+ <None Include="Caching\_Caching.cd" />
+ <None Include="key.snk" />
+ <None Include="Model\_Model.cd" />
+ <None Include="Retries\_Retries.cd" />
+ <None Include="Tasks\_Tasks.cd" />
+ <None Include="Web\Mocks\_Mocks.cd" />
+ <None Include="Web\_Web.cd" />
+ <None Include="_Hammock.cd" />
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+ <Visible>False</Visible>
+ <ProductName>Windows Installer 3.1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
\ No newline at end of file
--- /dev/null
+using System;
+
+#if NET40
+using System.Dynamic;
+#endif
+
+namespace Hammock
+{
+ public interface IRestClient
+ {
+#if !Silverlight
+
+#if NET40
+ RestResponse<dynamic> RequestDynamic(RestRequest request);
+#endif
+ RestResponse Request(RestRequest request);
+ RestResponse Request();
+
+ RestResponse<T> Request<T>(RestRequest request);
+ RestResponse<T> Request<T>();
+#endif
+
+#if !WindowsPhone
+ IAsyncResult BeginRequest();
+ IAsyncResult BeginRequest<T>();
+
+ IAsyncResult BeginRequest(RestRequest request, RestCallback callback);
+ IAsyncResult BeginRequest(RestRequest request, RestCallback callback, object userState);
+
+ IAsyncResult BeginRequest<T>(RestRequest request, RestCallback<T> callback);
+ IAsyncResult BeginRequest<T>(RestRequest request, RestCallback<T> callback, object userState);
+
+#if NET40
+ IAsyncResult BeginRequestDynamic();
+ IAsyncResult BeginRequestDynamic(RestRequest request, RestCallback<dynamic> callback);
+ IAsyncResult BeginRequestDynamic(RestRequest request, RestCallback<dynamic> callback, object userState);
+ RestResponse<dynamic> EndRequestDynamic(IAsyncResult result);
+#endif
+
+ IAsyncResult BeginRequest(RestRequest request);
+ IAsyncResult BeginRequest(RestRequest request, object userState);
+ IAsyncResult BeginRequest<T>(RestRequest request);
+ IAsyncResult BeginRequest<T>(RestRequest request, object userState);
+
+ IAsyncResult BeginRequest(RestCallback callback);
+ IAsyncResult BeginRequest<T>(RestCallback<T> callback);
+
+ RestResponse EndRequest(IAsyncResult result);
+ RestResponse<T> EndRequest<T>(IAsyncResult result);
+#else
+ void BeginRequest();
+ void BeginRequest<T>();
+
+ void BeginRequest(RestRequest request, RestCallback callback);
+ void BeginRequest(RestRequest request, RestCallback callback, object userState);
+
+ void BeginRequest<T>(RestRequest request, RestCallback<T> callback);
+ void BeginRequest<T>(RestRequest request, RestCallback<T> callback, object userState);
+
+ void BeginRequest(RestRequest request);
+ void BeginRequest(RestRequest request, object userState);
+ void BeginRequest<T>(RestRequest request);
+ void BeginRequest<T>(RestRequest request, object userState);
+
+ void BeginRequest(RestCallback callback);
+ void BeginRequest<T>(RestCallback<T> callback);
+#endif
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.ComponentModel;
+using System.Runtime.Serialization;
+
+namespace Hammock.Model
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+#if !Smartphone && !NET20 && !ClientProfiles && !NETCF
+ [DataContract]
+#endif
+ public class PropertyChangedBase : INotifyPropertyChanged
+ {
+ #region INotifyPropertyChanged Members
+
+#if !SILVERLIGHT
+ [field: NonSerialized]
+#endif
+ public virtual event PropertyChangedEventHandler PropertyChanged;
+
+ #endregion
+
+ public virtual void OnPropertyChanged(string propertyName)
+ {
+ if (PropertyChanged != null)
+ {
+ PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<ClassDiagram MajorVersion="1" MinorVersion="1">
+ <Class Name="Hammock.Model.PropertyChangedBase">
+ <Position X="3.75" Y="1.75" Width="2" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAIAAAAAAAgAAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Model\PropertyChangedBase.cs</FileName>
+ </TypeIdentifier>
+ <Lollipop Position="0.2" />
+ </Class>
+ <Font Name="Segoe UI" Size="9" />
+</ClassDiagram>
\ No newline at end of file
--- /dev/null
+//
+// System.Web.HttpUtility
+//
+// Authors:
+// Patrik Torstensson (Patrik.Torstensson@labs2.com)
+// Wictor Wilén (decode/encode functions) (wictor@ibizkit.se)
+// Tim Coleman (tim@timcoleman.com)
+// Gonzalo Paniagua Javier (gonzalo@ximian.com)
+//
+// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+
+using System.Collections;
+using System.Collections.Specialized;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+namespace System.Compat.Web
+{
+ public sealed class HttpUtility
+ {
+ #region Fields
+
+ private static Hashtable entities;
+ private static readonly object lock_ = new object();
+
+ #endregion // Fields
+
+ private static Hashtable Entities
+ {
+ get
+ {
+ lock (lock_)
+ {
+ if (entities == null)
+ {
+ InitEntities();
+ }
+
+ return entities;
+ }
+ }
+ }
+
+ #region Constructors
+
+ private static void InitEntities()
+ {
+ // Build the hash table of HTML entity references. This list comes
+ // from the HTML 4.01 W3C recommendation.
+ entities = new Hashtable
+ {
+ {"nbsp", '\u00A0'},
+ {"iexcl", '\u00A1'},
+ {"cent", '\u00A2'},
+ {"pound", '\u00A3'},
+ {"curren", '\u00A4'},
+ {"yen", '\u00A5'},
+ {"brvbar", '\u00A6'},
+ {"sect", '\u00A7'},
+ {"uml", '\u00A8'},
+ {"copy", '\u00A9'},
+ {"ordf", '\u00AA'},
+ {"laquo", '\u00AB'},
+ {"not", '\u00AC'},
+ {"shy", '\u00AD'},
+ {"reg", '\u00AE'},
+ {"macr", '\u00AF'},
+ {"deg", '\u00B0'},
+ {"plusmn", '\u00B1'},
+ {"sup2", '\u00B2'},
+ {"sup3", '\u00B3'},
+ {"acute", '\u00B4'},
+ {"micro", '\u00B5'},
+ {"para", '\u00B6'},
+ {"middot", '\u00B7'},
+ {"cedil", '\u00B8'},
+ {"sup1", '\u00B9'},
+ {"ordm", '\u00BA'},
+ {"raquo", '\u00BB'},
+ {"frac14", '\u00BC'},
+ {"frac12", '\u00BD'},
+ {"frac34", '\u00BE'},
+ {"iquest", '\u00BF'},
+ {"Agrave", '\u00C0'},
+ {"Aacute", '\u00C1'},
+ {"Acirc", '\u00C2'},
+ {"Atilde", '\u00C3'},
+ {"Auml", '\u00C4'},
+ {"Aring", '\u00C5'},
+ {"AElig", '\u00C6'},
+ {"Ccedil", '\u00C7'},
+ {"Egrave", '\u00C8'},
+ {"Eacute", '\u00C9'},
+ {"Ecirc", '\u00CA'},
+ {"Euml", '\u00CB'},
+ {"Igrave", '\u00CC'},
+ {"Iacute", '\u00CD'},
+ {"Icirc", '\u00CE'},
+ {"Iuml", '\u00CF'},
+ {"ETH", '\u00D0'},
+ {"Ntilde", '\u00D1'},
+ {"Ograve", '\u00D2'},
+ {"Oacute", '\u00D3'},
+ {"Ocirc", '\u00D4'},
+ {"Otilde", '\u00D5'},
+ {"Ouml", '\u00D6'},
+ {"times", '\u00D7'},
+ {"Oslash", '\u00D8'},
+ {"Ugrave", '\u00D9'},
+ {"Uacute", '\u00DA'},
+ {"Ucirc", '\u00DB'},
+ {"Uuml", '\u00DC'},
+ {"Yacute", '\u00DD'},
+ {"THORN", '\u00DE'},
+ {"szlig", '\u00DF'},
+ {"agrave", '\u00E0'},
+ {"aacute", '\u00E1'},
+ {"acirc", '\u00E2'},
+ {"atilde", '\u00E3'},
+ {"auml", '\u00E4'},
+ {"aring", '\u00E5'},
+ {"aelig", '\u00E6'},
+ {"ccedil", '\u00E7'},
+ {"egrave", '\u00E8'},
+ {"eacute", '\u00E9'},
+ {"ecirc", '\u00EA'},
+ {"euml", '\u00EB'},
+ {"igrave", '\u00EC'},
+ {"iacute", '\u00ED'},
+ {"icirc", '\u00EE'},
+ {"iuml", '\u00EF'},
+ {"eth", '\u00F0'},
+ {"ntilde", '\u00F1'},
+ {"ograve", '\u00F2'},
+ {"oacute", '\u00F3'},
+ {"ocirc", '\u00F4'},
+ {"otilde", '\u00F5'},
+ {"ouml", '\u00F6'},
+ {"divide", '\u00F7'},
+ {"oslash", '\u00F8'},
+ {"ugrave", '\u00F9'},
+ {"uacute", '\u00FA'},
+ {"ucirc", '\u00FB'},
+ {"uuml", '\u00FC'},
+ {"yacute", '\u00FD'},
+ {"thorn", '\u00FE'},
+ {"yuml", '\u00FF'},
+ {"fnof", '\u0192'},
+ {"Alpha", '\u0391'},
+ {"Beta", '\u0392'},
+ {"Gamma", '\u0393'},
+ {"Delta", '\u0394'},
+ {"Epsilon", '\u0395'},
+ {"Zeta", '\u0396'},
+ {"Eta", '\u0397'},
+ {"Theta", '\u0398'},
+ {"Iota", '\u0399'},
+ {"Kappa", '\u039A'},
+ {"Lambda", '\u039B'},
+ {"Mu", '\u039C'},
+ {"Nu", '\u039D'},
+ {"Xi", '\u039E'},
+ {"Omicron", '\u039F'},
+ {"Pi", '\u03A0'},
+ {"Rho", '\u03A1'},
+ {"Sigma", '\u03A3'},
+ {"Tau", '\u03A4'},
+ {"Upsilon", '\u03A5'},
+ {"Phi", '\u03A6'},
+ {"Chi", '\u03A7'},
+ {"Psi", '\u03A8'},
+ {"Omega", '\u03A9'},
+ {"alpha", '\u03B1'},
+ {"beta", '\u03B2'},
+ {"gamma", '\u03B3'},
+ {"delta", '\u03B4'},
+ {"epsilon", '\u03B5'},
+ {"zeta", '\u03B6'},
+ {"eta", '\u03B7'},
+ {"theta", '\u03B8'},
+ {"iota", '\u03B9'},
+ {"kappa", '\u03BA'},
+ {"lambda", '\u03BB'},
+ {"mu", '\u03BC'},
+ {"nu", '\u03BD'},
+ {"xi", '\u03BE'},
+ {"omicron", '\u03BF'},
+ {"pi", '\u03C0'},
+ {"rho", '\u03C1'},
+ {"sigmaf", '\u03C2'},
+ {"sigma", '\u03C3'},
+ {"tau", '\u03C4'},
+ {"upsilon", '\u03C5'},
+ {"phi", '\u03C6'},
+ {"chi", '\u03C7'},
+ {"psi", '\u03C8'},
+ {"omega", '\u03C9'},
+ {"thetasym", '\u03D1'},
+ {"upsih", '\u03D2'},
+ {"piv", '\u03D6'},
+ {"bull", '\u2022'},
+ {"hellip", '\u2026'},
+ {"prime", '\u2032'},
+ {"Prime", '\u2033'},
+ {"oline", '\u203E'},
+ {"frasl", '\u2044'},
+ {"weierp", '\u2118'},
+ {"image", '\u2111'},
+ {"real", '\u211C'},
+ {"trade", '\u2122'},
+ {"alefsym", '\u2135'},
+ {"larr", '\u2190'},
+ {"uarr", '\u2191'},
+ {"rarr", '\u2192'},
+ {"darr", '\u2193'},
+ {"harr", '\u2194'},
+ {"crarr", '\u21B5'},
+ {"lArr", '\u21D0'},
+ {"uArr", '\u21D1'},
+ {"rArr", '\u21D2'},
+ {"dArr", '\u21D3'},
+ {"hArr", '\u21D4'},
+ {"forall", '\u2200'},
+ {"part", '\u2202'},
+ {"exist", '\u2203'},
+ {"empty", '\u2205'},
+ {"nabla", '\u2207'},
+ {"isin", '\u2208'},
+ {"notin", '\u2209'},
+ {"ni", '\u220B'},
+ {"prod", '\u220F'},
+ {"sum", '\u2211'},
+ {"minus", '\u2212'},
+ {"lowast", '\u2217'},
+ {"radic", '\u221A'},
+ {"prop", '\u221D'},
+ {"infin", '\u221E'},
+ {"ang", '\u2220'},
+ {"and", '\u2227'},
+ {"or", '\u2228'},
+ {"cap", '\u2229'},
+ {"cup", '\u222A'},
+ {"int", '\u222B'},
+ {"there4", '\u2234'},
+ {"sim", '\u223C'},
+ {"cong", '\u2245'},
+ {"asymp", '\u2248'},
+ {"ne", '\u2260'},
+ {"equiv", '\u2261'},
+ {"le", '\u2264'},
+ {"ge", '\u2265'},
+ {"sub", '\u2282'},
+ {"sup", '\u2283'},
+ {"nsub", '\u2284'},
+ {"sube", '\u2286'},
+ {"supe", '\u2287'},
+ {"oplus", '\u2295'},
+ {"otimes", '\u2297'},
+ {"perp", '\u22A5'},
+ {"sdot", '\u22C5'},
+ {"lceil", '\u2308'},
+ {"rceil", '\u2309'},
+ {"lfloor", '\u230A'},
+ {"rfloor", '\u230B'},
+ {"lang", '\u2329'},
+ {"rang", '\u232A'},
+ {"loz", '\u25CA'},
+ {"spades", '\u2660'},
+ {"clubs", '\u2663'},
+ {"hearts", '\u2665'},
+ {"diams", '\u2666'},
+ {"quot", '\u0022'},
+ {"amp", '\u0026'},
+ {"lt", '\u003C'},
+ {"gt", '\u003E'},
+ {"OElig", '\u0152'},
+ {"oelig", '\u0153'},
+ {"Scaron", '\u0160'},
+ {"scaron", '\u0161'},
+ {"Yuml", '\u0178'},
+ {"circ", '\u02C6'},
+ {"tilde", '\u02DC'},
+ {"ensp", '\u2002'},
+ {"emsp", '\u2003'},
+ {"thinsp", '\u2009'},
+ {"zwnj", '\u200C'},
+ {"zwj", '\u200D'},
+ {"lrm", '\u200E'},
+ {"rlm", '\u200F'},
+ {"ndash", '\u2013'},
+ {"mdash", '\u2014'},
+ {"lsquo", '\u2018'},
+ {"rsquo", '\u2019'},
+ {"sbquo", '\u201A'},
+ {"ldquo", '\u201C'},
+ {"rdquo", '\u201D'},
+ {"bdquo", '\u201E'},
+ {"dagger", '\u2020'},
+ {"Dagger", '\u2021'},
+ {"permil", '\u2030'},
+ {"lsaquo", '\u2039'},
+ {"rsaquo", '\u203A'},
+ {"euro", '\u20AC'}
+ };
+ }
+
+ #endregion // Constructors
+
+ #region Methods
+
+ private static readonly char[] hexChars = "0123456789abcdef".ToCharArray();
+
+ public static void HtmlAttributeEncode(string s, TextWriter output)
+ {
+ output.Write(HtmlAttributeEncode(s));
+ }
+
+ public static string HtmlAttributeEncode(string s)
+ {
+ if (null == s)
+ {
+ return null;
+ }
+
+ var needEncode = false;
+ for (var i = 0; i < s.Length; i++)
+ {
+ if (s[i] == '&' || s[i] == '"' || s[i] == '<')
+ {
+ needEncode = true;
+ break;
+ }
+ }
+
+ if (!needEncode)
+ {
+ return s;
+ }
+
+ var output = new StringBuilder();
+ var len = s.Length;
+ for (var i = 0; i < len; i++)
+ {
+ switch (s[i])
+ {
+ case '&':
+ output.Append("&");
+ break;
+ case '"':
+ output.Append(""");
+ break;
+ case '<':
+ output.Append("<");
+ break;
+ default:
+ output.Append(s[i]);
+ break;
+ }
+ }
+
+ return output.ToString();
+ }
+
+ public static string UrlDecode(string str)
+ {
+ return UrlDecode(str, Encoding.UTF8);
+ }
+
+ private static char[] GetChars(MemoryStream b, Encoding e)
+ {
+ return e.GetChars(b.GetBuffer(), 0, (int) b.Length);
+ }
+
+ public static string UrlDecode(string s, Encoding e)
+ {
+ if (null == s)
+ {
+ return null;
+ }
+
+ if (s.IndexOf('%') == -1 && s.IndexOf('+') == -1)
+ {
+ return s;
+ }
+
+ if (e == null)
+ {
+ e = Encoding.UTF8;
+ }
+
+ var output = new StringBuilder();
+ long len = s.Length;
+ var bytes = new MemoryStream();
+
+ for (var i = 0; i < len; i++)
+ {
+ if (s[i] == '%' && i + 2 < len && s[i + 1] != '%')
+ {
+ int xchar;
+ if (s[i + 1] == 'u' && i + 5 < len)
+ {
+ if (bytes.Length > 0)
+ {
+ output.Append(GetChars(bytes, e));
+ bytes.SetLength(0);
+ }
+
+ xchar = GetChar(s, i + 2, 4);
+ if (xchar != -1)
+ {
+ output.Append((char) xchar);
+ i += 5;
+ }
+ else
+ {
+ output.Append('%');
+ }
+ }
+ else if ((xchar = GetChar(s, i + 1, 2)) != -1)
+ {
+ bytes.WriteByte((byte) xchar);
+ i += 2;
+ }
+ else
+ {
+ output.Append('%');
+ }
+ continue;
+ }
+
+ if (bytes.Length > 0)
+ {
+ output.Append(GetChars(bytes, e));
+ bytes.SetLength(0);
+ }
+
+ if (s[i] == '+')
+ {
+ output.Append(' ');
+ }
+ else
+ {
+ output.Append(s[i]);
+ }
+ }
+
+ if (bytes.Length > 0)
+ {
+ output.Append(GetChars(bytes, e));
+ }
+
+ return output.ToString();
+ }
+
+ public static string UrlDecode(byte[] bytes, Encoding e)
+ {
+ return bytes == null ? null : UrlDecode(bytes, 0, bytes.Length, e);
+ }
+
+ private static int GetInt(byte b)
+ {
+ var c = (char) b;
+ if (c >= '0' && c <= '9')
+ {
+ return c - '0';
+ }
+
+ if (c >= 'a' && c <= 'f')
+ {
+ return c - 'a' + 10;
+ }
+
+ if (c >= 'A' && c <= 'F')
+ {
+ return c - 'A' + 10;
+ }
+
+ return -1;
+ }
+
+ private static int GetChar(byte[] bytes, int offset, int length)
+ {
+ var value = 0;
+ var end = length + offset;
+ for (var i = offset; i < end; i++)
+ {
+ var current = GetInt(bytes[i]);
+ if (current == -1)
+ {
+ return -1;
+ }
+ value = (value << 4) + current;
+ }
+
+ return value;
+ }
+
+ private static int GetChar(string str, int offset, int length)
+ {
+ var val = 0;
+ var end = length + offset;
+ for (var i = offset; i < end; i++)
+ {
+ var c = str[i];
+ if (c > 127)
+ {
+ return -1;
+ }
+
+ var current = GetInt((byte) c);
+ if (current == -1)
+ {
+ return -1;
+ }
+ val = (val << 4) + current;
+ }
+
+ return val;
+ }
+
+ public static string UrlDecode(byte[] bytes, int offset, int count, Encoding e)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+ if (count == 0)
+ {
+ return String.Empty;
+ }
+
+ if (bytes == null)
+ {
+ throw new ArgumentNullException("bytes");
+ }
+
+ if (offset < 0 || offset > bytes.Length)
+ {
+ throw new ArgumentOutOfRangeException("offset");
+ }
+
+ if (count < 0 || offset + count > bytes.Length)
+ {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ var output = new StringBuilder();
+ var acc = new MemoryStream();
+
+ var end = count + offset;
+ for (var i = offset; i < end; i++)
+ {
+ if (bytes[i] == '%' && i + 2 < count && bytes[i + 1] != '%')
+ {
+ int xchar;
+ if (bytes[i + 1] == (byte) 'u' && i + 5 < end)
+ {
+ if (acc.Length > 0)
+ {
+ output.Append(GetChars(acc, e));
+ acc.SetLength(0);
+ }
+ xchar = GetChar(bytes, i + 2, 4);
+ if (xchar != -1)
+ {
+ output.Append((char) xchar);
+ i += 5;
+ continue;
+ }
+ }
+ else if ((xchar = GetChar(bytes, i + 1, 2)) != -1)
+ {
+ acc.WriteByte((byte) xchar);
+ i += 2;
+ continue;
+ }
+ }
+
+ if (acc.Length > 0)
+ {
+ output.Append(GetChars(acc, e));
+ acc.SetLength(0);
+ }
+
+ if (bytes[i] == '+')
+ {
+ output.Append(' ');
+ }
+ else
+ {
+ output.Append((char) bytes[i]);
+ }
+ }
+
+ if (acc.Length > 0)
+ {
+ output.Append(GetChars(acc, e));
+ }
+
+ return output.ToString();
+ }
+
+ public static byte[] UrlDecodeToBytes(byte[] bytes)
+ {
+ return bytes == null ? null : UrlDecodeToBytes(bytes, 0, bytes.Length);
+ }
+
+ public static byte[] UrlDecodeToBytes(string str)
+ {
+ return UrlDecodeToBytes(str, Encoding.UTF8);
+ }
+
+ public static byte[] UrlDecodeToBytes(string str, Encoding e)
+ {
+ if (str == null)
+ {
+ return null;
+ }
+
+ if (e == null)
+ {
+ throw new ArgumentNullException("e");
+ }
+
+ return UrlDecodeToBytes(e.GetBytes(str));
+ }
+
+ public static byte[] UrlDecodeToBytes(byte[] bytes, int offset, int count)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+ if (count == 0)
+ {
+ return new byte[0];
+ }
+
+ var len = bytes.Length;
+ if (offset < 0 || offset >= len)
+ {
+ throw new ArgumentOutOfRangeException("offset");
+ }
+
+ if (count < 0 || offset > len - count)
+ {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ var result = new MemoryStream();
+ var end = offset + count;
+ for (var i = offset; i < end; i++)
+ {
+ var c = (char) bytes[i];
+ if (c == '+')
+ {
+ c = ' ';
+ }
+ else if (c == '%' && i < end - 2)
+ {
+ var xchar = GetChar(bytes, i + 1, 2);
+ if (xchar != -1)
+ {
+ c = (char) xchar;
+ i += 2;
+ }
+ }
+ result.WriteByte((byte) c);
+ }
+
+ return result.ToArray();
+ }
+
+ public static string UrlEncode(string str)
+ {
+ return UrlEncode(str, Encoding.UTF8);
+ }
+
+ public static string UrlEncode(string s, Encoding Enc)
+ {
+ if (s == null)
+ {
+ return null;
+ }
+
+ if (s == "")
+ {
+ return "";
+ }
+
+ var needEncode = false;
+ var len = s.Length;
+ for (var i = 0; i < len; i++)
+ {
+ var c = s[i];
+ if ((c < '0') || (c < 'A' && c > '9') || (c > 'Z' && c < 'a') || (c > 'z'))
+ {
+ if (NotEncoded(c))
+ {
+ continue;
+ }
+
+ needEncode = true;
+ break;
+ }
+ }
+
+ if (!needEncode)
+ {
+ return s;
+ }
+
+ // avoided GetByteCount call
+ var bytes = new byte[Enc.GetMaxByteCount(s.Length)];
+ var realLen = Enc.GetBytes(s, 0, s.Length, bytes, 0);
+ return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, 0, realLen), 0, realLen);
+ }
+
+ public static string UrlEncode(byte[] bytes)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ if (bytes.Length == 0)
+ {
+ return "";
+ }
+
+ return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, 0, bytes.Length), 0, bytes.Length);
+ }
+
+ public static string UrlEncode(byte[] bytes, int offset, int count)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ if (bytes.Length == 0)
+ {
+ return "";
+ }
+
+ return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, offset, count), offset, count);
+ }
+
+ public static byte[] UrlEncodeToBytes(string str)
+ {
+ return UrlEncodeToBytes(str, Encoding.UTF8);
+ }
+
+ public static byte[] UrlEncodeToBytes(string str, Encoding e)
+ {
+ if (str == null)
+ {
+ return null;
+ }
+
+ if (str == "")
+ {
+ return new byte[0];
+ }
+
+ var bytes = e.GetBytes(str);
+ return UrlEncodeToBytes(bytes, 0, bytes.Length);
+ }
+
+ public static byte[] UrlEncodeToBytes(byte[] bytes)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ if (bytes.Length == 0)
+ {
+ return new byte[0];
+ }
+
+ return UrlEncodeToBytes(bytes, 0, bytes.Length);
+ }
+
+ private static bool NotEncoded(char c)
+ {
+ return (c == '!' || c == '\'' || c == '(' || c == ')' || c == '*' || c == '-' || c == '.' || c == '_');
+ }
+
+ private static void UrlEncodeChar(char c, Stream result, bool isUnicode)
+ {
+ if (c > 255)
+ {
+ //FIXME: what happens when there is an internal error?
+ //if (!isUnicode)
+ // throw new ArgumentOutOfRangeException ("c", c, "c must be less than 256");
+ int i = c;
+
+ result.WriteByte((byte) '%');
+ result.WriteByte((byte) 'u');
+ var idx = i >> 12;
+ result.WriteByte((byte) hexChars[idx]);
+ idx = (i >> 8) & 0x0F;
+ result.WriteByte((byte) hexChars[idx]);
+ idx = (i >> 4) & 0x0F;
+ result.WriteByte((byte) hexChars[idx]);
+ idx = i & 0x0F;
+ result.WriteByte((byte) hexChars[idx]);
+ return;
+ }
+
+ if (c > ' ' && NotEncoded(c))
+ {
+ result.WriteByte((byte) c);
+ return;
+ }
+ if (c == ' ')
+ {
+ result.WriteByte((byte) '+');
+ return;
+ }
+ if ((c < '0') ||
+ (c < 'A' && c > '9') ||
+ (c > 'Z' && c < 'a') ||
+ (c > 'z'))
+ {
+ if (isUnicode && c > 127)
+ {
+ result.WriteByte((byte) '%');
+ result.WriteByte((byte) 'u');
+ result.WriteByte((byte) '0');
+ result.WriteByte((byte) '0');
+ }
+ else
+ {
+ result.WriteByte((byte) '%');
+ }
+
+ var idx = (c) >> 4;
+ result.WriteByte((byte) hexChars[idx]);
+ idx = (c) & 0x0F;
+ result.WriteByte((byte) hexChars[idx]);
+ }
+ else
+ {
+ result.WriteByte((byte) c);
+ }
+ }
+
+ public static byte[] UrlEncodeToBytes(byte[] bytes, int offset, int count)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ var len = bytes.Length;
+ if (len == 0)
+ {
+ return new byte[0];
+ }
+
+ if (offset < 0 || offset >= len)
+ {
+ throw new ArgumentOutOfRangeException("offset");
+ }
+
+ if (count < 0 || count > len - offset)
+ {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ var result = new MemoryStream(count);
+ var end = offset + count;
+ for (var i = offset; i < end; i++)
+ {
+ UrlEncodeChar((char) bytes[i], result, false);
+ }
+
+ return result.ToArray();
+ }
+
+ public static string UrlEncodeUnicode(string str)
+ {
+ if (str == null)
+ {
+ return null;
+ }
+
+ var bytes = UrlEncodeUnicodeToBytes(str);
+ return Encoding.ASCII.GetString(bytes, 0, bytes.Length);
+ }
+
+ public static byte[] UrlEncodeUnicodeToBytes(string str)
+ {
+ if (str == null)
+ {
+ return null;
+ }
+
+ if (str == "")
+ {
+ return new byte[0];
+ }
+
+ var result = new MemoryStream(str.Length);
+ foreach (var c in str)
+ {
+ UrlEncodeChar(c, result, true);
+ }
+ return result.ToArray();
+ }
+
+ /// <summary>
+ /// Decodes an HTML-encoded string and returns the decoded string.
+ /// </summary>
+ /// <param name="s">The HTML string to decode. </param>
+ /// <returns>The decoded text.</returns>
+ public static string HtmlDecode(string s)
+ {
+ if (s == null)
+ {
+ throw new ArgumentNullException("s");
+ }
+
+ if (s.IndexOf('&') == -1)
+ {
+ return s;
+ }
+
+ var entity = new StringBuilder();
+ var output = new StringBuilder();
+ var len = s.Length;
+ // 0 -> nothing,
+ // 1 -> right after '&'
+ // 2 -> between '&' and ';' but no '#'
+ // 3 -> '#' found after '&' and getting numbers
+ var state = 0;
+ var number = 0;
+ var have_trailing_digits = false;
+
+ for (var i = 0; i < len; i++)
+ {
+ var c = s[i];
+ if (state == 0)
+ {
+ if (c == '&')
+ {
+ entity.Append(c);
+ state = 1;
+ }
+ else
+ {
+ output.Append(c);
+ }
+ continue;
+ }
+
+ if (c == '&')
+ {
+ state = 1;
+ if (have_trailing_digits)
+ {
+ entity.Append(number.ToString(CultureInfo.InvariantCulture));
+ have_trailing_digits = false;
+ }
+
+ output.Append(entity.ToString());
+ entity.Length = 0;
+ entity.Append('&');
+ continue;
+ }
+
+ if (state == 1)
+ {
+ if (c == ';')
+ {
+ state = 0;
+ output.Append(entity.ToString());
+ output.Append(c);
+ entity.Length = 0;
+ }
+ else
+ {
+ number = 0;
+ state = c != '#' ? 2 : 3;
+ entity.Append(c);
+ }
+ }
+ else if (state == 2)
+ {
+ entity.Append(c);
+ if (c == ';')
+ {
+ var key = entity.ToString();
+ if (key.Length > 1 && Entities.ContainsKey(key.Substring(1, key.Length - 2)))
+ {
+ key = Entities[key.Substring(1, key.Length - 2)].ToString();
+ }
+
+ output.Append(key);
+ state = 0;
+ entity.Length = 0;
+ }
+ }
+ else if (state == 3)
+ {
+ if (c == ';')
+ {
+ if (number > 65535)
+ {
+ output.Append("&#");
+ output.Append(number.ToString(CultureInfo.InvariantCulture));
+ output.Append(";");
+ }
+ else
+ {
+ output.Append((char) number);
+ }
+ state = 0;
+ entity.Length = 0;
+ have_trailing_digits = false;
+ }
+ else if (Char.IsDigit(c))
+ {
+ number = number*10 + (c - '0');
+ have_trailing_digits = true;
+ }
+ else
+ {
+ state = 2;
+ if (have_trailing_digits)
+ {
+ entity.Append(number.ToString(CultureInfo.InvariantCulture));
+ have_trailing_digits = false;
+ }
+ entity.Append(c);
+ }
+ }
+ }
+
+ if (entity.Length > 0)
+ {
+ output.Append(entity.ToString());
+ }
+ else if (have_trailing_digits)
+ {
+ output.Append(number.ToString(CultureInfo.InvariantCulture));
+ }
+ return output.ToString();
+ }
+
+ /// <summary>
+ /// Decodes an HTML-encoded string and sends the resulting output to a TextWriter output stream.
+ /// </summary>
+ /// <param name="s">The HTML string to decode</param>
+ /// <param name="output">The TextWriter output stream containing the decoded string. </param>
+ public static void HtmlDecode(string s, TextWriter output)
+ {
+ if (s != null)
+ {
+ output.Write(HtmlDecode(s));
+ }
+ }
+
+ /// <summary>
+ /// HTML-encodes a string and returns the encoded string.
+ /// </summary>
+ /// <param name="s">The text string to encode. </param>
+ /// <returns>The HTML-encoded text.</returns>
+ public static string HtmlEncode(string s)
+ {
+ if (s == null)
+ {
+ return null;
+ }
+
+ var needEncode = false;
+ for (var i = 0; i < s.Length; i++)
+ {
+ var c = s[i];
+ if (c == '&' || c == '"' || c == '<' || c == '>' || c > 159)
+ {
+ needEncode = true;
+ break;
+ }
+ }
+
+ if (!needEncode)
+ {
+ return s;
+ }
+
+ var output = new StringBuilder();
+
+ var len = s.Length;
+ for (var i = 0; i < len; i++)
+ {
+ switch (s[i])
+ {
+ case '&':
+ output.Append("&");
+ break;
+ case '>':
+ output.Append(">");
+ break;
+ case '<':
+ output.Append("<");
+ break;
+ case '"':
+ output.Append(""");
+ break;
+ default:
+ // MS starts encoding with &# from 160 and stops at 255.
+ // We don't do that. One reason is the 65308/65310 unicode
+ // characters that look like '<' and '>'.
+#if TARGET_JVM
+ if (s [i] > 159 && s [i] < 256) {
+#else
+ if (s[i] > 159)
+ {
+#endif
+ output.Append("&#");
+ output.Append(((int) s[i]).ToString(CultureInfo.InvariantCulture));
+ output.Append(";");
+ }
+ else
+ {
+ output.Append(s[i]);
+ }
+ break;
+ }
+ }
+ return output.ToString();
+ }
+
+ /// <summary>
+ /// HTML-encodes a string and sends the resulting output to a TextWriter output stream.
+ /// </summary>
+ /// <param name="s">The string to encode. </param>
+ /// <param name="output">The TextWriter output stream containing the encoded string. </param>
+ public static void HtmlEncode(string s, TextWriter output)
+ {
+ if (s != null)
+ {
+ output.Write(HtmlEncode(s));
+ }
+ }
+
+ public static string UrlPathEncode(string s)
+ {
+ if (string.IsNullOrEmpty(s))
+ return s;
+
+ var result = new MemoryStream();
+ var length = s.Length;
+ for (var i = 0; i < length; i++)
+ {
+ UrlPathEncodeChar(s[i], result);
+ }
+
+ var bytes = result.ToArray();
+ return Encoding.ASCII.GetString(bytes, 0, bytes.Length);
+ }
+
+ private static void UrlPathEncodeChar(char c, Stream result)
+ {
+ if (c < 33 || c > 126)
+ {
+ var bIn = Encoding.UTF8.GetBytes(c.ToString());
+ for (var i = 0; i < bIn.Length; i++)
+ {
+ result.WriteByte((byte) '%');
+ var idx = bIn[i] >> 4;
+ result.WriteByte((byte) hexChars[idx]);
+ idx = bIn[i] & 0x0F;
+ result.WriteByte((byte) hexChars[idx]);
+ }
+ }
+ else if (c == ' ')
+ {
+ result.WriteByte((byte) '%');
+ result.WriteByte((byte) '2');
+ result.WriteByte((byte) '0');
+ }
+ else
+ result.WriteByte((byte) c);
+ }
+
+ public static NameValueCollection ParseQueryString(string query)
+ {
+ return ParseQueryString(query, Encoding.UTF8);
+ }
+
+ public static NameValueCollection ParseQueryString(string query, Encoding encoding)
+ {
+ if (query == null)
+ throw new ArgumentNullException("query");
+ if (encoding == null)
+ throw new ArgumentNullException("encoding");
+ if (query.Length == 0 || (query.Length == 1 && query[0] == '?'))
+ return new NameValueCollection();
+ if (query[0] == '?')
+ query = query.Substring(1);
+
+ var result = new NameValueCollection();
+ ParseQueryString(query, encoding, result);
+ return result;
+ }
+
+ internal static void ParseQueryString(string query, Encoding encoding, NameValueCollection result)
+ {
+ if (query.Length == 0)
+ {
+ return;
+ }
+
+ var decoded = HtmlDecode(query);
+ var decodedLength = decoded.Length;
+ var namePos = 0;
+ var first = true;
+ while (namePos <= decodedLength)
+ {
+ int valuePos = -1, valueEnd = -1;
+ for (var q = namePos; q < decodedLength; q++)
+ {
+ if (valuePos == -1 && decoded[q] == '=')
+ {
+ valuePos = q + 1;
+ }
+ else if (decoded[q] == '&')
+ {
+ valueEnd = q;
+ break;
+ }
+ }
+
+ if (first)
+ {
+ first = false;
+ if (decoded[namePos] == '?')
+ {
+ namePos++;
+ }
+ }
+
+ string name;
+ if (valuePos == -1)
+ {
+ name = null;
+ valuePos = namePos;
+ }
+ else
+ {
+ name = UrlDecode(decoded.Substring(namePos, valuePos - namePos - 1), encoding);
+ }
+ if (valueEnd < 0)
+ {
+ namePos = -1;
+ valueEnd = decoded.Length;
+ }
+ else
+ {
+ namePos = valueEnd + 1;
+ }
+ var value = UrlDecode(decoded.Substring(valuePos, valueEnd - valuePos), encoding);
+
+ result.Add(name, value);
+ if (namePos == -1)
+ {
+ break;
+ }
+ }
+ }
+
+ #endregion // Methods
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// System.Net.WebHeaderCollection
+//
+// Authors:
+// Lawrence Pit (loz@cable.a2000.nl)
+// Gonzalo Paniagua Javier (gonzalo@ximian.com)
+// Miguel de Icaza (miguel@novell.com)
+//
+// Copyright 2003 Ximian, Inc. (http://www.ximian.com)
+// Copyright 2007 Novell, Inc. (http://www.novell.com)
+//
+//
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Net;
+using System.Runtime.InteropServices;
+using System.Text;
+
+// See RFC 2068 par 4.2 Message Headers
+
+namespace Mono.Net
+{
+ [Serializable]
+ [ComVisible(true)]
+ public class WebHeaderCollection : NameValueCollection
+ {
+ private static readonly Hashtable _restricted;
+ private static readonly Hashtable _multiValue;
+
+ private static readonly char[] tspecials =
+ new[]
+ {
+ '(', ')', '<', '>', '@',
+ ',', ';', ':', '\\', '"',
+ '/', '[', ']', '?', '=',
+ '{', '}', ' ', '\t'
+ };
+
+ private readonly bool internallyCreated;
+
+ // Static Initializer
+
+ static WebHeaderCollection()
+ {
+ // the list of restricted header names as defined
+ // by the ms.net spec
+ _restricted = new Hashtable(StringComparer.InvariantCultureIgnoreCase)
+ {
+ {"accept", true},
+ {"connection", true},
+ {"content-length", true},
+ {"content-type", true},
+ {"date", true},
+ {"expect", true},
+ {"host", true},
+ {"if-modified-since", true},
+ {"range", true},
+ {"referer", true},
+ {"transfer-encoding", true},
+ {"user-agent", true}
+ };
+
+ // see par 14 of RFC 2068 to see which header names
+ // accept multiple values each separated by a comma
+ _multiValue = new Hashtable(StringComparer.InvariantCultureIgnoreCase)
+ {
+ {"accept", true},
+ {"accept-charset", true},
+ {"accept-encoding", true},
+ {"accept-language", true},
+ {"accept-ranges", true},
+ {"allow", true},
+ {"authorization", true},
+ {"cache-control", true},
+ {"connection", true},
+ {"content-encoding", true},
+ {"content-language", true},
+ {"expect", true},
+ {"if-match", true},
+ {"if-none-match", true},
+ {"proxy-authenticate", true},
+ {"public", true},
+ {"range", true},
+ {"transfer-encoding", true},
+ {"upgrade", true},
+ {"vary", true},
+ {"via", true},
+ {"warning", true},
+ {"www-authenticate", true},
+ {"set-cookie", true},
+ {"set-cookie2", true}
+ };
+
+ // Extra
+ }
+
+ // Constructors
+
+ public WebHeaderCollection()
+ {
+ }
+
+ internal WebHeaderCollection(bool internallyCreated)
+ {
+ this.internallyCreated = internallyCreated;
+ }
+
+ public override string[] AllKeys
+ {
+ get { return (base.AllKeys); }
+ }
+
+ public override int Count
+ {
+ get { return (base.Count); }
+ }
+
+ public override KeysCollection Keys
+ {
+ get { return (base.Keys); }
+ }
+
+ public string this[HttpRequestHeader hrh]
+ {
+ get { return Get(RequestHeaderToString(hrh)); }
+
+ set { Add(RequestHeaderToString(hrh), value); }
+ }
+
+ public string this[HttpResponseHeader hrh]
+ {
+ get { return Get(ResponseHeaderToString(hrh)); }
+
+ set { Add(ResponseHeaderToString(hrh), value); }
+ }
+
+ // Methods
+
+ public void Add(string header)
+ {
+ if (header == null)
+ throw new ArgumentNullException("header");
+ var pos = header.IndexOf(':');
+ if (pos == -1)
+ throw new ArgumentException("no colon found", "header");
+ Add(header.Substring(0, pos),
+ header.Substring(pos + 1));
+ }
+
+ public override void Add(string name, string value)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+ if (internallyCreated && IsRestricted(name))
+ throw new ArgumentException("This header must be modified with the appropiate property.");
+ AddWithoutValidate(name, value);
+ }
+
+ protected void AddWithoutValidate(string headerName, string headerValue)
+ {
+ if (!IsHeaderName(headerName))
+ throw new ArgumentException("invalid header name: " + headerName, "headerName");
+ headerValue = headerValue == null ? String.Empty : headerValue.Trim();
+ if (!IsHeaderValue(headerValue))
+ throw new ArgumentException("invalid header value: " + headerValue, "headerValue");
+ base.Add(headerName, headerValue);
+ }
+
+ public override string[] GetValues(string header)
+ {
+ if (header == null)
+ throw new ArgumentNullException("header");
+
+ var values = base.GetValues(header);
+ if (values == null || values.Length == 0)
+ return null;
+
+ /*
+ if (IsMultiValue (header)) {
+ values = GetMultipleValues (values);
+ }
+ */
+
+ return values;
+ }
+
+ public override string[] GetValues(int index)
+ {
+ var values = base.GetValues(index);
+ if (values == null || values.Length == 0)
+ {
+ return (null);
+ }
+
+ return (values);
+ }
+
+ /* Now i wonder why this is here...
+ static string [] GetMultipleValues (string [] values)
+ {
+ ArrayList mvalues = new ArrayList (values.Length);
+ StringBuilder sb = null;
+ for (int i = 0; i < values.Length; ++i) {
+ string val = values [i];
+ if (val.IndexOf (',') == -1) {
+ mvalues.Add (val);
+ continue;
+ }
+
+ if (sb == null)
+ sb = new StringBuilder ();
+
+ bool quote = false;
+ for (int k = 0; k < val.Length; k++) {
+ char c = val [k];
+ if (c == '"') {
+ quote = !quote;
+ } else if (!quote && c == ',') {
+ mvalues.Add (sb.ToString ().Trim ());
+ sb.Length = 0;
+ continue;
+ }
+ sb.Append (c);
+ }
+
+ if (sb.Length > 0) {
+ mvalues.Add (sb.ToString ().Trim ());
+ sb.Length = 0;
+ }
+ }
+
+ return (string []) mvalues.ToArray (typeof (string));
+ }
+ */
+
+ public static bool IsRestricted(string headerName)
+ {
+ if (headerName == null)
+ throw new ArgumentNullException("headerName");
+
+ if (headerName == "") // MS throw nullexception here!
+ throw new ArgumentException("empty string", "headerName");
+
+ return _restricted.ContainsKey(headerName);
+ }
+
+ public static bool IsRestricted(string headerName, bool response)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void Remove(string name)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+ if (internallyCreated && IsRestricted(name))
+ throw new ArgumentException("restricted header");
+ base.Remove(name);
+ }
+
+ public override void Set(string name, string value)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+ if (internallyCreated && IsRestricted(name))
+ throw new ArgumentException("restricted header");
+ if (!IsHeaderName(name))
+ throw new ArgumentException("invalid header name");
+ value = value == null ? String.Empty : value.Trim();
+ if (!IsHeaderValue(value))
+ throw new ArgumentException("invalid header value");
+ base.Set(name, value);
+ }
+
+ public byte[] ToByteArray()
+ {
+ return Encoding.UTF8.GetBytes(ToString());
+ }
+
+ public override string ToString()
+ {
+ var sb = new StringBuilder();
+
+ var count = base.Count;
+ for (var i = 0; i < count; i++)
+ sb.Append(GetKey(i))
+ .Append(": ")
+ .Append(Get(i))
+ .Append("\r\n");
+
+ return sb.Append("\r\n").ToString();
+ }
+
+ public override string Get(int index)
+ {
+ return (base.Get(index));
+ }
+
+ public override string Get(string name)
+ {
+ return (base.Get(name));
+ }
+
+ public override string GetKey(int index)
+ {
+ return (base.GetKey(index));
+ }
+
+ public void Add(HttpRequestHeader header, string value)
+ {
+ Add(RequestHeaderToString(header), value);
+ }
+
+ public void Remove(HttpRequestHeader header)
+ {
+ Remove(RequestHeaderToString(header));
+ }
+
+ public void Set(HttpRequestHeader header, string value)
+ {
+ Set(RequestHeaderToString(header), value);
+ }
+
+ public void Add(HttpResponseHeader header, string value)
+ {
+ Add(ResponseHeaderToString(header), value);
+ }
+
+ public void Remove(HttpResponseHeader header)
+ {
+ Remove(ResponseHeaderToString(header));
+ }
+
+ public void Set(HttpResponseHeader header, string value)
+ {
+ Set(ResponseHeaderToString(header), value);
+ }
+
+ private static string RequestHeaderToString(HttpRequestHeader value)
+ {
+ switch (value)
+ {
+ case HttpRequestHeader.CacheControl:
+ return "cache-control";
+ case HttpRequestHeader.Connection:
+ return "connection";
+ case HttpRequestHeader.Date:
+ return "date";
+ case HttpRequestHeader.KeepAlive:
+ return "keep-alive";
+ case HttpRequestHeader.Pragma:
+ return "pragma";
+ case HttpRequestHeader.Trailer:
+ return "trailer";
+ case HttpRequestHeader.TransferEncoding:
+ return "transfer-encoding";
+ case HttpRequestHeader.Upgrade:
+ return "upgrade";
+ case HttpRequestHeader.Via:
+ return "via";
+ case HttpRequestHeader.Warning:
+ return "warning";
+ case HttpRequestHeader.Allow:
+ return "allow";
+ case HttpRequestHeader.ContentLength:
+ return "content-length";
+ case HttpRequestHeader.ContentType:
+ return "content-type";
+ case HttpRequestHeader.ContentEncoding:
+ return "content-encoding";
+ case HttpRequestHeader.ContentLanguage:
+ return "content-language";
+ case HttpRequestHeader.ContentLocation:
+ return "content-location";
+ case HttpRequestHeader.ContentMd5:
+ return "content-md5";
+ case HttpRequestHeader.ContentRange:
+ return "content-range";
+ case HttpRequestHeader.Expires:
+ return "expires";
+ case HttpRequestHeader.LastModified:
+ return "last-modified";
+ case HttpRequestHeader.Accept:
+ return "accept";
+ case HttpRequestHeader.AcceptCharset:
+ return "accept-charset";
+ case HttpRequestHeader.AcceptEncoding:
+ return "accept-encoding";
+ case HttpRequestHeader.AcceptLanguage:
+ return "accept-language";
+ case HttpRequestHeader.Authorization:
+ return "authorization";
+ case HttpRequestHeader.Cookie:
+ return "cookie";
+ case HttpRequestHeader.Expect:
+ return "expect";
+ case HttpRequestHeader.From:
+ return "from";
+ case HttpRequestHeader.Host:
+ return "host";
+ case HttpRequestHeader.IfMatch:
+ return "if-match";
+ case HttpRequestHeader.IfModifiedSince:
+ return "if-modified-since";
+ case HttpRequestHeader.IfNoneMatch:
+ return "if-none-match";
+ case HttpRequestHeader.IfRange:
+ return "if-range";
+ case HttpRequestHeader.IfUnmodifiedSince:
+ return "if-unmodified-since";
+ case HttpRequestHeader.MaxForwards:
+ return "max-forwards";
+ case HttpRequestHeader.ProxyAuthorization:
+ return "proxy-authorization";
+ case HttpRequestHeader.Referer:
+ return "referer";
+ case HttpRequestHeader.Range:
+ return "range";
+ case HttpRequestHeader.Te:
+ return "te";
+ case HttpRequestHeader.Translate:
+ return "translate";
+ case HttpRequestHeader.UserAgent:
+ return "user-agent";
+ default:
+ throw new InvalidOperationException();
+ }
+ }
+
+
+ private static string ResponseHeaderToString(HttpResponseHeader value)
+ {
+ switch (value)
+ {
+ case HttpResponseHeader.CacheControl:
+ return "cache-control";
+ case HttpResponseHeader.Connection:
+ return "connection";
+ case HttpResponseHeader.Date:
+ return "date";
+ case HttpResponseHeader.KeepAlive:
+ return "keep-alive";
+ case HttpResponseHeader.Pragma:
+ return "pragma";
+ case HttpResponseHeader.Trailer:
+ return "trailer";
+ case HttpResponseHeader.TransferEncoding:
+ return "transfer-encoding";
+ case HttpResponseHeader.Upgrade:
+ return "upgrade";
+ case HttpResponseHeader.Via:
+ return "via";
+ case HttpResponseHeader.Warning:
+ return "warning";
+ case HttpResponseHeader.Allow:
+ return "allow";
+ case HttpResponseHeader.ContentLength:
+ return "content-length";
+ case HttpResponseHeader.ContentType:
+ return "content-type";
+ case HttpResponseHeader.ContentEncoding:
+ return "content-encoding";
+ case HttpResponseHeader.ContentLanguage:
+ return "content-language";
+ case HttpResponseHeader.ContentLocation:
+ return "content-location";
+ case HttpResponseHeader.ContentMd5:
+ return "content-md5";
+ case HttpResponseHeader.ContentRange:
+ return "content-range";
+ case HttpResponseHeader.Expires:
+ return "expires";
+ case HttpResponseHeader.LastModified:
+ return "last-modified";
+ case HttpResponseHeader.AcceptRanges:
+ return "accept-ranges";
+ case HttpResponseHeader.Age:
+ return "age";
+ case HttpResponseHeader.ETag:
+ return "etag";
+ case HttpResponseHeader.Location:
+ return "location";
+ case HttpResponseHeader.ProxyAuthenticate:
+ return "proxy-authenticate";
+ case HttpResponseHeader.RetryAfter:
+ return "RetryAfter";
+ case HttpResponseHeader.Server:
+ return "server";
+ case HttpResponseHeader.SetCookie:
+ return "set-cookie";
+ case HttpResponseHeader.Vary:
+ return "vary";
+ case HttpResponseHeader.WwwAuthenticate:
+ return "www-authenticate";
+ default:
+ throw new InvalidOperationException();
+ }
+ }
+
+ public override IEnumerator GetEnumerator()
+ {
+ return (base.GetEnumerator());
+ }
+
+ // Internal Methods
+
+ // With this we don't check for invalid characters in header. See bug #55994.
+ internal void SetInternal(string header)
+ {
+ var pos = header.IndexOf(':');
+ if (pos == -1)
+ throw new ArgumentException("no colon found", "header");
+
+ SetInternal(header.Substring(0, pos), header.Substring(pos + 1));
+ }
+
+ internal void SetInternal(string name, string value)
+ {
+ value = value == null ? String.Empty : value.Trim();
+ if (!IsHeaderValue(value))
+ throw new ArgumentException("invalid header value");
+
+ if (IsMultiValue(name))
+ {
+ base.Add(name, value);
+ }
+ else
+ {
+ base.Remove(name);
+ base.Set(name, value);
+ }
+ }
+
+ internal void RemoveAndAdd(string name, string value)
+ {
+ value = value == null ? String.Empty : value.Trim();
+
+ base.Remove(name);
+ base.Set(name, value);
+ }
+
+ internal void RemoveInternal(string name)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+ base.Remove(name);
+ }
+
+ internal static bool IsMultiValue(string headerName)
+ {
+ return !string.IsNullOrEmpty(headerName) && _multiValue.ContainsKey(headerName);
+ }
+
+ internal static bool IsHeaderValue(string value)
+ {
+ // TEXT any 8 bit value except CTL's (0-31 and 127)
+ // but including \r\n space and \t
+ // after a newline at least one space or \t must follow
+ // certain header fields allow comments ()
+
+ var len = value.Length;
+ for (var i = 0; i < len; i++)
+ {
+ var c = value[i];
+ if (c == 127)
+ return false;
+ if (c < 0x20 && (c != '\r' && c != '\n' && c != '\t'))
+ return false;
+ if (c == '\n' && ++i < len)
+ {
+ c = value[i];
+ if (c != ' ' && c != '\t')
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ internal static bool IsHeaderName(string name)
+ {
+ // token = 1*<any CHAR except CTLs or tspecials>
+ // tspecials = "(" | ")" | "<" | ">" | "@"
+ // | "," | ";" | ":" | "\" | <">
+ // | "/" | "[" | "]" | "?" | "="
+ // | "{" | "}" | SP | HT
+
+ if (string.IsNullOrEmpty(name))
+ return false;
+
+ var len = name.Length;
+ for (var i = 0; i < len; i++)
+ {
+ var c = name[i];
+ if (c < 0x20 || c >= 0x7f)
+ return false;
+ }
+
+ return name.IndexOfAny(tspecials) == -1;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Security;
+
+// 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("Hammock")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apitize")]
+[assembly: AssemblyProduct("Hammock")]
+[assembly: AssemblyCopyright("Copyright © Daniel Crenna and Jason Diller")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: AllowPartiallyTrustedCallers]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. RetryIf you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("f191262b-8d70-4050-89a0-c225cc13d568")]
+
+// 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 Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Text;
+using Hammock.Authentication;
+using Hammock.Caching;
+using Hammock.Model;
+using Hammock.Retries;
+using Hammock.Serialization;
+using Hammock.Tasks;
+using Hammock.Web;
+using Hammock.Streaming;
+
+#if SILVERLIGHT
+using Hammock.Silverlight.Compat;
+#else
+using System.Collections.Specialized;
+#endif
+
+namespace Hammock
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public enum QueryHandling
+ {
+ /// <summary>
+ /// Query strings present in paths are left alone.
+ /// </summary>
+ None,
+ /// <summary>
+ /// Query string pairs present in paths are added to the parameter collection,
+ /// where they are appended back in the case of GET, HEAD, DELETE, and OPTIONS, or added to the
+ /// request body in the case of POST, or PUT.
+ /// </summary>
+ AppendToParameters
+ }
+
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public abstract class RestBase : PropertyChangedBase
+ {
+ private byte[] _postContent;
+ private TaskOptions _taskOptions;
+ private RetryPolicy _retryPolicy;
+
+ public WebParameterCollection GetAllHeaders()
+ {
+ var headers = new WebParameterCollection();
+
+ var parameters = Headers.AllKeys.Select(key => new WebPair(key, Headers[key]));
+ foreach (var parameter in parameters)
+ {
+ headers.Add(parameter.Name, parameter.Value);
+ }
+
+ return headers;
+ }
+
+ protected virtual internal NameValueCollection Headers { get; set; }
+ protected virtual internal WebParameterCollection Parameters { get; set; }
+ protected virtual internal WebParameterCollection Cookies { get; set; }
+ protected virtual internal ICollection<HttpPostParameter> PostParameters { get; set; }
+ protected internal virtual bool TraceEnabled { get; set; }
+
+ protected virtual internal byte[] PostContent
+ {
+ get
+ {
+ return _postContent;
+ }
+ set
+ {
+ _postContent = value;
+ if (value != null && (Method != WebMethod.Post && Method != WebMethod.Put))
+ {
+ Method = WebMethod.Post;
+ }
+ }
+ }
+
+ public virtual Func<RestRequest, RestResponseBase, Type> GetErrorResponseEntityType { get; set; }
+ public virtual string UserAgent { get; set; }
+ public virtual WebMethod? Method { get; set; }
+ public virtual IWebCredentials Credentials { get; set; }
+ public virtual Encoding Encoding { get; set; }
+
+ protected RestBase()
+ {
+ Initialize();
+ }
+
+ private void Initialize()
+ {
+ Headers = new NameValueCollection(0);
+ Parameters = new WebParameterCollection();
+ Cookies = new WebParameterCollection(0);
+ PostParameters = new List<HttpPostParameter>(0);
+ }
+
+#if !Silverlight
+ public virtual ServicePoint ServicePoint { get; set; }
+ public virtual bool? FollowRedirects { get; set; }
+#endif
+
+ public virtual QueryHandling? QueryHandling { get; set; }
+ public virtual string Proxy { get; set; }
+ public virtual TimeSpan? Timeout { get; set; }
+ public virtual string VersionPath { get; set; }
+ public virtual ISerializer Serializer { get; set; }
+ public virtual IDeserializer Deserializer { get; set; }
+ public virtual ICache Cache { get; set; }
+ public virtual CacheOptions CacheOptions { get; set; }
+ public virtual RetryPolicy RetryPolicy
+ {
+ get { return _retryPolicy; }
+ set
+ {
+ if (_retryPolicy == value)
+ {
+ return;
+ }
+ _retryPolicy = value;
+ RetryState = new TaskState();
+ }
+ }
+
+ public virtual TaskOptions TaskOptions
+ {
+ get { return _taskOptions; }
+ set
+ {
+ if (_taskOptions == value)
+ {
+ return;
+ }
+ _taskOptions = value;
+ TaskState = new TaskState();
+ }
+ }
+
+ public virtual bool IsFirstIteration
+ {
+ get
+ {
+ if (RetryState != null)
+ {
+ return RetryState.RepeatCount == 0;
+ }
+ if (TaskState != null)
+ {
+ return TaskState.RepeatCount == 0;
+ }
+ return true;
+ }
+ }
+
+ public virtual ITaskState TaskState { get; set; }
+ public virtual ITaskState RetryState { get; set; }
+ public virtual StreamOptions StreamOptions { get; set; }
+ public virtual Func<string> CacheKeyFunction { get; set; }
+ public virtual DecompressionMethods? DecompressionMethods { get; set; }
+ public virtual IWebQueryInfo Info { get; set; }
+ public virtual string Path { get; set; }
+ public virtual object Tag { get; set; }
+
+ public virtual void AddHeader(string name, string value)
+ {
+ Headers.Add(name, value);
+ }
+
+ public virtual void AddParameter(string name, string value)
+ {
+ Parameters.Add(name, value);
+ }
+
+ public virtual void AddCookie(string name, string value)
+ {
+ Cookies.Add(new HttpCookieParameter(name, value));
+ }
+
+ public virtual void AddCookie(Uri domain, string name, string value)
+ {
+ Cookies.Add(new HttpCookieParameter(name, value) { Domain = domain });
+ }
+
+ public virtual void AddField(string name, string value)
+ {
+ var field = new HttpPostParameter(name, value);
+ PostParameters.Add(field);
+ }
+
+ public virtual void AddFile(string name, string fileName, string filePath)
+ {
+ AddFile(name, fileName, filePath, "application/octet-stream", "form-data");
+ }
+
+ public virtual void AddFile(string name, string fileName, string filePath, string contentType)
+ {
+ AddFile(name, fileName, filePath, contentType, "form-data");
+ }
+
+ public virtual void AddFile(string name, string fileName, Stream stream)
+ {
+ AddFile(name, fileName, stream, "application/octet-stream", "form-data");
+ }
+
+ public virtual void AddFile(string name, string fileName, Stream stream, string contentType)
+ {
+ AddFile(name, fileName, stream, contentType, "form-data");
+ }
+
+ public virtual void AddFile(string name, string fileName, string filePath, string contentType, string contentDisposition)
+ {
+ var parameter = HttpPostParameter.CreateFile(name, fileName, filePath, contentType, contentDisposition);
+ PostParameters.Add(parameter);
+ }
+
+ public virtual void AddFile(string name, string fileName, Stream stream, string contentType, string contentDisposition)
+ {
+ var parameter = HttpPostParameter.CreateFile(name, fileName, stream, contentType, contentDisposition);
+ PostParameters.Add(parameter);
+ }
+
+ public virtual void AddPostContent(byte[] content)
+ {
+ if (PostContent == null)
+ {
+ PostContent = content;
+ }
+ else
+ {
+ var original = PostContent.Length;
+ var current = content.Length;
+
+ var final = new byte[current + original];
+ Array.Copy(PostContent, 0, final, 0, original);
+ Array.Copy(content, 0, final, original, current);
+
+ PostContent = final;
+ }
+ }
+ }
+
+ public class RetryEventArgs : EventArgs
+ {
+ public virtual RestClient Client { get; set; }
+ public virtual RestRequest Request { get; set; }
+ }
+
+ public class FileProgressEventArgs : EventArgs
+ {
+ public virtual string FileName { get; set; }
+ public virtual long BytesWritten { get; set; }
+ public virtual long TotalBytes { get; set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Hammock
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public delegate void RestCallback(RestRequest request, RestResponse response, object userState);
+
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public delegate void RestCallback<T>(RestRequest request, RestResponse<T> response, object userState);
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+#if NET40
+using System.Dynamic;
+#endif
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Reflection;
+using System.Text;
+using System.Threading;
+using Hammock.Authentication;
+using Hammock.Caching;
+using Hammock.Extensions;
+using Hammock.Retries;
+using Hammock.Serialization;
+using Hammock.Tasks;
+using Hammock.Web;
+using Hammock.Streaming;
+using Hammock.Web.Mocks;
+
+#if SILVERLIGHT
+using Hammock.Silverlight.Compat;
+#endif
+
+namespace Hammock
+{
+#if !Silverlight
+ [Serializable]
+#endif
+ public class RestClient : RestBase, IRestClient
+ {
+ private const string MockContentType = "mockContentType";
+ private const string MockScheme = "mockScheme";
+ private const string MockProtocol = "mock";
+ private const string MockStatusDescription = "mockStatusDescription";
+ private const string MockContent = "mockContent";
+ private const string MockHttpMethod = "mockHttpMethod";
+ private const string EndStreamingContent = "END STREAMING";
+
+ public virtual string Authority { get; set; }
+
+ public virtual event EventHandler<FileProgressEventArgs> FileProgress;
+ public virtual void OnFileProgress(FileProgressEventArgs args)
+ {
+ var handler = FileProgress;
+ if (handler != null)
+ {
+ handler(this, args);
+ }
+ }
+
+ public virtual event EventHandler<RetryEventArgs> BeforeRetry;
+ public virtual void OnBeforeRetry(RetryEventArgs args)
+ {
+ var handler = BeforeRetry;
+ if (handler != null)
+ {
+ handler(this, args);
+ }
+ }
+
+#if SILVERLIGHT
+ public virtual bool HasElevatedPermissions { get; set; }
+ /// <summary>
+ /// Used to set the name of the "Accept" header used by your Silverlight proxy.
+ /// </summary>
+ public virtual string SilverlightAcceptEncodingHeader { get; set;}
+
+ /// <summary>
+ /// Used to set the name of the "User-Agent" header used by your Silverlight proxy.
+ /// </summary>
+ public virtual string SilverlightUserAgentHeader { get; set;}
+#endif
+
+#if !Silverlight
+ private bool _firstTry = true;
+#endif
+ private int _remainingRetries;
+
+ private readonly object _timedTasksLock = new object();
+ private readonly object _streamingLock = new object();
+ private WebQuery _streamQuery;
+
+ private readonly Dictionary<RestRequest, TimedTask> _tasks = new Dictionary<RestRequest, TimedTask>();
+
+#if !Silverlight
+
+#if NET40
+ public RestResponse<dynamic> RequestDynamic(RestRequest request)
+ {
+ var query = RequestImpl(request);
+
+ dynamic response = BuildResponseFromResultDynamic(request, query);
+
+ return response;
+ }
+#endif
+
+ public virtual RestResponse Request(RestRequest request)
+ {
+ var query = RequestImpl(request);
+
+ return BuildResponseFromResult(request, query);
+ }
+
+ public virtual RestResponse<T> Request<T>(RestRequest request)
+ {
+ var query = RequestImpl(request);
+
+ return BuildResponseFromResult<T>(request, query);
+ }
+
+ public RestResponse Request()
+ {
+ var query = RequestImpl(null);
+
+ return BuildResponseFromResult(null, query);
+ }
+
+ public RestResponse<T> Request<T>()
+ {
+ var query = RequestImpl(null);
+
+ return BuildResponseFromResult<T>(null, query);
+ }
+
+ private static bool _mockFactoryInitialized;
+
+ private WebQuery RequestImpl(RestRequest request)
+ {
+ Uri uri;
+ WebQuery query = null;
+ request = request ?? new RestRequest();
+
+ var retryPolicy = GetRetryPolicy(request);
+ if (_firstTry)
+ {
+ _remainingRetries = (retryPolicy != null ? retryPolicy.RetryCount : 0) + 1;
+ _firstTry = false;
+ }
+
+ while (_remainingRetries > 0)
+ {
+ request = PrepareRequest(request, out uri, out query);
+
+ var url = uri.ToString();
+
+ if (RequestExpectsMock(request))
+ {
+ if (!_mockFactoryInitialized)
+ {
+ WebRequest.RegisterPrefix(MockProtocol, new MockWebRequestFactory());
+ _mockFactoryInitialized = true;
+ }
+
+ url = BuildMockRequestUrl(request, query, url);
+ }
+
+ UpdateRetryState(request);
+
+ WebException exception;
+ if (!RequestWithCache(request, query, url, out exception) &&
+ !RequestMultiPart(request, query, url, out exception))
+ {
+ query.Request(url, out exception);
+ }
+
+ query.Result.Exception = exception;
+ var current = query.Result;
+
+ if (retryPolicy != null)
+ {
+ var retry = _remainingRetries > 0 && ShouldRetry(retryPolicy, exception, current);
+
+ if (retry)
+ {
+ _remainingRetries--;
+ if (_remainingRetries > 0)
+ {
+ query.Result = new WebQueryResult { TimesTried = GetIterationCount(request) };
+
+ OnBeforeRetry(new RetryEventArgs { Client = this, Request = request });
+ }
+ }
+ else
+ {
+ _remainingRetries = 0;
+ }
+ }
+ else
+ {
+ _remainingRetries = 0;
+ }
+ }
+
+ _firstTry = _remainingRetries == 0;
+ return query;
+ }
+
+ private RestRequest PrepareRequest(RestRequest request, out Uri uri, out WebQuery query)
+ {
+ request = request ?? new RestRequest();
+ uri = request.BuildEndpoint(this);
+ query = GetQueryFor(request, uri);
+ SetQueryMeta(request, query);
+ return request;
+ }
+
+ private bool RequestMultiPart(RestBase request, WebQuery query, string url, out WebException exception)
+ {
+ var parameters = GetPostParameters(request);
+ if (parameters == null || parameters.Count() == 0)
+ {
+ exception = null;
+ return false;
+ }
+
+ // [DC]: Default to POST if no method provided
+ query.Method = query.Method != WebMethod.Post && query.Method != WebMethod.Put ? WebMethod.Post : query.Method;
+ query.Request(url, parameters, out exception);
+ return true;
+ }
+
+ private bool RequestWithCache(RestBase request, WebQuery query, string url, out WebException exception)
+ {
+ var cache = GetCache(request);
+ if (cache == null)
+ {
+ exception = null;
+ return false;
+ }
+
+ var options = GetCacheOptions(request);
+ if (options == null)
+ {
+ exception = null;
+ return false;
+ }
+
+ // [DC]: This is currently prefixed to the full URL
+ var function = GetCacheKeyFunction(request);
+ var key = function != null ? function.Invoke() : "";
+
+ switch (options.Mode)
+ {
+ case CacheMode.NoExpiration:
+ query.Request(url, key, cache, out exception);
+ break;
+ case CacheMode.AbsoluteExpiration:
+ var expiry = options.Duration.FromNow();
+ query.Request(url, key, cache, expiry, out exception);
+ break;
+ case CacheMode.SlidingExpiration:
+ query.Request(url, key, cache, options.Duration, out exception);
+ break;
+ default:
+ throw new NotSupportedException("Unknown CacheMode");
+ }
+
+ return true;
+ }
+#endif
+ private void UpdateRepeatingRequestState(RestBase request)
+ {
+ var taskState = request.TaskState ?? TaskState;
+ if (taskState == null)
+ {
+ return;
+ }
+ taskState.RepeatCount++;
+ taskState.LastRepeat = DateTime.Now;
+ }
+
+ private void UpdateRetryState(RestBase request)
+ {
+ var retryState = request.RetryState ?? RetryState;
+ if (retryState == null)
+ {
+ return;
+ }
+
+ retryState.RepeatCount++;
+ retryState.LastRepeat = DateTime.Now;
+ }
+
+ private static bool ShouldRetry(RetryPolicy retryPolicy,
+ Exception exception,
+ WebQueryResult current)
+ {
+ var retry = false;
+ foreach (var condition in retryPolicy.RetryConditions.OfType<RetryErrorCondition>())
+ {
+ if (exception == null)
+ {
+ continue;
+ }
+ retry |= condition.RetryIf(exception);
+ }
+
+ foreach (var condition in retryPolicy.RetryConditions.OfType<RetryResultCondition>())
+ {
+ if (current == null)
+ {
+ continue;
+ }
+ retry |= condition.RetryIf(current);
+ }
+
+ foreach (var condition in retryPolicy.RetryConditions.OfType<IRetryCustomCondition>())
+ {
+ var innerType = condition.GetDeclaredTypeForGeneric(typeof(IRetryCondition<>));
+ if (innerType == null)
+ {
+ continue;
+ }
+
+ /*
+ var retryType = typeof(RetryCustomCondition<>).MakeGenericType(innerType);
+ if (retryType == null)
+ {
+ continue;
+ }
+ */
+
+ var func = condition.GetValue("ConditionFunction") as MulticastDelegate;
+ if (func == null)
+ {
+ continue;
+ }
+
+ // Call the function to find the retry evaluator
+#if !Smartphone && !NETCF
+ var t = func.DynamicInvoke(null);
+#else
+ var del = func.GetInvocationList().FirstOrDefault();
+ var t = del.Method.Invoke(func, null);
+#endif
+
+ // Invoke the retry predicate and pass the evaluator
+ var p = condition.GetValue("RetryIf");
+ var r = p.GetType().InvokeMember("Invoke",
+ BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance,
+ null, p, new[] { t });
+
+ retry |= (bool)r;
+ }
+
+ return retry;
+ }
+
+ private string BuildMockRequestUrl(RestRequest request,
+ WebQuery query,
+ string url)
+ {
+ if (url.Contains("https"))
+ {
+ url = url.Replace("https", MockProtocol);
+
+ query.Parameters.Add(MockScheme, "https");
+ }
+ if (url.Contains("http"))
+ {
+ url = url.Replace("http", MockProtocol);
+ query.Parameters.Add(MockScheme, "http");
+ }
+
+ if (request.ExpectStatusCode.HasValue)
+ {
+ query.Parameters.Add("mockStatusCode", ((int)request.ExpectStatusCode.Value).ToString());
+ if (request.ExpectStatusDescription.IsNullOrBlank())
+ {
+ query.Parameters.Add(MockStatusDescription, request.ExpectStatusCode.ToString());
+ }
+ }
+ if (!request.ExpectStatusDescription.IsNullOrBlank())
+ {
+ query.Parameters.Add(MockStatusDescription, request.ExpectStatusDescription);
+ }
+
+ query.Parameters.Add(
+ MockHttpMethod, request.Method.ToString().ToUpper()
+ );
+
+ var expectEntity = SerializeExpectEntity(request);
+ if (expectEntity != null)
+ {
+ query.Parameters.Add(MockContent, expectEntity.Content);
+ query.Parameters.Add(MockContentType, expectEntity.ContentType);
+ query.HasEntity = true; // Used with POSTs
+ }
+ else
+ {
+ if (!request.ExpectContent.IsNullOrBlank())
+ {
+ query.Parameters.Add(MockContent, request.ExpectContent);
+ query.Parameters.Add(MockContentType,
+ !request.ExpectContentType.IsNullOrBlank()
+ ? request.ExpectContentType
+ : "text/html"
+ );
+ }
+ else
+ {
+ if (!request.ExpectContentType.IsNullOrBlank())
+ {
+ query.Parameters.Add(
+ MockContentType, request.ExpectContentType
+ );
+ }
+ }
+ }
+
+ if (request.ExpectHeaders.Count > 0)
+ {
+ var names = new StringBuilder();
+ var values = new StringBuilder();
+ var count = 0;
+ foreach (var key in request.ExpectHeaders.AllKeys)
+ {
+ names.Append(key);
+ values.Append(request.ExpectHeaders[key].Value);
+ count++;
+ if (count < request.ExpectHeaders.Count)
+ {
+ names.Append(",");
+ values.Append(",");
+ }
+ }
+
+ query.Parameters.Add("mockHeaderNames", names.ToString());
+ query.Parameters.Add("mockHeaderValues", values.ToString());
+ }
+
+ return url;
+ }
+
+ private static bool RequestExpectsMock(RestRequest request)
+ {
+ return request.ExpectEntity != null ||
+ request.ExpectHeaders.Count > 0 ||
+ request.ExpectStatusCode.HasValue ||
+ !request.ExpectContent.IsNullOrBlank() ||
+ !request.ExpectContentType.IsNullOrBlank() ||
+ !request.ExpectStatusDescription.IsNullOrBlank();
+ }
+
+ private ICache GetCache(RestBase request)
+ {
+ return request.Cache ?? Cache;
+ }
+
+ private IEnumerable<HttpPostParameter> GetPostParameters(RestBase request)
+ {
+ if (request.PostParameters != null)
+ {
+ foreach (var parameter in request.PostParameters)
+ {
+ yield return parameter;
+ }
+ }
+
+ if (PostParameters == null)
+ {
+ yield break;
+ }
+
+ foreach (var parameter in PostParameters)
+ {
+ yield return parameter;
+ }
+ }
+
+ private CacheOptions GetCacheOptions(RestBase request)
+ {
+ return request.CacheOptions ?? CacheOptions;
+ }
+
+ private Func<string> GetCacheKeyFunction(RestBase request)
+ {
+ return request.CacheKeyFunction ?? CacheKeyFunction;
+ }
+
+ private string GetProxy(RestBase request)
+ {
+ return request.Proxy ?? Proxy;
+ }
+
+ private string GetUserAgent(RestBase request)
+ {
+ var userAgent = request.UserAgent.IsNullOrBlank()
+ ? UserAgent
+ : request.UserAgent;
+ return userAgent;
+ }
+
+ private ISerializer GetSerializer(RestBase request)
+ {
+ return request.Serializer ?? Serializer;
+ }
+
+ private IWebCredentials GetWebCredentials(RestBase request)
+ {
+ var credentials = request.Credentials ?? Credentials;
+ return credentials;
+ }
+
+ private IWebQueryInfo GetInfo(RestBase request)
+ {
+ var info = request.Info ?? Info;
+ return info;
+ }
+
+ private bool GetTraceEnabled(RestBase request)
+ {
+ var info = request.TraceEnabled || TraceEnabled;
+ return info;
+ }
+
+ private TimeSpan? GetTimeout(RestBase request)
+ {
+ return request.Timeout ?? Timeout;
+ }
+
+ private DecompressionMethods? GetDecompressionMethods(RestBase request)
+ {
+ return request.DecompressionMethods ?? DecompressionMethods;
+ }
+
+ private WebMethod GetWebMethod(RestBase request)
+ {
+ var method = !request.Method.HasValue
+ ? !Method.HasValue
+ ? WebMethod.Get
+ : Method.Value
+ : request.Method.Value;
+
+ return method;
+ }
+
+ private byte[] GetPostContent(RestBase request)
+ {
+ var content = request.PostContent ?? PostContent;
+ return content;
+ }
+
+ private RetryPolicy GetRetryPolicy(RestBase request)
+ {
+ var policy = request.RetryPolicy ?? RetryPolicy;
+ return policy;
+ }
+
+ private Encoding GetEncoding(RestBase request)
+ {
+ var encoding = request.Encoding ?? Encoding;
+ return encoding;
+ }
+
+#if !SILVERLIGHT
+ private bool GetFollowRedirects(RestBase request)
+ {
+ var redirects = request.FollowRedirects ?? FollowRedirects ?? false;
+ return redirects;
+ }
+#endif
+
+ private TaskOptions GetTaskOptions(RestBase request)
+ {
+ var options = request.TaskOptions ?? TaskOptions;
+ return options;
+ }
+
+ private StreamOptions GetStreamOptions(RestBase request)
+ {
+ var options = request.StreamOptions ?? StreamOptions;
+ return options;
+ }
+
+ private object GetTag(RestBase request)
+ {
+ var tag = request.Tag ?? Tag;
+ return tag;
+ }
+
+#if !WindowsPhone
+ public virtual IAsyncResult BeginRequest(RestRequest request, RestCallback callback, object userState)
+ {
+ return BeginRequestImpl(request, callback, null, null, false /* isInternal */, userState);
+ }
+
+ public virtual IAsyncResult BeginRequest<T>(RestRequest request, RestCallback<T> callback, object userState)
+ {
+ return BeginRequestImpl(request, callback, null, null, false /* isInternal */, null);
+ }
+
+ public IAsyncResult BeginRequest()
+ {
+ return BeginRequest(null /* request */, null /* callback */);
+ }
+
+ public IAsyncResult BeginRequest<T>()
+ {
+ return BeginRequest(null /* request */, null /* callback */);
+ }
+
+#if NET40
+ public IAsyncResult BeginRequestDynamic()
+ {
+ return BeginRequestDynamic(null /* request */, null /* callback */);
+ }
+#endif
+
+ public virtual IAsyncResult BeginRequest(RestRequest request, RestCallback callback)
+ {
+ return BeginRequestImpl(request, callback, null, null, false /* isInternal */, null);
+ }
+
+ public virtual IAsyncResult BeginRequest<T>(RestRequest request, RestCallback<T> callback)
+ {
+ return BeginRequestImpl(request, callback, null, null, false /* isInternal */, null);
+ }
+
+#if NET40
+ public virtual IAsyncResult BeginRequestDynamic(RestRequest request, RestCallback<dynamic> callback)
+ {
+ return BeginRequestImplDynamic(request, callback, null, null, false /* isInternal */, null);
+ }
+
+ public virtual IAsyncResult BeginRequestDynamic(RestRequest request, RestCallback<dynamic> callback, object userState)
+ {
+ return BeginRequestImplDynamic(request, callback, null, null, false /* isInternal */, userState);
+ }
+#endif
+
+ public virtual IAsyncResult BeginRequest(RestCallback callback)
+ {
+ return BeginRequestImpl(null, callback, null, null, false /* isInternal */, null);
+ }
+
+ public virtual IAsyncResult BeginRequest(RestRequest request)
+ {
+ return BeginRequest(request, null, null);
+ }
+
+ public IAsyncResult BeginRequest(RestRequest request, object userState)
+ {
+ return BeginRequest(request, null, userState);
+ }
+
+ public virtual IAsyncResult BeginRequest<T>(RestRequest request)
+ {
+ return BeginRequest<T>(request, null, null);
+ }
+
+ public IAsyncResult BeginRequest<T>(RestRequest request, object userState)
+ {
+ return BeginRequest<T>(request, null, userState);
+ }
+
+ public virtual IAsyncResult BeginRequest<T>(RestCallback<T> callback)
+ {
+ return BeginRequest(null, callback, null);
+ }
+#else
+ public virtual void BeginRequest(RestRequest request, RestCallback callback, object userState)
+ {
+ BeginRequestImpl(request, callback, null, null, false /* isInternal */, userState);
+ }
+
+ public virtual void BeginRequest<T>(RestRequest request, RestCallback<T> callback, object userState)
+ {
+ BeginRequestImpl(request, callback, null, null, false /* isInternal */, null);
+ }
+
+ public virtual void BeginRequest()
+ {
+ BeginRequest(null /* request */, null /* callback */);
+ }
+
+ public virtual void BeginRequest<T>()
+ {
+ BeginRequest(null /* request */, null /* callback */);
+ }
+
+ public virtual void BeginRequest(RestRequest request, RestCallback callback)
+ {
+ BeginRequestImpl(request, callback, null, null, false /* isInternal */, null);
+ }
+
+ public virtual void BeginRequest<T>(RestRequest request, RestCallback<T> callback)
+ {
+ BeginRequestImpl(request, callback, null, null, false /* isInternal */, null);
+ }
+
+ public virtual void BeginRequest(RestCallback callback)
+ {
+ BeginRequestImpl(null, callback, null, null, false /* isInternal */, null);
+ }
+
+ public virtual void BeginRequest(RestRequest request)
+ {
+ BeginRequest(request, null, null);
+ }
+
+ public void BeginRequest(RestRequest request, object userState)
+ {
+ BeginRequest(request, null, userState);
+ }
+
+ public virtual void BeginRequest<T>(RestRequest request)
+ {
+ BeginRequest<T>(request, null, null);
+ }
+
+ public void BeginRequest<T>(RestRequest request, object userState)
+ {
+ BeginRequest<T>(request, null, userState);
+ }
+
+ public virtual void BeginRequest<T>(RestCallback<T> callback)
+ {
+ BeginRequest(null, callback, null);
+ }
+#endif
+
+#if !WindowsPhone
+ public virtual RestResponse EndRequest(IAsyncResult result)
+ {
+#if !Mono && !NETCF
+ var webResult = EndRequestImpl(result);
+#else
+ var webResult = EndRequestImpl(result, null);
+#endif
+ return webResult.AsyncState as RestResponse;
+ }
+
+ public virtual RestResponse EndRequest(IAsyncResult result, TimeSpan timeout)
+ {
+ var webResult = EndRequestImpl(result, timeout);
+ return webResult.AsyncState as RestResponse;
+ }
+
+ public virtual RestResponse<T> EndRequest<T>(IAsyncResult result)
+ {
+#if !Mono && !NETCF
+ var webResult = EndRequestImpl<T>(result);
+#else
+ var webResult = EndRequestImpl<T>(result, null);
+#endif
+ return webResult.AsyncState as RestResponse<T>;
+ }
+
+#if NET40
+ public virtual RestResponse<dynamic> EndRequestDynamic(IAsyncResult result)
+ {
+#if !Mono
+ var webResult = EndRequestImplDynamic(result);
+#else
+ var webResult = EndRequestImplDynamic<T>(result, null);
+#endif
+ return webResult.AsyncState as RestResponse<dynamic>;
+ }
+#endif
+
+ public virtual RestResponse<T> EndRequest<T>(IAsyncResult result, TimeSpan timeout)
+ {
+ var webResult = EndRequestImpl<T>(result, timeout);
+ return webResult.AsyncState as RestResponse<T>;
+ }
+
+#if !Mono && !NETCF
+ private WebQueryAsyncResult EndRequestImpl(IAsyncResult result, TimeSpan? timeout = null)
+ {
+#else
+ private WebQueryAsyncResult EndRequestImpl(IAsyncResult result, TimeSpan? timeout)
+ {
+#endif
+ var webResult = result as WebQueryAsyncResult;
+ if (webResult == null)
+ {
+ throw new InvalidOperationException("The IAsyncResult provided was not for this operation.");
+ }
+
+ var tag = (Triplet<RestRequest, RestCallback, object>)webResult.Tag;
+
+ if (RequestExpectsMock(tag.First))
+ {
+ // [DC]: Mock results come via InnerResult
+ webResult = (WebQueryAsyncResult)webResult.InnerResult;
+ }
+
+ if (webResult.CompletedSynchronously)
+ {
+ var query = webResult.AsyncState as WebQuery;
+ if (query != null)
+ {
+ // [DC]: From cache
+ CompleteWithQuery(query, tag.First, tag.Second, webResult);
+ }
+ else
+ {
+ // [DC]: From mocks
+ webResult = CompleteWithMockWebResponse(result, webResult, tag);
+ }
+ }
+
+ if (!webResult.IsCompleted)
+ {
+ if(timeout.HasValue)
+ {
+#if NETCF
+ var millisecondsTimeout = Convert.ToInt32(timeout.Value.TotalMilliseconds);
+ webResult.AsyncWaitHandle.WaitOne(millisecondsTimeout, false);
+#else
+ webResult.AsyncWaitHandle.WaitOne(timeout.Value);
+#endif
+ }
+ else
+ {
+ webResult.AsyncWaitHandle.WaitOne();
+ }
+ }
+ return webResult;
+ }
+
+#if !Mono && !NETCF
+ private WebQueryAsyncResult EndRequestImpl<T>(IAsyncResult result, TimeSpan? timeout = null)
+#else
+ private WebQueryAsyncResult EndRequestImpl<T>(IAsyncResult result, TimeSpan? timeout)
+#endif
+ {
+ var webResult = result as WebQueryAsyncResult;
+ if (webResult == null)
+ {
+ throw new InvalidOperationException("The IAsyncResult provided was not for this operation.");
+ }
+
+ var tag = (Triplet<RestRequest, RestCallback<T>, object>)webResult.Tag;
+
+ if (RequestExpectsMock(tag.First))
+ {
+ // [DC]: Mock results come via InnerResult
+ webResult = (WebQueryAsyncResult)webResult.InnerResult;
+ }
+
+ if (webResult.CompletedSynchronously)
+ {
+ var query = webResult.AsyncState as WebQuery;
+ if (query != null)
+ {
+ // [DC]: From cache
+ CompleteWithQuery(query, tag.First, tag.Second, webResult);
+ }
+ else
+ {
+ // [DC]: From mocks
+ webResult = CompleteWithMockWebResponse(result, webResult, tag);
+ }
+ }
+
+ if (!webResult.IsCompleted)
+ {
+ if(timeout.HasValue)
+ {
+#if NETCF
+ var millisecondsTimeout = Convert.ToInt32(timeout.Value.TotalMilliseconds);
+ webResult.AsyncWaitHandle.WaitOne(millisecondsTimeout, false);
+#else
+ webResult.AsyncWaitHandle.WaitOne(timeout.Value);
+#endif
+ }
+ else
+ {
+ webResult.AsyncWaitHandle.WaitOne();
+ }
+ }
+ return webResult;
+ }
+#endif
+
+#if NET40
+#if !Mono
+ private WebQueryAsyncResult EndRequestImplDynamic(IAsyncResult result, TimeSpan? timeout = null)
+#else
+ private WebQueryAsyncResult EndRequestImplDynamic(IAsyncResult result, TimeSpan? timeout)
+#endif
+ {
+ var webResult = result as WebQueryAsyncResult;
+ if (webResult == null)
+ {
+ throw new InvalidOperationException("The IAsyncResult provided was not for this operation.");
+ }
+
+ var tag = (Triplet<RestRequest, RestCallback<dynamic>, object>) webResult.Tag;
+
+ if (RequestExpectsMock(tag.First))
+ {
+ // [DC]: Mock results come via InnerResult
+ webResult = (WebQueryAsyncResult) webResult.InnerResult;
+ }
+
+ if (webResult.CompletedSynchronously)
+ {
+ var query = webResult.AsyncState as WebQuery;
+ if (query != null)
+ {
+ // [DC]: From cache
+ CompleteWithQueryDynamic(query, tag.First, tag.Second, webResult);
+ }
+ else
+ {
+ // [DC]: From mocks
+ webResult = CompleteWithMockWebResponse(result, webResult, tag);
+ }
+ }
+
+ if (!webResult.IsCompleted)
+ {
+ if(timeout.HasValue)
+ {
+ webResult.AsyncWaitHandle.WaitOne(timeout.Value);
+ }
+ else
+ {
+ webResult.AsyncWaitHandle.WaitOne();
+ }
+ }
+ return webResult;
+ }
+#endif
+
+ private WebQueryAsyncResult CompleteWithMockWebResponse<T>(
+ IAsyncResult result,
+ IAsyncResult webResult,
+ Triplet<RestRequest, RestCallback<T>, object> tag)
+ {
+ var webResponse = (WebResponse)webResult.AsyncState;
+ var restRequest = tag.First;
+ var userState = tag.Third;
+
+ var m = new MemoryStream();
+ using (var stream = webResponse.GetResponseStream())
+ {
+ if (stream != null)
+ {
+ using (var reader = new StreamReader(stream))
+ {
+ while (reader.Peek() >= 0)
+ {
+ m.WriteByte((byte) reader.Read());
+ }
+ }
+ }
+ }
+ m.Position = 0;
+
+ var restResponse = new RestResponse<T>
+ {
+ ContentStream = m,
+ ContentType = webResponse.ContentType,
+ ContentLength = webResponse.ContentLength,
+ StatusCode = restRequest.ExpectStatusCode.HasValue
+ ? restRequest.ExpectStatusCode.Value
+ : 0,
+ StatusDescription = restRequest.ExpectStatusDescription,
+ ResponseUri = webResponse.ResponseUri,
+ IsMock = true
+ };
+
+ foreach (var key in webResponse.Headers.AllKeys)
+ {
+ restResponse.Headers.Add(key, webResponse.Headers[key]);
+ }
+
+ var deserializer = restRequest.Deserializer ?? Deserializer;
+ if (deserializer != null && !restResponse.Content.IsNullOrBlank())
+ {
+ restResponse.ContentEntity = deserializer.Deserialize<T>(restResponse);
+ }
+
+ TraceResponseWithMock(restResponse);
+
+ var parentResult = (WebQueryAsyncResult)result;
+ parentResult.AsyncState = restResponse;
+ parentResult.IsCompleted = true;
+
+ var callback = tag.Second;
+ if (callback != null)
+ {
+ callback.Invoke(restRequest, restResponse, userState);
+ }
+ parentResult.Signal();
+ return parentResult;
+ }
+
+ private WebQueryAsyncResult CompleteWithMockWebResponse(
+ IAsyncResult result,
+ IAsyncResult webResult,
+ Triplet<RestRequest, RestCallback, object> tag)
+ {
+ var webResponse = (WebResponse)webResult.AsyncState;
+ var restRequest = tag.First;
+ var userState = tag.Third;
+
+ var m = new MemoryStream();
+ using (var stream = webResponse.GetResponseStream())
+ {
+ if (stream != null)
+ {
+ using (var reader = new StreamReader(stream))
+ {
+ while (reader.Peek() >= 0)
+ {
+ m.WriteByte((byte) reader.Read());
+ }
+ }
+ }
+ }
+ m.Position = 0;
+
+ var restResponse = new RestResponse
+ {
+ ContentStream = m,
+ ContentType = webResponse.ContentType,
+ ContentLength = webResponse.ContentLength,
+ StatusCode = restRequest.ExpectStatusCode.HasValue
+ ? restRequest.ExpectStatusCode.Value
+ : 0,
+ StatusDescription = restRequest.ExpectStatusDescription,
+ ResponseUri = webResponse.ResponseUri,
+ IsMock = true
+ };
+
+ foreach (var key in webResponse.Headers.AllKeys)
+ {
+ restResponse.Headers.Add(key, webResponse.Headers[key]);
+ }
+
+ var deserializer = restRequest.Deserializer ?? Deserializer;
+ if (deserializer != null && !restResponse.Content.IsNullOrBlank() && restRequest.ResponseEntityType != null)
+ {
+ restResponse.ContentEntity = deserializer.Deserialize(restResponse, restRequest.ResponseEntityType);
+ }
+
+ TraceResponseWithMock(restResponse);
+
+ var parentResult = (WebQueryAsyncResult)result;
+ parentResult.AsyncState = restResponse;
+ parentResult.IsCompleted = true;
+
+ var callback = tag.Second;
+ if (callback != null)
+ {
+ callback.Invoke(restRequest, restResponse, userState);
+ }
+ parentResult.Signal();
+ return parentResult;
+ }
+
+ private void TraceResponseWithMock(RestResponseBase restResponse)
+ {
+#if TRACE
+ if(!TraceEnabled)
+ {
+ return;
+ }
+
+ Trace.WriteLine(string.Concat("RESPONSE: ", restResponse.StatusCode, " ", restResponse.StatusDescription));
+ Trace.WriteLineIf(restResponse.Headers.AllKeys.Count() > 0, "HEADERS:");
+ foreach (var trace in restResponse.Headers.AllKeys.Select(key => string.Concat("\t", key, ": ", restResponse.Headers[key])))
+ {
+ Trace.WriteLine(trace);
+ }
+ Trace.WriteLine(string.Concat("\r\n", restResponse.Content));
+#endif
+ }
+
+#if !WindowsPhone
+ // TODO BeginRequestImpl and BeginRequestImpl<T> have too much duplication
+ private IAsyncResult BeginRequestImpl(RestRequest request,
+ RestCallback callback,
+ WebQuery query,
+ string url,
+ bool isInternal,
+ object userState)
+ {
+ request = request ?? new RestRequest();
+ if (!isInternal)
+ {
+ // [DC]: Recursive call possible, only do this once
+ var uri = request.BuildEndpoint(this);
+ query = GetQueryFor(request, uri);
+ SetQueryMeta(request, query);
+ url = uri.ToString();
+ }
+
+ if (RequestExpectsMock(request))
+ {
+ url = BuildMockRequestUrl(request, query, url);
+ }
+
+ var retryPolicy = GetRetryPolicy(request);
+ bool inRetryScope = false;
+ if (!isInternal && retryPolicy != null)
+ {
+ _remainingRetries = retryPolicy.RetryCount;
+ inRetryScope = true;
+ }
+
+ Func<WebQueryAsyncResult> beginRequest;
+ WebQueryAsyncResult asyncResult;
+
+ var streamOptions = GetStreamOptions(request);
+ if (streamOptions != null)
+ {
+#if !SILVERLIGHT
+ query.KeepAlive = true;
+#endif
+ var duration = streamOptions.Duration.HasValue
+ ? streamOptions.Duration.Value
+ : TimeSpan.Zero;
+
+ var resultCount = streamOptions.ResultsPerCallback.HasValue
+ ? streamOptions.ResultsPerCallback.Value
+ : 10;
+
+ beginRequest = () => BeginRequestStreamFunction(
+ request, query, url, callback, duration, resultCount, userState
+ );
+
+ asyncResult = beginRequest.Invoke();
+ }
+ else
+ {
+ beginRequest
+ = () => BeginRequestFunction(isInternal,
+ request,
+ query,
+ url,
+ callback,
+ userState);
+
+ asyncResult = beginRequest.Invoke();
+ }
+
+ if (isInternal || (request.TaskOptions == null || request.TaskOptions.RepeatInterval.TotalMilliseconds == 0))
+ {
+ if (IsFirstIteration && request.IsFirstIteration)
+ {
+ query.QueryResponse += (sender, args) =>
+ {
+ var current = query.Result;
+
+ if (retryPolicy != null)
+ {
+ // [DC]: Query should already have exception applied
+ var exception = query.Result.Exception;
+ var retry = inRetryScope &&
+ _remainingRetries > 0 &&
+ ShouldRetry(retryPolicy, exception, current);
+
+ if (retry)
+ {
+ UpdateRetryState(request);
+ BeginRequestImpl(request, callback, query, url, true /* isInternal */, userState);
+ Interlocked.Decrement(ref _remainingRetries);
+ if(_remainingRetries > 0)
+ {
+ OnBeforeRetry(new RetryEventArgs { Client = this, Request = request });
+ }
+ }
+ else if (inRetryScope)
+ {
+ _remainingRetries = 0;
+ }
+ current.TimesTried = GetIterationCount(request);
+ }
+ else if (inRetryScope)
+ {
+ _remainingRetries = 0;
+ }
+
+ query.Result = current;
+
+ if (_remainingRetries == 0)
+ {
+ CompleteWithQuery(query, request, callback, asyncResult);
+ }
+ };
+ }
+ UpdateRepeatingRequestState(request);
+ }
+ return asyncResult;
+ }
+
+
+#if NET40
+ private IAsyncResult BeginRequestImplDynamic(RestRequest request,
+ RestCallback<dynamic> callback,
+ WebQuery query,
+ string url,
+ bool isInternal,
+ object userState)
+ {
+ request = request ?? new RestRequest();
+ if (!isInternal)
+ {
+ var uri = request.BuildEndpoint(this);
+ query = GetQueryFor(request, uri);
+ SetQueryMeta(request, query);
+ url = uri.ToString();
+ }
+
+ if (RequestExpectsMock(request))
+ {
+ url = BuildMockRequestUrl(request, query, url);
+ }
+
+ var retryPolicy = GetRetryPolicy(request);
+ bool inRetryScope = false;
+ if (!isInternal && retryPolicy != null)
+ {
+ _remainingRetries = retryPolicy.RetryCount;
+ inRetryScope = true;
+ }
+
+ Func<WebQueryAsyncResult> beginRequest;
+ WebQueryAsyncResult asyncResult;
+
+ var streamOptions = GetStreamOptions(request);
+ if (streamOptions != null)
+ {
+#if !SILVERLIGHT
+ query.KeepAlive = true;
+#endif
+
+ var duration = streamOptions.Duration.HasValue
+ ? streamOptions.Duration.Value
+ : TimeSpan.Zero;
+
+ var resultCount = streamOptions.ResultsPerCallback.HasValue
+ ? streamOptions.ResultsPerCallback.Value
+ : 10;
+
+ beginRequest = () => BeginRequestStreamFunction(
+ request, query, url, callback, duration, resultCount, userState
+ );
+
+ asyncResult = beginRequest.Invoke();
+ }
+ else
+ {
+ beginRequest = () => BeginRequestFunction(
+ isInternal, request, query, url, callback, userState
+ );
+
+ asyncResult = beginRequest.Invoke();
+ }
+ if (isInternal || (request.TaskOptions == null || request.TaskOptions.RepeatInterval.TotalMilliseconds == 0))
+ {
+ if (IsFirstIteration && request.IsFirstIteration)
+ {
+ query.QueryResponse += (sender, args) =>
+ {
+ var current = query.Result;
+
+ if (retryPolicy != null)
+ {
+ // [DC]: Query should already have exception applied
+ var exception = query.Result.Exception;
+ var retry = inRetryScope &&
+ _remainingRetries > 0 &&
+ ShouldRetry(retryPolicy, exception, current);
+
+ if (retry)
+ {
+ UpdateRetryState(request);
+ BeginRequestImpl(request, callback, query, url, true /* isInternal */, userState);
+ Interlocked.Decrement(ref _remainingRetries);
+ if (_remainingRetries > 0)
+ {
+ OnBeforeRetry(new RetryEventArgs { Client = this, Request = request });
+ }
+ }
+ else if (inRetryScope)
+ {
+ _remainingRetries = 0;
+ }
+ current.TimesTried = GetIterationCount(request);
+ }
+ else if (inRetryScope)
+ {
+ _remainingRetries = 0;
+ }
+
+ query.Result = current;
+
+ // [DC]: Callback is for a final result, not a retry
+ if (_remainingRetries == 0)
+ {
+ CompleteWithQueryDynamic(query, request, callback, asyncResult);
+ }
+ };
+ }
+ UpdateRepeatingRequestState(request);
+ }
+ return asyncResult;
+ }
+#endif
+
+ private IAsyncResult BeginRequestImpl<T>(RestRequest request,
+ RestCallback<T> callback,
+ WebQuery query,
+ string url,
+ bool isInternal,
+ object userState)
+ {
+ request = request ?? new RestRequest();
+ if (!isInternal)
+ {
+ var uri = request.BuildEndpoint(this);
+ query = GetQueryFor(request, uri);
+ SetQueryMeta(request, query);
+ url = uri.ToString();
+ }
+
+ if (RequestExpectsMock(request))
+ {
+ url = BuildMockRequestUrl(request, query, url);
+ }
+
+ var retryPolicy = GetRetryPolicy(request);
+ bool inRetryScope = false;
+ if (!isInternal && retryPolicy != null)
+ {
+ _remainingRetries = retryPolicy.RetryCount;
+ inRetryScope = true;
+ }
+
+ Func<WebQueryAsyncResult> beginRequest;
+ WebQueryAsyncResult asyncResult;
+
+ var streamOptions = GetStreamOptions(request);
+ if (streamOptions != null)
+ {
+#if !SILVERLIGHT
+ query.KeepAlive = true;
+#endif
+
+ var duration = streamOptions.Duration.HasValue
+ ? streamOptions.Duration.Value
+ : TimeSpan.Zero;
+
+ var resultCount = streamOptions.ResultsPerCallback.HasValue
+ ? streamOptions.ResultsPerCallback.Value
+ : 10;
+
+ beginRequest = () => BeginRequestStreamFunction(
+ request, query, url, callback, duration, resultCount, userState
+ );
+
+ asyncResult = beginRequest.Invoke();
+ }
+ else
+ {
+ beginRequest = () => BeginRequestFunction(
+ isInternal, request, query, url, callback, userState
+ );
+
+ asyncResult = beginRequest.Invoke();
+ }
+ if (isInternal || (request.TaskOptions == null || request.TaskOptions.RepeatInterval.TotalMilliseconds == 0))
+ {
+ if (IsFirstIteration && request.IsFirstIteration)
+ {
+ query.QueryResponse += (sender, args) =>
+ {
+ var current = query.Result;
+
+ if (retryPolicy != null)
+ {
+ // [DC]: Query should already have exception applied
+ var exception = query.Result.Exception;
+ var retry = inRetryScope &&
+ _remainingRetries > 0 &&
+ ShouldRetry(retryPolicy, exception, current);
+
+ if (retry)
+ {
+ UpdateRetryState(request);
+ BeginRequestImpl(request, callback, query, url, true /* isInternal */, userState);
+ Interlocked.Decrement(ref _remainingRetries);
+ if(_remainingRetries > 0)
+ {
+ OnBeforeRetry(new RetryEventArgs { Client = this, Request = request });
+ }
+ }
+ else if (inRetryScope)
+ {
+ _remainingRetries = 0;
+ }
+ current.TimesTried = GetIterationCount(request);
+ }
+ else if (inRetryScope)
+ {
+ _remainingRetries = 0;
+ }
+
+ query.Result = current;
+
+ // [DC]: Callback is for a final result, not a retry
+ if (_remainingRetries == 0)
+ {
+ CompleteWithQuery(query, request, callback, asyncResult);
+ }
+ };
+ }
+ UpdateRepeatingRequestState(request);
+ }
+ return asyncResult;
+ }
+#else
+ // TODO BeginRequest and BeginRequest<T> have too much duplication
+
+ private void BeginRequestImpl(RestRequest request,
+ RestCallback callback,
+ WebQuery query,
+ string url,
+ bool isInternal,
+ object userState)
+ {
+ request = request ?? new RestRequest();
+ if (!isInternal)
+ {
+ // [DC]: Recursive call possible, only do this once
+ var uri = request.BuildEndpoint(this);
+ query = GetQueryFor(request, uri);
+ SetQueryMeta(request, query);
+ url = uri.ToString();
+ }
+
+ if (RequestExpectsMock(request))
+ {
+ url = BuildMockRequestUrl(request, query, url);
+ }
+
+ var retryPolicy = GetRetryPolicy(request);
+ _remainingRetries = (retryPolicy != null
+ ? retryPolicy.RetryCount
+ : 0);
+
+ Action beginRequest;
+
+ var streamOptions = GetStreamOptions(request);
+ if (streamOptions != null)
+ {
+#if !SILVERLIGHT
+ query.KeepAlive = true;
+#endif
+ var duration = streamOptions.Duration.HasValue
+ ? streamOptions.Duration.Value
+ : TimeSpan.Zero;
+
+ var resultCount = streamOptions.ResultsPerCallback.HasValue
+ ? streamOptions.ResultsPerCallback.Value
+ : 10;
+
+ beginRequest = () => BeginRequestStreamFunction(
+ request, query, url, callback, duration, resultCount, userState
+ );
+
+ beginRequest.Invoke();
+ }
+ else
+ {
+ beginRequest = ()=> BeginRequestFunction(isInternal,
+ request,
+ query,
+ url,
+ callback,
+ userState);
+
+ beginRequest.Invoke();
+ }
+
+ if (isInternal || (request.TaskOptions == null || request.TaskOptions.RepeatInterval.TotalMilliseconds == 0))
+ {
+ if (request.IsFirstIteration && IsFirstIteration)
+ {
+ query.QueryResponse += (sender, args) => QueryResponseCallback(query,
+ retryPolicy,
+ request,
+ callback,
+ url,
+ userState);
+ }
+ UpdateRepeatingRequestState(request);
+ UpdateRetryState(request);
+ }
+ }
+
+ private void BeginRequestImpl<T>(RestRequest request,
+ RestCallback<T> callback,
+ WebQuery query,
+ string url,
+ bool isInternal,
+ object userState)
+ {
+ request = request ?? new RestRequest();
+ if (!isInternal)
+ {
+ var uri = request.BuildEndpoint(this);
+ query = GetQueryFor(request, uri);
+ SetQueryMeta(request, query);
+ url = uri.ToString();
+ }
+
+ if (RequestExpectsMock(request))
+ {
+ url = BuildMockRequestUrl(request, query, url);
+ }
+
+ var retryPolicy = GetRetryPolicy(request);
+ _remainingRetries = (retryPolicy != null
+ ? retryPolicy.RetryCount
+ : 0);
+
+ Action beginRequest;
+ var streamOptions = GetStreamOptions(request);
+ if (streamOptions != null)
+ {
+#if !SILVERLIGHT
+ query.KeepAlive = true;
+#endif
+
+ var duration = streamOptions.Duration.HasValue
+ ? streamOptions.Duration.Value
+ : TimeSpan.Zero;
+
+ var resultCount = streamOptions.ResultsPerCallback.HasValue
+ ? streamOptions.ResultsPerCallback.Value
+ : 10;
+
+ beginRequest = () => BeginRequestStreamFunction(
+ request, query, url, callback, duration, resultCount, userState
+ );
+
+ beginRequest.Invoke();
+ }
+ else
+ {
+ beginRequest = () => BeginRequestFunction(
+ isInternal, request, query, url, callback, userState
+ );
+
+ beginRequest.Invoke();
+ }
+ if (IsFirstIteration && request.IsFirstIteration)
+ {
+ query.QueryResponse += (sender, args) => QueryResponseCallback(query,
+ retryPolicy,
+ request,
+ callback,
+ url,
+ userState);
+ }
+ UpdateRepeatingRequestState(request);
+ UpdateRetryState(request);
+ }
+
+ private void QueryResponseCallback(WebQuery query,
+ RetryPolicy retryPolicy,
+ RestRequest request,
+ RestCallback callback,
+ string url,
+ object userState)
+ {
+ var current = query.Result;
+
+ if (retryPolicy != null)
+ {
+ // [DC]: Query should already have exception applied
+ var exception = query.Result.Exception;
+ var retry = _remainingRetries > 0 && ShouldRetry(retryPolicy, exception, current);
+
+ if (retry)
+ {
+ BeginRequestImpl(request, callback, query, url, true /* isInternal */, userState);
+ Interlocked.Decrement(ref _remainingRetries);
+ }
+ else
+ {
+ _remainingRetries = 0;
+ }
+ current.TimesTried = GetIterationCount(request);
+ }
+ else
+ {
+ _remainingRetries = 0;
+ }
+
+ query.Result = current;
+
+ // [DC]: Callback is for a final result, not a retry
+ if (_remainingRetries == 0)
+ {
+ CompleteWithQuery(query, request, callback);
+ }
+ }
+ private void QueryResponseCallback<T>(WebQuery query,
+ RetryPolicy retryPolicy,
+ RestRequest request,
+ RestCallback<T> callback,
+ string url,
+ object userState)
+ {
+ var current = query.Result;
+
+ if (retryPolicy != null)
+ {
+ // [DC]: Query should already have exception applied
+ var exception = query.Result.Exception;
+ var retry = _remainingRetries > 0 && ShouldRetry(retryPolicy, exception, current);
+
+ if (retry)
+ {
+ BeginRequestImpl(request, callback, query, url, true /* isInternal */, userState);
+ Interlocked.Decrement(ref _remainingRetries);
+ }
+ else
+ {
+ _remainingRetries = 0;
+ }
+ current.TimesTried = GetIterationCount(request);
+
+ }
+ else
+ {
+ _remainingRetries = 0;
+ }
+
+ query.Result = current;
+
+ // [DC]: Callback is for a final result, not a retry
+ if (_remainingRetries == 0)
+ {
+ CompleteWithQuery(query, request, callback);
+ }
+ }
+#endif
+
+#if !WindowsPhone
+ private WebQueryAsyncResult BeginRequestFunction(bool isInternal,
+ RestRequest request,
+ WebQuery query,
+ string url,
+ RestCallback callback,
+ object userState)
+ {
+ WebQueryAsyncResult result;
+ if (!isInternal)
+ {
+ if (!BeginRequestWithTask(request, callback, query, url, out result, userState))
+ {
+ if (!BeginRequestWithCache(request, query, url, out result, userState))
+ {
+ if (!BeginRequestMultiPart(request, query, url, out result, userState))
+ {
+ // Normal operation
+ result = query.RequestAsync(url, userState);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Normal operation
+ result = query.RequestAsync(url, userState);
+ }
+
+ result.Tag = new Triplet<RestRequest, RestCallback, object>
+ {
+ First = request,
+ Second = callback,
+ Third = userState
+ };
+
+ return result;
+ }
+#else
+ private void BeginRequestFunction(bool isInternal,
+ RestRequest request,
+ WebQuery query,
+ string url,
+ RestCallback callback,
+ object userState)
+ {
+ if (!isInternal)
+ {
+ if (!BeginRequestWithTask(request, callback, query, url, userState))
+ {
+ if (!BeginRequestWithCache(request, query, url, userState))
+ {
+ if (!BeginRequestMultiPart(request, query, url, userState))
+ {
+ // Normal operation
+ query.RequestAsync(url, userState);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Normal operation
+ query.RequestAsync(url, userState);
+ }
+ }
+#endif
+
+ private void SignalTasks(RestRequest request, WebQueryAsyncResult result)
+ {
+ // Recurring tasks are only signalled when cancelled
+ // or when they reach their iteration limit
+ lock (_timedTasksLock)
+ {
+ if (!_tasks.ContainsKey(request))
+ {
+ result.Signal();
+ }
+ }
+ }
+
+#if !WindowsPhone
+
+#if NET40
+ private void CompleteWithQueryDynamic(WebQuery query,
+ RestRequest request,
+ RestCallback<dynamic> callback,
+ WebQueryAsyncResult result)
+ {
+ var response = BuildResponseFromResultDynamic(request, query);
+
+ CompleteWithQuery(request, query, callback, response, result);
+ }
+#endif
+
+ private void CompleteWithQuery<T>(WebQuery query,
+ RestRequest request,
+ RestCallback<T> callback,
+ WebQueryAsyncResult result)
+ {
+ var response = BuildResponseFromResult<T>(request, query);
+
+ CompleteWithQuery(request, query, callback, response, result);
+ }
+
+ private void CompleteWithQuery<T>(RestRequest request, WebQuery query, RestCallback<T> callback, RestResponse<T> response, WebQueryAsyncResult result)
+ {
+ if (query.IsStreaming && callback != null)
+ {
+ callback.Invoke(request, response, query.UserState);
+ return;
+ }
+
+ var wasStreaming = response.Content.Equals(EndStreamingContent);
+
+ result.AsyncState = response;
+ result.IsCompleted = true;
+ if (callback != null && !wasStreaming)
+ {
+ callback.Invoke(request, response, query.UserState);
+ }
+
+ if (wasStreaming)
+ {
+ _streamQuery = null;
+ }
+
+ SignalTasks(request, result);
+ }
+
+ private void CompleteWithQuery(WebQuery query,
+ RestRequest request,
+ RestCallback callback,
+ WebQueryAsyncResult result)
+ {
+ var response = BuildResponseFromResult(request, query);
+ if (query.IsStreaming && callback != null)
+ {
+ callback.Invoke(request, response, query.UserState);
+ return;
+ }
+
+ var wasStreaming = response.Content.Equals(EndStreamingContent);
+
+ result.AsyncState = response;
+ result.IsCompleted = true;
+ if (callback != null && !wasStreaming)
+ {
+ callback.Invoke(request, response, query.UserState);
+ }
+
+ if (wasStreaming)
+ {
+ _streamQuery = null;
+ }
+
+ SignalTasks(request, result);
+ }
+#else
+ private void CompleteWithQuery<T>(WebQuery query,
+ RestRequest request,
+ RestCallback<T> callback)
+ {
+ var response = BuildResponseFromResult<T>(request, query);
+ if (query.IsStreaming)
+ {
+ return;
+ }
+
+ var wasStreaming = response.Content.Equals("END STREAMING");
+
+ if (callback != null && !wasStreaming)
+ {
+ callback.Invoke(request, response, query.UserState);
+ }
+ }
+ private void CompleteWithQuery(WebQuery query,
+ RestRequest request,
+ RestCallback callback)
+ {
+ var response = BuildResponseFromResult(request, query);
+ if (query.IsStreaming)
+ {
+ return;
+ }
+
+ var wasStreaming = response.Content.Equals("END STREAMING");
+
+ if (callback != null && !wasStreaming)
+ {
+ callback.Invoke(request, response, query.UserState);
+ }
+ }
+#endif
+
+#if !WindowsPhone
+ private WebQueryAsyncResult BeginRequestFunction<T>(bool isInternal,
+ RestRequest request,
+ WebQuery query,
+ string url,
+ RestCallback<T> callback,
+ object userState)
+ {
+
+ WebQueryAsyncResult result;
+ if (!isInternal)
+ {
+ if (!BeginRequestWithTask(request, callback, query, url, out result, userState))
+ {
+ if (!BeginRequestWithCache(request, query, url, out result, userState))
+ {
+ if (!BeginRequestMultiPart(request, query, url, out result, userState))
+ {
+ // Normal operation
+ result = query.RequestAsync(url, userState);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Normal operation
+ result = query.RequestAsync(url, userState);
+ }
+
+ result.Tag = new Triplet<RestRequest, RestCallback<T>, object>
+ {
+ First = request,
+ Second = callback,
+ Third = userState
+ };
+ return result;
+ }
+#else
+ private void BeginRequestFunction<T>(bool isInternal,
+ RestRequest request,
+ WebQuery query,
+ string url,
+ RestCallback<T> callback,
+ object userState)
+ {
+
+ if (!isInternal)
+ {
+ if (!BeginRequestWithTask(request, callback, query, url, userState))
+ {
+ if (!BeginRequestWithCache(request, query, url, userState))
+ {
+ if (!BeginRequestMultiPart(request, query, url, userState))
+ {
+ // Normal operation
+ query.RequestAsync(url, userState);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Normal operation
+ query.RequestAsync(url, userState);
+ }
+ }
+#endif
+ private WebQueryAsyncResult BeginRequestStreamFunction<T>(RestRequest request,
+ WebQuery query,
+ string url,
+ RestCallback<T> callback,
+ TimeSpan duration,
+ int resultsPerCallback,
+ object userState)
+ {
+ var result = GetStreamResult(request, query, url, duration, resultsPerCallback);
+
+ result.Tag = new Triplet<RestRequest, RestCallback<T>, object>
+ {
+ First = request,
+ Second = callback,
+ Third = userState
+ };
+
+ return result;
+ }
+ private WebQueryAsyncResult BeginRequestStreamFunction(RestRequest request,
+ WebQuery query,
+ string url,
+ RestCallback callback,
+ TimeSpan duration,
+ int resultsPerCallback,
+ object userState)
+ {
+ var result = GetStreamResult(request, query, url, duration, resultsPerCallback);
+
+ result.Tag = new Triplet<RestRequest, RestCallback, object>
+ {
+ First = request,
+ Second = callback,
+ Third = userState
+ };
+
+ return result;
+ }
+
+ private WebQueryAsyncResult GetStreamResult(RestBase request,
+ WebQuery query,
+ string url,
+ TimeSpan duration,
+ int resultsPerCallback)
+ {
+ if (!request.Method.HasValue)
+ {
+ request.Method = WebMethod.Get;
+ }
+
+ WebQueryAsyncResult result;
+ switch (request.Method)
+ {
+ case WebMethod.Get:
+ result = query.ExecuteStreamGetAsync(url, duration, resultsPerCallback);
+ break;
+ case WebMethod.Post:
+ result = query.ExecuteStreamPostAsync(url, duration, resultsPerCallback);
+ break;
+ default:
+ throw new NotSupportedException("Unsupported HTTP method declared for streaming.");
+ }
+
+ _streamQuery = query;
+
+ return result;
+ }
+
+ private void RegisterTimedTaskForRequest(RestRequest request, TimedTask task)
+ {
+ lock (_timedTasksLock)
+ {
+ if (_tasks.ContainsKey(request))
+ {
+ throw new InvalidOperationException("Task already has a registered timed task");
+ }
+ task.Stopped += (s, e) => UnregisterTimedTaskForRequest(request);
+ _tasks.Add(request, task);
+ }
+ }
+
+ private void UnregisterTimedTaskForRequest(RestRequest request)
+ {
+ lock (_timedTasksLock)
+ {
+ if (_tasks.ContainsKey(request))
+ {
+ var task = _tasks[request];
+ _tasks.Remove(request);
+ task.Dispose();
+ }
+ }
+ }
+
+#if !WindowsPhone
+ private bool BeginRequestWithTask(RestRequest request,
+ RestCallback callback,
+ WebQuery query,
+ string url,
+ out WebQueryAsyncResult asyncResult,
+ object userState)
+ {
+ var taskOptions = GetTaskOptions(request);
+ if (taskOptions == null)
+ {
+ asyncResult = null;
+ return false;
+ }
+
+ if (taskOptions.RepeatInterval <= TimeSpan.Zero)
+ {
+ asyncResult = null;
+ return false;
+ }
+
+ TimedTask task;
+#if !NETCF
+ if (!taskOptions.GetType().IsGenericType)
+ {
+#endif
+ // Tasks without rate limiting
+ task = new TimedTask(taskOptions.DueTime,
+ taskOptions.RepeatInterval,
+ taskOptions.RepeatTimes,
+ taskOptions.ContinueOnError,
+ skip => BeginRequestImpl(request,
+ callback,
+ query,
+ url,
+ true /* isInternal */,
+ userState
+ ));
+
+#if !NETCF
+ }
+ else
+ {
+ // Tasks with rate limiting
+ task = (TimedTask)BuildRateLimitingTask(request,
+ taskOptions,
+ callback,
+ query,
+ url,
+ userState);
+ }
+#endif
+
+ RegisterTimedTaskForRequest(request, task);
+
+ Action action = task.Start;
+
+ var inner = action.BeginInvoke(ar => {/* No callback */}, null);
+
+ asyncResult = new WebQueryAsyncResult { InnerResult = inner };
+ task.AsyncResult = asyncResult;
+ return true;
+ }
+
+ private bool BeginRequestWithTask<T>(RestRequest request,
+ RestCallback<T> callback,
+ WebQuery query,
+ string url,
+ out WebQueryAsyncResult asyncResult,
+ object userState)
+ {
+ var taskOptions = GetTaskOptions(request);
+ if (taskOptions == null)
+ {
+ asyncResult = null;
+ return false;
+ }
+
+ if (taskOptions.RepeatInterval <= TimeSpan.Zero)
+ {
+ asyncResult = null;
+ return false;
+ }
+
+ TimedTask task;
+#if !NETCF
+ if (!taskOptions.GetType().IsGenericType)
+ {
+#endif
+ // Tasks without rate limiting
+ task = new TimedTask(taskOptions.DueTime,
+ taskOptions.RepeatInterval,
+ taskOptions.RepeatTimes,
+ taskOptions.ContinueOnError,
+ skip => BeginRequestImpl(request,
+ callback,
+ query,
+ url,
+ true /* isInternal */,
+ userState));
+#if !NETCF
+ }
+ else
+ {
+ // Tasks with rate limiting
+ task = (TimedTask)BuildRateLimitingTask(request,
+ taskOptions,
+ callback,
+ query,
+ url,
+ userState);
+
+ }
+#endif
+ lock (_timedTasksLock)
+ {
+ _tasks[request] = task;
+ }
+ var action = new Action(task.Start);
+
+ var inner = action.BeginInvoke(ar => { /* No callback */ }, null);
+ asyncResult = new WebQueryAsyncResult { InnerResult = inner };
+ task.AsyncResult = asyncResult;
+ return true;
+ }
+#else
+ private bool BeginRequestWithTask(RestRequest request,
+ RestCallback callback,
+ WebQuery query,
+ string url,
+ object userState)
+ {
+ var taskOptions = GetTaskOptions(request);
+ if (taskOptions == null)
+ {
+ return false;
+ }
+
+ if (taskOptions.RepeatInterval <= TimeSpan.Zero)
+ {
+ return false;
+ }
+
+ TimedTask task;
+ if (!taskOptions.GetType().IsGenericType)
+ {
+ // Tasks without rate limiting
+ task = new TimedTask(taskOptions.DueTime,
+ taskOptions.RepeatInterval,
+ taskOptions.RepeatTimes,
+ taskOptions.ContinueOnError,
+ skip => BeginRequestImpl(request,
+ callback,
+ query,
+ url,
+ true /* isInternal */,
+ userState
+ ));
+ }
+ else
+ {
+ // Tasks with rate limiting
+ task = (TimedTask)BuildRateLimitingTask(request,
+ taskOptions,
+ callback,
+ query,
+ url,
+ userState);
+ }
+
+ RegisterTimedTaskForRequest(request, task);
+
+ var action = new Action(task.Start);
+ action.Invoke();
+ return true;
+ }
+
+ private bool BeginRequestWithTask<T>(RestRequest request,
+ RestCallback<T> callback,
+ WebQuery query,
+ string url,
+ object userState)
+ {
+ var taskOptions = GetTaskOptions(request);
+ if (taskOptions == null)
+ {
+ return false;
+ }
+
+ if (taskOptions.RepeatInterval <= TimeSpan.Zero)
+ {
+ return false;
+ }
+
+ TimedTask task;
+ if (!taskOptions.GetType().IsGenericType)
+ {
+ // Tasks without rate limiting
+ task = new TimedTask(taskOptions.DueTime,
+ taskOptions.RepeatInterval,
+ taskOptions.RepeatTimes,
+ taskOptions.ContinueOnError,
+ skip => BeginRequestImpl(request,
+ callback,
+ query,
+ url,
+ true /* isInternal */,
+ userState));
+ }
+ else
+ {
+ // Tasks with rate limiting
+ task = (TimedTask)BuildRateLimitingTask(request,
+ taskOptions,
+ callback,
+ query,
+ url,
+ userState);
+
+ }
+ lock (_timedTasksLock)
+ {
+ _tasks[request] = task;
+ }
+
+ var action = new Action(task.Start);
+ action.Invoke();
+ return true;
+ }
+#endif
+
+#if !NETCF
+ private object BuildRateLimitingTask(RestRequest request, ITaskOptions taskOptions, RestCallback callback, WebQuery query, string url, object userState)
+ {
+ var taskAction = new Action<bool>(skip =>
+ {
+ if (!skip)
+ {
+ BeginRequestImpl(request, callback, query, url, true /* isInternal */, userState);
+ }
+ else
+ {
+ callback(request,
+ new RestResponse { SkippedDueToRateLimitingRule = true },
+ userState);
+ }
+ });
+
+ return BuildRateLimitingTaskImpl(taskOptions, taskAction);
+ }
+
+ private object BuildRateLimitingTask<T>(RestRequest request,
+ ITaskOptions taskOptions,
+ RestCallback<T> callback,
+ WebQuery query,
+ string url,
+ object userState)
+ {
+ var taskAction = new Action<bool>(skip => BeginRequestImpl(request,
+ callback,
+ query,
+ url,
+ true /* isInternal */,
+ userState
+ ));
+
+ return BuildRateLimitingTaskImpl(taskOptions, taskAction);
+ }
+
+ private static object BuildRateLimitingTaskImpl(ITaskOptions taskOptions,
+ Action<bool> taskAction)
+ {
+ var innerType = taskOptions.GetDeclaredTypeForGeneric(typeof(ITaskOptions<>));
+ var rateType = typeof(RateLimitingRule<>).MakeGenericType(innerType);
+ var taskType = typeof(TimedTask<>).MakeGenericType(innerType);
+ var rateLimitingType = (RateLimitType)taskOptions.GetValue("RateLimitType");
+
+ object taskRule;
+ var getRateLimitStatus = taskOptions.GetValue("GetRateLimitStatus");
+ switch (rateLimitingType)
+ {
+ case RateLimitType.ByPercent:
+ var rateLimitingPercent = taskOptions.GetValue("RateLimitPercent");
+ taskRule = getRateLimitStatus != null
+ ? Activator.CreateInstance(rateType, getRateLimitStatus, rateLimitingPercent)
+ : Activator.CreateInstance(rateType, rateLimitingPercent);
+ break;
+ case RateLimitType.ByPredicate:
+ var rateLimitingPredicate = taskOptions.GetValue("RateLimitingPredicate");
+ taskRule = getRateLimitStatus != null
+ ? Activator.CreateInstance(rateType, getRateLimitStatus, rateLimitingPredicate)
+ : Activator.CreateInstance(rateType, rateLimitingPredicate);
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+
+ return Activator.CreateInstance(taskType,
+ taskOptions.DueTime,
+ taskOptions.RepeatInterval,
+ taskOptions.RepeatTimes,
+ taskOptions.ContinueOnError,
+ taskAction,
+ taskRule);
+ }
+#endif
+
+#if !WindowsPhone
+ private bool BeginRequestMultiPart(RestBase request, WebQuery query, string url, out WebQueryAsyncResult result, object userState)
+ {
+ var parameters = GetPostParameters(request);
+ if (parameters == null || parameters.Count() == 0)
+ {
+ result = null;
+ return false;
+ }
+
+ // [DC]: Default to POST if no method provided
+ query.Method = query.Method != WebMethod.Post && Method != WebMethod.Put ? WebMethod.Post : query.Method;
+ result = query.RequestAsync(url, parameters, userState);
+ return true;
+ }
+#else
+ private bool BeginRequestMultiPart(RestBase request, WebQuery query, string url, object userState)
+ {
+ var parameters = GetPostParameters(request);
+ if (parameters == null || parameters.Count() == 0)
+ {
+ return false;
+ }
+
+ // [DC]: Default to POST if no method provided
+ query.Method = query.Method != WebMethod.Post && Method != WebMethod.Put ? WebMethod.Post : query.Method;
+ query.RequestAsync(url, parameters, userState);
+ return true;
+ }
+#endif
+
+#if !WindowsPhone
+ private bool BeginRequestWithCache(RestBase request,
+ WebQuery query,
+ string url,
+ out WebQueryAsyncResult result,
+ object userState)
+ {
+ var cache = GetCache(request);
+ if (cache == null)
+ {
+ result = null;
+ return false;
+ }
+
+ var options = GetCacheOptions(request);
+ if (options == null)
+ {
+ result = null;
+ return false;
+ }
+
+ // [DC]: This is currently prefixed to the full URL
+ var function = GetCacheKeyFunction(request);
+ var key = function != null ? function.Invoke() : "";
+
+ switch (options.Mode)
+ {
+ case CacheMode.NoExpiration:
+ result = query.RequestAsync(url, key, cache, userState);
+ break;
+ case CacheMode.AbsoluteExpiration:
+ var expiry = options.Duration.FromNow();
+ result = query.RequestAsync(url, key, cache, expiry, userState);
+ break;
+ case CacheMode.SlidingExpiration:
+ result = query.RequestAsync(url, key, cache, options.Duration, userState);
+ break;
+ default:
+ throw new NotSupportedException("Unknown CacheMode");
+ }
+
+ return true;
+ }
+#else
+ private bool BeginRequestWithCache(RestBase request,
+ WebQuery query,
+ string url,
+ object userState)
+ {
+ var cache = GetCache(request);
+ if (cache == null)
+ {
+ return false;
+ }
+
+ var options = GetCacheOptions(request);
+ if (options == null)
+ {
+ return false;
+ }
+
+ // [DC]: This is currently prefixed to the full URL
+ var function = GetCacheKeyFunction(request);
+ var key = function != null ? function.Invoke() : "";
+
+ switch (options.Mode)
+ {
+ case CacheMode.NoExpiration:
+ query.RequestAsync(url, key, cache, userState);
+ break;
+ case CacheMode.AbsoluteExpiration:
+ var expiry = options.Duration.FromNow();
+ query.RequestAsync(url, key, cache, expiry, userState);
+ break;
+ case CacheMode.SlidingExpiration:
+ query.RequestAsync(url, key, cache, options.Duration, userState);
+ break;
+ default:
+ throw new NotSupportedException("Unknown CacheMode");
+ }
+
+ return true;
+ }
+#endif
+
+ private RestResponse BuildResponseFromResult(RestRequest request, WebQuery query)
+ {
+ request = request ?? new RestRequest();
+ var result = query.Result;
+ var response = BuildBaseResponse(result);
+
+ DeserializeEntityBody(request, response);
+ response.Tag = GetTag(request);
+
+ return response;
+ }
+
+ private RestResponse<T> BuildResponseFromResult<T>(RestRequest request, WebQuery query)
+ {
+ request = request ?? new RestRequest();
+ var result = query.Result;
+ var response = BuildBaseResponse<T>(result);
+
+ DeserializeEntityBody(request, response);
+ response.Tag = GetTag(request);
+
+ return response;
+ }
+
+#if NET40
+ private RestResponse<dynamic> BuildResponseFromResultDynamic(RestRequest request, WebQuery query)
+ {
+ request = request ?? new RestRequest();
+ var result = query.Result;
+ var response = BuildBaseResponse<dynamic>(result);
+
+ DeserializeEntityBodyDynamic(request, response);
+ response.Tag = GetTag(request);
+
+ return response;
+ }
+#endif
+
+ private static readonly Func<RestResponseBase, WebQueryResult, RestResponseBase> _baseSetter =
+ (response, result) =>
+ {
+ response.ContentStream = result.ContentStream;
+ response.InnerResponse = result.WebResponse;
+ response.InnerException = result.Exception;
+ response.RequestDate = result.RequestDate;
+ response.RequestUri = result.RequestUri;
+ response.RequestMethod = result.RequestHttpMethod;
+ response.RequestKeptAlive = result.RequestKeptAlive;
+ response.ResponseDate = result.ResponseDate;
+ response.ResponseUri = result.ResponseUri;
+ response.StatusCode = (HttpStatusCode)result.ResponseHttpStatusCode;
+ response.StatusDescription = result.ResponseHttpStatusDescription;
+ response.ContentType = result.ResponseType;
+ response.ContentLength = result.ResponseLength;
+ response.IsMock = result.IsMock;
+ response.TimedOut = result.TimedOut;
+ response.TimesTried = result.TimesTried;
+ if (result.WebResponse == null)
+ {
+ // [DC] WebResponse could be null, i.e. when streaming
+ return response;
+ }
+#if !SILVERLIGHT
+ response.Headers = result.WebResponse.Headers;
+#else
+ response.Headers = new NameValueCollection();
+ foreach(var key in result.WebResponse.Headers.AllKeys)
+ {
+ response.Headers.Add(key, result.WebResponse.Headers[key]);
+ }
+#endif
+
+#if !SILVERLIGHT && !NETCF
+ if(result.WebResponse is HttpWebResponse)
+ {
+ var cookies = (result.WebResponse as HttpWebResponse).Cookies;
+ if(cookies != null)
+ {
+ foreach (Cookie cookie in cookies)
+ {
+ response.Cookies.Add(cookie.Name, cookie.Value);
+ }
+ }
+ }
+#endif
+
+ return response;
+ };
+
+ private static RestResponse BuildBaseResponse(WebQueryResult result)
+ {
+ var response = new RestResponse();
+
+ _baseSetter.Invoke(response, result);
+
+ return response;
+ }
+
+ private static RestResponse<T> BuildBaseResponse<T>(WebQueryResult result)
+ {
+ var response = new RestResponse<T>();
+
+ _baseSetter.Invoke(response, result);
+
+ return response;
+ }
+
+ private bool ShouldDeserializeEntityBody(RestRequest request, RestResponseBase response, out IDeserializer deserializer)
+ {
+ deserializer = request.Deserializer ?? Deserializer;
+ if (deserializer == null || response.ContentStream == null || string.IsNullOrEmpty(response.ContentType))
+ {
+ return false;
+ }
+ if (response.InnerException != null)
+ {
+ Type errorResponseEntityType;
+ var getErrorResponseEntityType = request.GetErrorResponseEntityType ?? GetErrorResponseEntityType;
+ if (getErrorResponseEntityType != null && (errorResponseEntityType = getErrorResponseEntityType(request, response)) != null)
+ {
+ response.ErrorContentEntity = deserializer.Deserialize(response, errorResponseEntityType);
+ }
+ return false;
+ }
+
+ return true;
+ }
+
+ private void DeserializeEntityBody(RestRequest request, RestResponse response)
+ {
+ IDeserializer deserializer;
+ if (ShouldDeserializeEntityBody(request, response, out deserializer) && request.ResponseEntityType != null)
+ {
+ response.ContentEntity = deserializer.Deserialize(response, request.ResponseEntityType);
+ }
+ }
+
+ private void DeserializeEntityBody<T>(RestRequest request, RestResponse<T> response)
+ {
+ IDeserializer deserializer;
+ if (ShouldDeserializeEntityBody(request, response, out deserializer))
+ {
+ response.ContentEntity = deserializer.Deserialize<T>(response);
+ }
+ }
+
+#if NET40
+ private void DeserializeEntityBodyDynamic(RestRequest request, RestResponse<dynamic> response)
+ {
+ IDeserializer deserializer;
+ if (ShouldDeserializeEntityBody(request, response, out deserializer))
+ {
+ response.ContentEntity = deserializer.DeserializeDynamic(response);
+ }
+ }
+#endif
+
+ private void SetQueryMeta(RestRequest request, WebQuery query)
+ {
+ // Fill query collections with found value pairs
+ CoalesceWebPairsIntoCollection(query.Parameters, Parameters, request.Parameters);
+ CoalesceWebPairsIntoCollection(query.Cookies, Cookies, request.Cookies);
+
+ query.Headers.AddRange(Headers);
+ query.Headers.AddRange(request.Headers);
+
+ // [DC]: These properties are trumped by request over client
+ query.UserAgent = GetUserAgent(request);
+ query.Method = GetWebMethod(request);
+ query.Proxy = GetProxy(request);
+ query.RequestTimeout = GetTimeout(request);
+ query.DecompressionMethods = GetDecompressionMethods(request);
+ query.PostContent = GetPostContent(request);
+ query.Encoding = GetEncoding(request);
+
+#if !SILVERLIGHT
+ query.FollowRedirects = GetFollowRedirects(request);
+#endif
+ SerializeEntityBody(query, request);
+ }
+
+ // [DC]: Trump duplicates by request over client over info values
+ private static void CoalesceWebPairsIntoCollection(WebPairCollection target, params IEnumerable<WebPair>[] values)
+ {
+ var parameters = new WebPairCollection(values.SelectMany(value => value));
+
+ foreach (var pair in parameters)
+ {
+ if(target[pair.Name] == null)
+ {
+ target.Add(pair);
+ }
+ }
+ }
+
+ private void SerializeEntityBody(WebQuery query, RestRequest request)
+ {
+ var serializer = GetSerializer(request);
+ if (serializer == null)
+ {
+ // No suitable serializer for entity
+ return;
+ }
+
+ if (request.Entity == null || request.RequestEntityType == null)
+ {
+ // Not enough information to serialize
+ return;
+ }
+
+ var entityBody = serializer.Serialize(request.Entity, request.RequestEntityType);
+ query.Entity = !entityBody.IsNullOrBlank()
+ ? new WebEntity
+ {
+ Content = entityBody,
+ ContentEncoding = serializer.ContentEncoding,
+ ContentType = serializer.ContentType
+ }
+ : null;
+ }
+
+ private WebEntity SerializeExpectEntity(RestRequest request)
+ {
+ var serializer = GetSerializer(request);
+ if (serializer == null || request.ExpectEntity == null)
+ {
+ // No suitable serializer or entity
+ return null;
+ }
+
+ var entityBody = serializer.Serialize(request.ExpectEntity, request.RequestEntityType);
+ var entity = !entityBody.IsNullOrBlank()
+ ? new WebEntity
+ {
+ Content = entityBody,
+ ContentEncoding = serializer.ContentEncoding,
+ ContentType = serializer.ContentType
+ } : null;
+ return entity;
+ }
+
+ public WebQuery GetQueryFor(RestBase request, Uri uri)
+ {
+ var method = GetWebMethod(request);
+ var credentials = GetWebCredentials(request);
+ var info = GetInfo(request);
+ var traceEnabled = GetTraceEnabled(request);
+
+ // [DC]: UserAgent is set via Info
+ // [DC]: Request credentials trump client credentials
+ var query = credentials != null
+ ? credentials.GetQueryFor(uri.ToString(), request, info, method, traceEnabled)
+ : new BasicAuthWebQuery(info, traceEnabled);
+
+ query.PostProgress += QueryPostProgress;
+
+#if SILVERLIGHT
+ query.HasElevatedPermissions = HasElevatedPermissions;
+ query.SilverlightAcceptEncodingHeader = SilverlightAcceptEncodingHeader;
+ query.SilverlightUserAgentHeader = SilverlightUserAgentHeader;
+#endif
+ return query;
+ }
+
+ private void QueryPostProgress(object sender, PostProgressEventArgs e)
+ {
+ var args = new FileProgressEventArgs
+ {
+ FileName = e.FileName,
+ BytesWritten = e.BytesWritten,
+ TotalBytes = e.TotalBytes
+ };
+ OnFileProgress(args);
+ }
+
+ public void CancelStreaming()
+ {
+ lock (_streamingLock)
+ {
+ if (_streamQuery != null)
+ {
+ _streamQuery.IsStreaming = false;
+ }
+ }
+ }
+
+ public void CancelPeriodicTasks()
+ {
+ lock (_timedTasksLock)
+ {
+ // Copy to a new list, since canceling
+ // the task removes it from the _tasks
+ // list, the enumeration will throw
+ var toCancel = new List<TimedTask>();
+ toCancel.AddRange(_tasks.Values);
+ toCancel.ForEach(t => t.Stop());
+ }
+ }
+
+ public int GetIterationCount(RestRequest request)
+ {
+ var retryState = request.RetryState ?? RetryState;
+ var taskState = request.TaskState ?? TaskState;
+ if (retryState != null)
+ {
+ return retryState.RepeatCount;
+ }
+ if (taskState != null)
+ {
+ return taskState.RepeatCount;
+ }
+ return 0;
+ }
+
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Net;
+using System.Text;
+using Hammock.Extensions;
+using Hammock.Web;
+
+#if SILVERLIGHT
+using Hammock.Silverlight.Compat;
+#endif
+
+namespace Hammock
+{
+#if !Silverlight
+ [Serializable]
+#endif
+ public class RestRequest : RestBase
+ {
+ private object _entity;
+ private object _expectEntity;
+
+ protected internal virtual Web.WebHeaderCollection ExpectHeaders { get; set; }
+ public virtual HttpStatusCode? ExpectStatusCode { get; set; }
+ public virtual string ExpectStatusDescription { get; set; }
+ public virtual string ExpectContent { get; set; }
+ public virtual string ExpectContentType { get; set; }
+
+ public RestRequest()
+ {
+ Initialize();
+ }
+
+ private void Initialize()
+ {
+ ExpectHeaders = new Web.WebHeaderCollection();
+ }
+
+ public virtual object Entity
+ {
+ get
+ {
+ return _entity;
+ }
+ set
+ {
+ if (_entity != null && _entity.Equals(value))
+ {
+ return;
+ }
+
+ _entity = value;
+ OnPropertyChanged("Entity");
+
+ // [DC] Automatically posts an entity unless put is declared
+ RequestEntityType = _entity.GetType();
+ if (_entity != null && (Method != WebMethod.Post && Method != WebMethod.Put))
+ {
+ Method = WebMethod.Post;
+ }
+ }
+ }
+
+ public virtual object ExpectEntity
+ {
+ get
+ {
+ return _expectEntity;
+ }
+ set
+ {
+ if (_expectEntity != null && _expectEntity.Equals(value))
+ {
+ return;
+ }
+
+ _expectEntity = value;
+ OnPropertyChanged("ExpectEntity");
+ }
+ }
+
+ public virtual Type ResponseEntityType { get; set; }
+ public virtual Type RequestEntityType { get; set; }
+
+ public Uri BuildEndpoint(RestClient client)
+ {
+ var sb = new StringBuilder();
+
+ var path = Path.IsNullOrBlank()
+ ? client.Path.IsNullOrBlank() ? "" : client.Path
+ : Path;
+
+ var versionPath = VersionPath.IsNullOrBlank()
+ ? client.VersionPath.IsNullOrBlank() ? "" : client.VersionPath
+ : VersionPath;
+ var skipAuthority = client.Authority.IsNullOrBlank();
+
+ sb.Append(skipAuthority ? "" : client.Authority);
+ sb.Append(skipAuthority ? "" : client.Authority.EndsWith("/") ? "" : "/");
+ sb.Append(skipAuthority ? "" : versionPath.IsNullOrBlank() ? "" : versionPath);
+ if (!skipAuthority && !versionPath.IsNullOrBlank())
+ {
+ sb.Append(versionPath.EndsWith("/") ? "" : "/");
+ }
+ sb.Append(path.IsNullOrBlank() ? "" : path.StartsWith("/") ? path.Substring(1) : path);
+
+ Uri uri;
+ Uri.TryCreate(sb.ToString(), UriKind.RelativeOrAbsolute, out uri);
+
+ var queryStringHandling = QueryHandling ?? client.QueryHandling ?? Hammock.QueryHandling.None;
+
+ switch (queryStringHandling)
+ {
+ case Hammock.QueryHandling.AppendToParameters:
+ WebParameterCollection parameters;
+ uri = uri.UriMinusQuery(out parameters);
+ foreach (var parameter in parameters)
+ {
+ Parameters.Add(parameter);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return uri;
+ }
+
+ public void ExpectHeader(string name, string value)
+ {
+ ExpectHeaders.Add(name, value);
+ }
+ }
+}
+
+
--- /dev/null
+using System;
+using System.IO;
+using System.Net;
+using Hammock.Extensions;
+
+#if SILVERLIGHT
+using Hammock.Silverlight.Compat;
+#else
+using System.Collections.Specialized;
+#endif
+
+namespace Hammock
+{
+#if !Silverlight
+ [Serializable]
+#endif
+ public class RestResponseBase : IDisposable
+ {
+ private string _content;
+ public virtual string Content
+ {
+ get
+ {
+ if(_content == null && ContentStream != null)
+ {
+ ContentStream = ReplaceContentStreamWithMemoryStream();
+ using (var reader = new StreamReader(ContentStream))
+ {
+ _content = reader.ReadToEnd();
+ }
+ if (ContentStream.CanSeek)
+ {
+ ContentStream.Position = 0;
+ }
+ }
+ return _content;
+ }
+ }
+
+ private byte[] _contentBytes;
+ public virtual byte[] ContentBytes
+ {
+ get
+ {
+ if(_contentBytes == null && ContentStream != null)
+ {
+ ContentStream = ReplaceContentStreamWithMemoryStream();
+ _contentBytes = ReadFully(ContentStream);
+ if(ContentStream.CanSeek)
+ {
+ ContentStream.Position = 0;
+ }
+ }
+ return _contentBytes;
+ }
+ }
+
+ public virtual object ErrorContentEntity { get; set; }
+ public virtual Stream ContentStream { get; set; }
+ public virtual WebResponse InnerResponse { get; set; }
+ public virtual Exception InnerException { get; set; }
+ public virtual DateTime? RequestDate { get; set; }
+ public virtual DateTime? ResponseDate { get; set; }
+ public virtual string RequestMethod { get; set; }
+ public virtual bool RequestKeptAlive { get; set; }
+ public virtual HttpStatusCode StatusCode { get; set; }
+ public virtual string StatusDescription { get; set; }
+ public virtual string ContentType { get; set; }
+ public virtual long ContentLength { get; set; }
+ public virtual Uri RequestUri { get; set; }
+ public virtual Uri ResponseUri { get; set; }
+ public virtual bool IsMock { get; set; }
+ public virtual bool TimedOut { get; set; }
+ public virtual int TimesTried { get; set; }
+ public virtual object Tag { get; set; }
+ public virtual NameValueCollection Headers { get; set; }
+ public virtual NameValueCollection Cookies { get; set; }
+ public virtual bool SkippedDueToRateLimitingRule { get; set; }
+ public virtual bool IsFromCache
+ {
+ get
+ {
+ return StatusCode == 0 &&
+ StatusDescription.IsNullOrBlank() &&
+ Content != null;
+ }
+ }
+
+ public RestResponseBase()
+ {
+ Initialize();
+ }
+
+ private void Initialize()
+ {
+ Headers = new NameValueCollection(0);
+ Cookies = new NameValueCollection(0);
+ }
+
+ // http://www.yoda.arachsys.com/csharp/readbinary.html
+ public static byte[] ReadFully(Stream stream)
+ {
+ const int initialLength = 32768;
+ var buffer = new byte[initialLength];
+ var read = 0;
+
+ int chunk;
+ while ((chunk = stream.Read(buffer, read, buffer.Length - read)) > 0)
+ {
+ read += chunk;
+ if (read != buffer.Length)
+ {
+ continue;
+ }
+ var nextByte = stream.ReadByte();
+ if (nextByte == -1)
+ {
+ return buffer;
+ }
+ var newBuffer = new byte[buffer.Length * 2];
+ Array.Copy(buffer, newBuffer, buffer.Length);
+ newBuffer[read] = (byte)nextByte;
+ buffer = newBuffer;
+ read++;
+ }
+ var ret = new byte[read];
+ Array.Copy(buffer, ret, read);
+ return ret;
+ }
+
+ private Stream ReplaceContentStreamWithMemoryStream()
+ {
+ if(ContentStream is DurableMemoryStream)
+ {
+ return ContentStream;
+ }
+
+ var buffer = new byte[4096];
+ var stream = new MemoryStream();
+ var count = 0;
+ do
+ {
+ if (ContentStream == null)
+ {
+ continue;
+ }
+ count = ContentStream.Read(buffer, 0, buffer.Length);
+ stream.Write(buffer, 0, count);
+ } while (count != 0);
+
+ if (ContentStream != null)
+ {
+ ContentStream.Close();
+ ContentStream.Dispose();
+ }
+
+ if(stream.CanSeek)
+ {
+ stream.Position = 0;
+ }
+
+ return new DurableMemoryStream(stream);
+ }
+
+ private class DurableMemoryStream : MemoryStream
+ {
+ private readonly Stream _stream;
+
+ public DurableMemoryStream(Stream stream)
+ {
+ _stream = stream;
+ }
+
+ public override IAsyncResult BeginRead(byte[] buffer, int offset, int count,
+ AsyncCallback callback, object state)
+ {
+ return _stream.BeginRead(buffer, offset, count, callback, state);
+ }
+
+ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count,
+ AsyncCallback callback, object state)
+ {
+ return _stream.BeginWrite(buffer, offset, count, callback, state);
+ }
+
+ public override bool CanRead
+ {
+ get { return _stream.CanRead; }
+ }
+
+ public override bool CanSeek
+ {
+ get { return _stream.CanSeek; }
+ }
+
+ public override bool CanWrite
+ {
+ get { return _stream.CanWrite; }
+ }
+
+ public override void Close()
+ {
+ _stream.Flush();
+ }
+
+ public override int EndRead(IAsyncResult asyncResult)
+ {
+ return _stream.EndRead(asyncResult);
+ }
+
+ public override void EndWrite(IAsyncResult asyncResult)
+ {
+ _stream.EndWrite(asyncResult);
+ }
+
+ public override void Flush()
+ {
+ _stream.Flush();
+ }
+
+ public override long Length
+ {
+ get
+ {
+ return _stream.Length;
+ }
+ }
+
+ public override long Position
+ {
+ get
+ {
+ return _stream.Position;
+ }
+ set
+ {
+ _stream.Position = value;
+ }
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ return _stream.Read(buffer, offset, count);
+ }
+
+ public override int ReadByte()
+ {
+ return _stream.ReadByte();
+ }
+
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ return _stream.Seek(offset, origin);
+ }
+
+ public override void SetLength(long value)
+ {
+ _stream.SetLength(value);
+ }
+
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ _stream.Write(buffer, offset, count);
+ }
+
+ public override void WriteByte(byte value)
+ {
+ _stream.WriteByte(value);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if(disposing)
+ {
+ _stream.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+ }
+
+ public void SetContent(string content)
+ {
+ _content = content;
+ }
+
+ public void Dispose()
+ {
+ if(ContentStream != null)
+ {
+ ContentStream.Dispose();
+ }
+ }
+ }
+
+#if !Silverlight
+ [Serializable]
+#endif
+ public class RestResponse : RestResponseBase
+ {
+ public virtual object ContentEntity { get; set; }
+ }
+
+#if !Silverlight
+ [Serializable]
+#endif
+ public class RestResponse<T> : RestResponseBase
+ {
+ public virtual T ContentEntity { get; set; }
+ }
+}
+
+
--- /dev/null
+using System;
+using System.Net;
+
+namespace Hammock.Retries
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class ConnectionClosed : RetryErrorCondition
+ {
+ public override Predicate<Exception> RetryIf
+ {
+ get
+ {
+ return e =>
+ {
+ var we = e as WebException;
+ return we != null && (we.Status == WebExceptionStatus.ConnectionClosed || we.Status == WebExceptionStatus.KeepAliveFailure);
+ };
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Hammock.Retries
+{
+ public interface IRetryCondition
+ {
+
+ }
+
+ public interface IRetryCondition<T> : IRetryCondition
+ {
+ Predicate<T> RetryIf { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Hammock.Retries
+{
+ public interface IRetryCustomCondition
+ {
+
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Net;
+
+namespace Hammock.Retries
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class NetworkError : RetryErrorCondition
+ {
+ public override Predicate<Exception> RetryIf
+ {
+ get
+ {
+ return e =>
+ {
+ var we = (e as WebException);
+
+ return we != null && (we.Status != WebExceptionStatus.Success &&
+#if !SILVERLIGHT
+ we.Status != WebExceptionStatus.ProtocolError &&
+#endif
+ we.Status != WebExceptionStatus.Pending);
+ };
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Hammock.Retries
+{
+ public abstract class RetryCondition<T> : IRetryCondition<T>
+ {
+ public abstract Predicate<T> RetryIf { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Hammock.Retries
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public abstract class RetryCustomCondition<T> :
+ IRetryCustomCondition,
+ IRetryCondition<T>
+ {
+ public virtual Func<T> ConditionFunction { get; set; }
+ public virtual Predicate<T> RetryIf
+ {
+ get
+ {
+ return t => false;
+ }
+ }
+ }
+}
--- /dev/null
+using System;
+
+namespace Hammock.Retries
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public abstract class RetryErrorCondition : IRetryCondition<Exception>
+ {
+ public virtual Predicate<Exception> RetryIf
+ {
+ get { return e => false; }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Hammock.Extensions;
+
+namespace Hammock.Retries
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class RetryPolicy
+ {
+ public virtual ICollection<IRetryCondition> RetryConditions { get; set; }
+
+ public virtual int RetryCount { get; set; }
+
+ public RetryPolicy()
+ {
+ Initialize();
+ }
+
+ private void Initialize()
+ {
+ RetryConditions = new List<IRetryCondition>(0);
+ }
+
+ public virtual void RetryOn(IEnumerable<IRetryCondition> conditions)
+ {
+ foreach(var condition in conditions)
+ {
+ RetryConditions.Add(condition);
+ }
+ }
+
+ public virtual void RetryOn(params IRetryCondition[] conditions)
+ {
+ var enumerable = conditions.ToList();
+ RetryOn(enumerable);
+ }
+ }
+}
--- /dev/null
+using System;
+using Hammock.Web;
+
+namespace Hammock.Retries
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public abstract class RetryResultCondition : IRetryCondition<WebQueryResult>
+ {
+ public virtual Predicate<WebQueryResult> RetryIf
+ {
+ get { return r => false; }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Net;
+
+namespace Hammock.Retries
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class Timeout : RetryErrorCondition
+ {
+ public override Predicate<Exception> RetryIf
+ {
+ get
+ {
+ return e =>
+ {
+ var we = (e as WebException);
+ return we != null && (we.Status == WebExceptionStatus.RequestCanceled || we.Status == WebExceptionStatus.Timeout);
+ };
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<ClassDiagram MajorVersion="1" MinorVersion="1">
+ <Class Name="Hammock.Retries.RetryErrorCondition">
+ <Position X="8" Y="3.75" Width="1.5" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAA=</HashCode>
+ <FileName>Retries\RetryErrorCondition.cs</FileName>
+ </TypeIdentifier>
+ <Lollipop Position="0.2" />
+ </Class>
+ <Class Name="Hammock.Retries.RetryPolicy">
+ <Position X="2.5" Y="1" Width="2.25" />
+ <TypeIdentifier>
+ <HashCode>QAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAA=</HashCode>
+ <FileName>Retries\RetryPolicy.cs</FileName>
+ </TypeIdentifier>
+ <ShowAsCollectionAssociation>
+ <Property Name="RetryConditions" />
+ </ShowAsCollectionAssociation>
+ </Class>
+ <Class Name="Hammock.Retries.Timeout" Collapsed="true">
+ <Position X="10.25" Y="5.5" Width="1.5" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAA=</HashCode>
+ <FileName>Retries\Timeout.cs</FileName>
+ </TypeIdentifier>
+ </Class>
+ <Class Name="Hammock.Retries.NetworkError" Collapsed="true">
+ <Position X="5.75" Y="5.5" Width="1.5" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAA=</HashCode>
+ <FileName>Retries\NetworkError.cs</FileName>
+ </TypeIdentifier>
+ </Class>
+ <Class Name="Hammock.Retries.ConnectionClosed" Collapsed="true">
+ <Position X="7.75" Y="5.5" Width="2" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAA=</HashCode>
+ <FileName>Retries\ConnectionClosed.cs</FileName>
+ </TypeIdentifier>
+ </Class>
+ <Interface Name="Hammock.Retries.IRetryCondition" Collapsed="true">
+ <Position X="2.5" Y="3.75" Width="2.25" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Retries\IRetryCondition.cs</FileName>
+ </TypeIdentifier>
+ </Interface>
+ <Interface Name="Hammock.Retries.IRetryCondition<T>">
+ <Position X="2.5" Y="5" Width="2.25" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAA=</HashCode>
+ <FileName>Retries\IRetryCondition.cs</FileName>
+ </TypeIdentifier>
+ </Interface>
+ <Font Name="Segoe UI" Size="9" />
+</ClassDiagram>
\ No newline at end of file
--- /dev/null
+using System;
+#if NET40
+using System.Dynamic;
+#endif
+
+namespace Hammock.Serialization
+{
+ public class DefaultJsonSerializer : IDeserializer
+ {
+ public object Deserialize(RestResponseBase response, Type type)
+ {
+ var result = JsonParser.Deserialize(response.Content, type);
+ return result;
+ }
+
+ public T Deserialize<T>(RestResponseBase response)
+ {
+ var result = JsonParser.Deserialize<T>(response.Content);
+ return result;
+ }
+
+#if NET40
+ public dynamic DeserializeDynamic(RestResponseBase response)
+ {
+ var result = JsonParser.Deserialize(response.Content);
+ return result;
+ }
+#endif
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+#if NET40
+using System.Dynamic;
+#endif
+using System.IO;
+using System.Runtime.Serialization.Json;
+
+namespace Hammock.Serialization
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class HammockDataContractJsonSerializer : Utf8Serializer, ISerializer, IDeserializer
+ {
+ private readonly Dictionary<RuntimeTypeHandle, DataContractJsonSerializer> _serializers =
+ new Dictionary<RuntimeTypeHandle, DataContractJsonSerializer>();
+
+ #region ISerializer Members
+
+ public virtual string Serialize(object instance, Type type)
+ {
+ string result;
+ using (var stream = new MemoryStream())
+ {
+ var serializer = CacheOrGetSerializerFor(type);
+ serializer.WriteObject(stream, instance);
+
+ var data = stream.ToArray();
+ result = ContentEncoding.GetString(data, 0, data.Length);
+ }
+ return result;
+ }
+
+ public virtual string ContentType
+ {
+ get { return "application/json"; }
+ }
+
+ #endregion
+
+ #region IDeserializer Members
+
+ public virtual object Deserialize(RestResponseBase response, Type type)
+ {
+ object instance;
+ using (var stream = new MemoryStream(ContentEncoding.GetBytes(response.Content)))
+ {
+ var serializer = CacheOrGetSerializerFor(type);
+ instance = serializer.ReadObject(stream);
+ }
+ return instance;
+ }
+
+ public virtual T Deserialize<T>(RestResponseBase response)
+ {
+ var type = typeof (T);
+ T instance;
+ using (var stream = new MemoryStream(ContentEncoding.GetBytes(response.Content)))
+ {
+ var serializer = CacheOrGetSerializerFor(type);
+ instance = (T) serializer.ReadObject(stream);
+ }
+ return instance;
+ }
+
+#if NET40
+ public dynamic DeserializeDynamic(RestResponseBase response)
+ {
+ throw new NotSupportedException();
+ }
+#endif
+
+ #endregion
+
+ private DataContractJsonSerializer CacheOrGetSerializerFor(Type type)
+ {
+ var handle = type.TypeHandle;
+ if (_serializers.ContainsKey(handle))
+ {
+ return _serializers[handle];
+ }
+
+ var serializer = new DataContractJsonSerializer(type);
+ _serializers.Add(handle, serializer);
+
+ return serializer;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+#if NET40
+using System.Dynamic;
+#endif
+using System.IO;
+using System.Runtime.Serialization;
+using System.Xml;
+#if !NET20
+using System.Xml.Linq;
+#endif
+
+namespace Hammock.Serialization
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class HammockDataContractSerializer : Utf8Serializer, ISerializer, IDeserializer
+ {
+ private readonly Dictionary<RuntimeTypeHandle, DataContractSerializer> _serializers =
+ new Dictionary<RuntimeTypeHandle, DataContractSerializer>();
+
+#if !SILVERLIGHT
+ [NonSerialized]
+#endif
+ private readonly XmlWriterSettings _settings;
+
+ public HammockDataContractSerializer(XmlWriterSettings settings)
+ {
+ _settings = settings;
+ }
+
+ #region IDeserializer Members
+
+ public virtual object Deserialize(RestResponseBase response, Type type)
+ {
+ using (var stringReader = new StringReader(response.Content))
+ {
+ var xmlRoot = XElement.Load(stringReader);
+ var serializer = CacheOrGetSerializerFor(type);
+
+ using (var reader = xmlRoot.CreateReader())
+ {
+ return serializer.ReadObject(reader);
+ }
+ }
+ }
+
+ public virtual T Deserialize<T>(RestResponseBase response)
+ {
+ using (var stringReader = new StringReader(response.Content))
+ {
+ var xmlRoot = XElement.Load(stringReader);
+ var serializer = CacheOrGetSerializerFor(typeof (T));
+
+ using (var reader = xmlRoot.CreateReader())
+ {
+ return (T) serializer.ReadObject(reader);
+ }
+ }
+ }
+
+#if NET40
+ public dynamic DeserializeDynamic(RestResponseBase response)
+ {
+ throw new NotSupportedException();
+ }
+#endif
+
+ #endregion
+
+ #region ISerializer Members
+
+ public virtual string Serialize(object instance, Type type)
+ {
+ string result;
+
+ using (var stream = new MemoryStream())
+ {
+ using (var writer = XmlWriter.Create(stream, _settings))
+ {
+
+ var serializer = CacheOrGetSerializerFor(type);
+ writer.WriteStartDocument();
+ serializer.WriteObject(writer, instance);
+ writer.Flush();
+ }
+
+ var data = stream.ToArray();
+ result = ContentEncoding.GetString(data, 0, data.Length);
+ }
+
+ return result;
+ }
+
+ public virtual string ContentType
+ {
+ get { return "application/xml"; }
+ }
+
+ #endregion
+
+ private DataContractSerializer CacheOrGetSerializerFor(Type type)
+ {
+ var handle = type.TypeHandle;
+ if (_serializers.ContainsKey(handle))
+ {
+ return _serializers[handle];
+ }
+
+ var serializer = new DataContractSerializer(type);
+ _serializers.Add(handle, serializer);
+
+ return serializer;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Web.Script.Serialization;
+
+namespace Hammock.Serialization
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class HammockJavaScriptSerializer : Utf8Serializer, ISerializer, IDeserializer
+ {
+ private readonly JavaScriptSerializer _serializer;
+
+ public HammockJavaScriptSerializer(JavaScriptTypeResolver resolver)
+ {
+ _serializer = new JavaScriptSerializer(resolver);
+ }
+
+ public HammockJavaScriptSerializer(JavaScriptTypeResolver resolver, IEnumerable<JavaScriptConverter> converters)
+ {
+ _serializer = new JavaScriptSerializer(resolver);
+ _serializer.RegisterConverters(converters);
+ }
+
+ public HammockJavaScriptSerializer(IEnumerable<JavaScriptConverter> converters)
+ {
+ _serializer = new JavaScriptSerializer();
+ _serializer.RegisterConverters(converters);
+ }
+
+ public virtual string Serialize(object instance, Type type)
+ {
+ return _serializer.Serialize(instance);
+ }
+
+ public virtual string ContentType
+ {
+ get { return "application/json"; }
+ }
+
+ public virtual object Deserialize(RestResponse response, Type type)
+ {
+ return _serializer.DeserializeObject(response.Content);
+ }
+
+ public virtual T Deserialize<T>(RestResponse<T> response)
+ {
+ return _serializer.Deserialize<T>(response.Content);
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Xml;
+using System.Xml.Serialization;
+#if NET40
+using System.Dynamic;
+#endif
+
+namespace Hammock.Serialization
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class HammockXmlSerializer : Utf8Serializer, ISerializer, IDeserializer
+ {
+ private readonly Dictionary<RuntimeTypeHandle, XmlSerializer> _serializers =
+ new Dictionary<RuntimeTypeHandle, XmlSerializer>();
+
+ [NonSerialized]
+ private readonly XmlWriterSettings _settings;
+
+ [NonSerialized]
+ private readonly XmlSerializerNamespaces _namespaces;
+
+ public HammockXmlSerializer(XmlWriterSettings settings)
+ {
+ _settings = settings;
+ }
+
+ public HammockXmlSerializer(XmlWriterSettings settings, XmlSerializerNamespaces namespaces) : this(settings)
+ {
+ _namespaces = namespaces;
+ }
+
+ #region ISerializer Methods
+
+ public virtual string Serialize(object instance, Type type)
+ {
+ string result;
+ using (var stream = new MemoryStream())
+ {
+ using (var writer = XmlWriter.Create(stream, _settings))
+ {
+ var serializer = CacheOrGetSerializerFor(type);
+
+ if (_namespaces != null)
+ {
+ serializer.Serialize(writer, instance, _namespaces);
+ }
+ else
+ {
+ serializer.Serialize(writer, instance);
+ }
+ }
+
+#if !Smartphone && !NETCF
+ result = ContentEncoding.GetString(stream.ToArray());
+#else
+ result = ContentEncoding.GetString(stream.ToArray(), 0, (int)stream.Length);
+#endif
+ }
+ return result;
+ }
+
+ #endregion
+
+ public virtual string ContentType
+ {
+ get { return "application/xml"; }
+ }
+
+ #region IDeserializer Methods
+
+ public virtual object Deserialize(RestResponseBase response, Type type)
+ {
+ object instance;
+ var serializer = CacheOrGetSerializerFor(type);
+ using(var reader = new StringReader(response.Content))
+ {
+ instance = serializer.Deserialize(reader);
+ }
+ return instance;
+ }
+
+ public virtual T Deserialize<T>(RestResponseBase response)
+ {
+ T instance;
+ var serializer = CacheOrGetSerializerFor(typeof(T));
+ using (var reader = new StringReader(response.Content))
+ {
+ instance = (T) serializer.Deserialize(reader);
+ }
+ return instance;
+ }
+
+#if NET40
+ public virtual dynamic DeserializeDynamic(RestResponseBase response)
+ {
+ var result = Deserialize<dynamic>(response);
+ return result;
+ }
+#endif
+
+ #endregion
+
+ private XmlSerializer CacheOrGetSerializerFor(Type type)
+ {
+ var handle = type.TypeHandle;
+ if (_serializers.ContainsKey(handle))
+ {
+ return _serializers[handle];
+ }
+
+ var serializer = new XmlSerializer(type);
+ _serializers.Add(handle, serializer);
+
+ return serializer;
+ }
+ }
+}
+
+
--- /dev/null
+using System;
+#if NET40
+using System.Dynamic;
+#endif
+
+namespace Hammock.Serialization
+{
+ public interface IDeserializer
+ {
+ object Deserialize(RestResponseBase response, Type type);
+ T Deserialize<T>(RestResponseBase response);
+#if NET40
+ dynamic DeserializeDynamic(RestResponseBase response);
+#endif
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Text;
+
+namespace Hammock.Serialization
+{
+ public interface ISerializer
+ {
+ string Serialize(object instance, Type type);
+ string ContentType { get; }
+ Encoding ContentEncoding { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+#region Public Domain License
+/*
+ * JSON Parser
+ * Written by Daniel Crenna
+ * (http://danielcrenna.com)
+ *
+ * This work is public domain.
+ *
+ * "The person who associated a work with this document has
+ * dedicated the work to the Commons by waiving all of his
+ * or her rights to the work worldwide under copyright law
+ * and all related or neighboring legal rights he or she
+ * had in the work, to the extent allowable by law."
+ *
+ * For more information, please visit:
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+#if NET40
+using System.Dynamic;
+#endif
+#if NETCF
+using Hammock.Extensions;
+#endif
+
+
+namespace Hammock.Serialization
+{
+ /// <summary>
+ /// Possible JSON tokens in parsed input.
+ /// </summary>
+ public enum JsonToken
+ {
+ Unknown,
+ LeftBrace,
+ RightBrace,
+ Colon,
+ Comma,
+ LeftBracket,
+ RightBracket,
+ String,
+ Number,
+ True,
+ False,
+ Null
+ }
+
+ /// <summary>
+ /// Exception raised when <see cref="JsonParser" /> encounters an invalid token.
+ /// </summary>
+ public class InvalidJsonException : Exception
+ {
+ public InvalidJsonException(string message)
+ : base(message)
+ {
+
+ }
+ }
+
+#if NET40
+ public interface IJson { }
+
+ public class JsonArray : DynamicObject, IEnumerable, IJson
+ {
+ private readonly List<IJson> _collection;
+
+ public JsonArray(ICollection<object> collection)
+ {
+ _collection = new List<IJson>(collection.Count);
+ foreach (var instance in collection.Cast<IDictionary<string, object>>())
+ {
+ _collection.Add(new JsonObject(instance));
+ }
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return _collection.GetEnumerator();
+ }
+ }
+
+ public class JsonObject : DynamicObject, IJson
+ {
+ private readonly IDictionary<string, object> _hash = new Dictionary<string, object>();
+
+ public JsonObject(IDictionary<string, object> hash)
+ {
+ _hash = hash;
+ }
+
+ public override bool TrySetMember(SetMemberBinder binder, object value)
+ {
+ var name = Underscored(binder.Name);
+ _hash[name] = value;
+ return _hash[name] == value;
+ }
+
+ public override bool TryGetMember(GetMemberBinder binder, out object result)
+ {
+ var name = Underscored(binder.Name);
+ return YieldMember(name, out result);
+ }
+
+ private bool YieldMember(string name, out object result)
+ {
+ if (_hash.ContainsKey(name))
+ {
+ result = _hash[name];
+
+ if (result is IDictionary<string, object>)
+ {
+ result = new JsonObject((IDictionary<string, object>)result);
+ return true;
+ }
+
+ return _hash[name] == result;
+ }
+ result = null;
+ return false;
+ }
+
+ private static string Underscored(IEnumerable<char> pascalCase)
+ {
+ var sb = new StringBuilder();
+ var i = 0;
+ foreach (var c in pascalCase)
+ {
+ if (char.IsUpper(c) && i > 0)
+ {
+ sb.Append("_");
+ }
+ sb.Append(c);
+ i++;
+ }
+ return sb.ToString().ToLowerInvariant();
+ }
+ }
+#endif
+
+ /// <summary>
+ /// A parser for JSON.
+ /// <seealso cref="http://json.org" />
+ /// </summary>
+ public class JsonParser
+ {
+#if !NETCF
+ private const NumberStyles JsonNumbers = NumberStyles.Float;
+#endif
+ private static readonly IDictionary<Type, PropertyInfo[]> _cache;
+
+ private static readonly char[] _base16 = new[]
+ {
+ '0', '1', '2', '3',
+ '4', '5', '6', '7',
+ '8', '9', 'A', 'B',
+ 'C', 'D', 'E', 'F'
+ };
+
+ static JsonParser()
+ {
+ _cache = new Dictionary<Type, PropertyInfo[]>(0);
+ }
+
+ public static string Serialize<T>(T instance)
+ {
+ var bag = GetBagForObject(instance);
+
+ return ToJson(bag);
+ }
+
+ public static object Deserialize(string json, Type type)
+ {
+ object instance;
+ var map = PrepareInstance(out instance, type);
+ var bag = FromJson(json);
+
+ DeserializeImpl(map, bag, instance);
+ return instance;
+ }
+
+ public static T Deserialize<T>(string json)
+ {
+ T instance;
+ var map = PrepareInstance(out instance);
+ var bag = FromJson(json);
+
+ DeserializeImpl(map, bag, instance);
+ return instance;
+ }
+
+#if NET40
+ public static dynamic Deserialize(string json)
+ {
+ JsonToken type;
+ var inner = FromJson(json, out type);
+ dynamic instance = null;
+
+ switch (type)
+ {
+ case JsonToken.LeftBrace:
+ var @object = (IDictionary<string, object>)inner.Single().Value;
+ instance = new JsonObject(@object);
+ break;
+ case JsonToken.LeftBracket:
+ var @array = (IList<object>)inner.Single().Value;
+ instance = new JsonArray(@array);
+ break;
+ }
+
+ return instance;
+ }
+#endif
+
+ private static void DeserializeImpl(IEnumerable<PropertyInfo> map,
+ IDictionary<string, object> bag,
+ object instance)
+ {
+ DeserializeType(map, bag, instance);
+ }
+
+ private static void DeserializeImpl<T>(IEnumerable<PropertyInfo> map,
+ IDictionary<string, object> bag,
+ T instance)
+ {
+ DeserializeType(map, bag, instance);
+ }
+
+ private static void DeserializeType(IEnumerable<PropertyInfo> map, IDictionary<string, object> bag, object instance)
+ {
+ foreach (var info in map)
+ {
+ var key = info.Name;
+ if (!bag.ContainsKey(key))
+ {
+ key = info.Name.Replace("_", "");
+ if (!bag.ContainsKey(key))
+ {
+ key = info.Name.Replace("-", "");
+ if (!bag.ContainsKey(key))
+ {
+ continue;
+ }
+ }
+ }
+
+ var value = bag[key];
+ if (info.PropertyType == typeof(DateTime))
+ {
+ // Dates (Not part of spec, using lossy epoch convention)
+ var seconds = Int32.Parse(
+ value.ToString(), NumberStyles.Number, CultureInfo.InvariantCulture
+ );
+ var time = new DateTime(1970, 1, 1).ToUniversalTime();
+ value = time.AddSeconds(seconds);
+ }
+
+ if (info.PropertyType == typeof(byte[]))
+ {
+ var bytes = (List<object>)value;
+#if NETCF
+ value = bytes.Select(o => Convert.ToByte(o)).ToArray();
+#else
+ value = bytes.Select(Convert.ToByte).ToArray();
+#endif
+ }
+
+ if (info.PropertyType == typeof(double))
+ {
+ value = Convert.ToDouble(value);
+ }
+
+ if (info.PropertyType == typeof(int))
+ {
+ value = Convert.ToInt32(value);
+ }
+
+ if (info.PropertyType == typeof(long))
+ {
+ value = Convert.ToInt64(value);
+ }
+
+ info.SetValue(instance, value, null);
+ }
+ }
+
+ public static IDictionary<string, object> FromJson(string json)
+ {
+ JsonToken type;
+
+ var result = FromJson(json, out type);
+
+ switch (type)
+ {
+ case JsonToken.LeftBrace:
+ var @object = (IDictionary<string, object>)result.Single().Value;
+ return @object;
+ }
+
+ return result;
+ }
+
+ public static IDictionary<string, object> FromJson(string json, out JsonToken type)
+ {
+ var data = json.ToCharArray();
+ var index = 0;
+
+ // Rewind index for first token
+ var token = NextToken(data, ref index);
+ switch (token)
+ {
+ case JsonToken.LeftBrace: // Start Object
+ case JsonToken.LeftBracket: // Start Array
+ index--;
+ type = token;
+ break;
+ default:
+ throw new InvalidJsonException("JSON must begin with an object or array");
+ }
+
+ return ParseObject(data, ref index);
+ }
+
+ public static string ToJson(IDictionary<string, object> bag)
+ {
+ var sb = new StringBuilder(0);
+
+ SerializeItem(sb, bag);
+
+ return sb.ToString();
+ }
+
+ internal static IDictionary<string, object> GetBagForObject(Type type, object instance)
+ {
+ CacheReflection(type);
+
+ if (type.FullName == null)
+ {
+ return null;
+ }
+
+ var anonymous = type.FullName.Contains("__AnonymousType");
+ var map = _cache[type];
+
+ IDictionary<string, object> bag = InitializeBag();
+ foreach (var info in map)
+ {
+ var readWrite = (info.CanWrite && info.CanRead);
+ if (!readWrite && !anonymous)
+ {
+ continue;
+ }
+ var value = info.GetValue(instance, null);
+ bag.Add(info.Name, value);
+ }
+
+ return bag;
+ }
+
+ internal static IDictionary<string, object> GetBagForObject<T>(T instance)
+ {
+ return GetBagForObject(typeof(T), instance);
+ }
+
+ internal static Dictionary<string, object> InitializeBag()
+ {
+ return new Dictionary<string, object>(
+ 0, StringComparer.OrdinalIgnoreCase
+ );
+ }
+
+ internal static IEnumerable<PropertyInfo> PrepareInstance(out object instance, Type type)
+ {
+ instance = Activator.CreateInstance(type);
+
+ CacheReflection(type);
+
+ return _cache[type];
+ }
+
+ internal static IEnumerable<PropertyInfo> PrepareInstance<T>(out T instance)
+ {
+ instance = Activator.CreateInstance<T>();
+ var item = typeof(T);
+
+ CacheReflection(item);
+
+ return _cache[item];
+ }
+
+ internal static void CacheReflection(Type item)
+ {
+ if (_cache.ContainsKey(item))
+ {
+ return;
+ }
+
+ var properties = item.GetProperties(
+ BindingFlags.Public | BindingFlags.Instance
+ );
+
+ _cache.Add(item, properties);
+ }
+
+ internal static void SerializeItem(StringBuilder sb, object item)
+ {
+ if (item is IDictionary<string, object>)
+ {
+ SerializeObject(item, sb);
+ return;
+ }
+
+ if (item is IEnumerable)
+ {
+ SerializeArray(item, sb);
+ return;
+ }
+
+ if (item is DateTime)
+ {
+ SerializeDateTime(sb);
+ return;
+ }
+
+ if (item is bool)
+ {
+ sb.Append(((bool)item).ToString().ToLower());
+ return;
+ }
+
+ double number;
+ var input = item != null ? item.ToString() : "";
+#if NETCF
+ if (input.TryParse(out number))
+ {
+ sb.Append(number);
+ }
+#else
+ if (double.TryParse(input, JsonNumbers, CultureInfo.InvariantCulture, out number))
+ {
+ sb.Append(number);
+ return;
+ }
+#endif
+ if (item == null)
+ {
+ sb.Append("null");
+ return;
+ }
+
+ var bag = GetBagForObject(item.GetType(), item);
+ SerializeItem(sb, bag);
+ }
+
+ internal static void SerializeDateTime(StringBuilder sb)
+ {
+ var elapsed = DateTime.UtcNow - new DateTime(1970, 1, 1).ToUniversalTime();
+ var epoch = (long)elapsed.TotalSeconds;
+ SerializeString(sb, epoch);
+ }
+
+ internal static void SerializeArray(object item, StringBuilder sb)
+ {
+ var array = (IEnumerable)item;
+ sb.Append("[");
+ var count = 0;
+
+ var total = array.Cast<object>().Count();
+ foreach (var element in array)
+ {
+ SerializeItem(sb, element);
+ count++;
+ if (count < total)
+ {
+ sb.Append(",");
+ }
+ }
+ sb.Append("]");
+ }
+
+ internal static void SerializeObject(object item, StringBuilder sb)
+ {
+ var nested = (IDictionary<string, object>)item;
+ sb.Append("{");
+
+ var count = 0;
+ foreach (var key in nested.Keys)
+ {
+ SerializeString(sb, key.ToLower());
+ sb.Append(":");
+
+ var value = nested[key];
+ if (value is string)
+ {
+ SerializeString(sb, value);
+ }
+ else
+ {
+ SerializeItem(sb, nested[key]);
+ }
+
+ if (count < nested.Keys.Count - 1)
+ {
+ sb.Append(",");
+ }
+ count++;
+ }
+ sb.Append("}");
+ }
+
+
+ internal static void SerializeString(StringBuilder sb, object item)
+ {
+ sb.Append("\"");
+ var symbols = item.ToString().ToCharArray();
+#if NETCF
+ foreach (var unicode in symbols.Select(symbol => (int)symbol).Select(code => GetUnicode(code)))
+#else
+ foreach (var unicode in symbols.Select(symbol => (int)symbol).Select(GetUnicode))
+#endif
+ {
+ sb.Append(unicode);
+ }
+ sb.Append("\"");
+ }
+
+ internal static string GetUnicode(int code)
+ {
+ // http://unicode.org/roadmaps/bmp/
+ var basicLatin = code >= 32 && code <= 126;
+ if (basicLatin)
+ {
+ return new string((char)code, 1);
+ }
+
+ var unicode = BaseConvert(code, _base16, 4);
+ return string.Concat("\\u", unicode);
+ }
+
+ internal static KeyValuePair<string, object> ParsePair(IList<char> data, ref int index)
+ {
+ var valid = true;
+
+ var name = ParseString(data, ref index);
+ if (name == null)
+ {
+ valid = false;
+ }
+
+ if (!ParseToken(JsonToken.Colon, data, ref index))
+ {
+ valid = false;
+ }
+
+ if (!valid)
+ {
+ throw new InvalidJsonException(string.Format(
+ "Invalid JSON found while parsing a value pair at index {0}.", index
+ ));
+ }
+
+ index++;
+ var value = ParseValue(data, ref index);
+ return new KeyValuePair<string, object>(name, value);
+ }
+
+ internal static bool ParseToken(JsonToken token, IList<char> data, ref int index)
+ {
+ var nextToken = NextToken(data, ref index);
+ return token == nextToken;
+ }
+
+ internal static string ParseString(IList<char> data, ref int index)
+ {
+ var symbol = data[index];
+ IgnoreWhitespace(data, ref index, symbol);
+ symbol = data[++index]; // Skip first quotation
+
+ var sb = new StringBuilder();
+ while (true)
+ {
+ if (index >= data.Count - 1)
+ {
+ return null;
+ }
+ switch (symbol)
+ {
+ case '"': // End String
+ index++;
+ return sb.ToString();
+ case '\\': // Control Character
+ symbol = data[++index];
+ switch (symbol)
+ {
+ case '/':
+ sb.Append(symbol);
+ break;
+ case '\\':
+ case 'b':
+ case 'f':
+ case 'n':
+ case 'r':
+ case 't':
+ break;
+ case 'u': // Unicode literals
+ if (index < data.Count - 5)
+ {
+ var array = data.ToArray();
+ var buffer = new char[4];
+ Array.Copy(array, index + 1, buffer, 0, 4);
+
+ // http://msdn.microsoft.com/en-us/library/aa664669%28VS.71%29.aspx
+ // http://www.yoda.arachsys.com/csharp/unicode.html
+ // http://en.wikipedia.org/wiki/UTF-32/UCS-4
+ var hex = new string(buffer);
+ var unicode = (char)Convert.ToInt32(hex, 16);
+ sb.Append(unicode);
+ index += 4;
+ }
+ else
+ {
+ break;
+ }
+ break;
+ }
+ break;
+ default:
+ sb.Append(symbol);
+ break;
+ }
+ symbol = data[++index];
+ }
+ }
+
+ internal static object ParseValue(IList<char> data, ref int index)
+ {
+ var token = NextToken(data, ref index);
+
+ switch (token)
+ {
+ // End Tokens
+ case JsonToken.RightBracket: // Bad Data
+ case JsonToken.RightBrace:
+ case JsonToken.Unknown:
+ case JsonToken.Colon:
+ case JsonToken.Comma:
+ throw new InvalidJsonException(string.Format(
+ "Invalid JSON found while parsing a value at index {0}.", index
+ ));
+ // Value Tokens
+ case JsonToken.LeftBrace:
+ return ParseObject(data, ref index);
+ case JsonToken.LeftBracket:
+ return ParseArray(data, ref index);
+ case JsonToken.String:
+ return ParseString(data, ref index);
+ case JsonToken.Number:
+ return ParseNumber(data, ref index);
+ case JsonToken.True:
+ return true;
+ case JsonToken.False:
+ return false;
+ case JsonToken.Null:
+ return null;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+
+ internal static IDictionary<string, object> ParseObject(IList<char> data, ref int index)
+ {
+ var result = InitializeBag();
+
+ index++; // Skip first token
+
+ while (index < data.Count - 1)
+ {
+ var token = NextToken(data, ref index);
+ switch (token)
+ {
+ // End Tokens
+ case JsonToken.Unknown: // Bad Data
+ case JsonToken.True:
+ case JsonToken.False:
+ case JsonToken.Null:
+ case JsonToken.Colon:
+ case JsonToken.RightBracket:
+ case JsonToken.Number:
+ throw new InvalidJsonException(string.Format(
+ "Invalid JSON found while parsing an object at index {0}.", index
+ ));
+ case JsonToken.RightBrace: // End Object
+ index++;
+ return result;
+ // Skip Tokens
+ case JsonToken.Comma:
+ index++;
+ break;
+ // Start Tokens
+ case JsonToken.LeftBrace: // Start Object
+ var @object = ParseObject(data, ref index);
+ if (@object != null)
+ {
+ result.Add(string.Concat("object", result.Count), @object);
+ }
+ index++;
+ break;
+ case JsonToken.LeftBracket: // Start Array
+ var @array = ParseArray(data, ref index);
+ if (@array != null)
+ {
+ result.Add(string.Concat("array", result.Count), @array);
+ }
+ index++;
+ break;
+ case JsonToken.String:
+ var pair = ParsePair(data, ref index);
+ result.Add(pair.Key, pair.Value);
+ break;
+ default:
+ throw new NotSupportedException("Invalid token expected.");
+ }
+ }
+
+ return result;
+ }
+
+ internal static IEnumerable<object> ParseArray(IList<char> data, ref int index)
+ {
+ var result = new List<object>();
+
+ index++; // Skip first bracket
+ while (index < data.Count - 1)
+ {
+ var token = NextToken(data, ref index);
+ switch (token)
+ {
+ // End Tokens
+ case JsonToken.Unknown: // Bad Data
+ throw new InvalidJsonException(string.Format(
+ "Invalid JSON found while parsing an array at index {0}.", index
+ ));
+ case JsonToken.RightBracket: // End Array
+ index++;
+ return result;
+ // Skip Tokens
+ case JsonToken.Comma: // Separator
+ case JsonToken.RightBrace: // End Object
+ case JsonToken.Colon: // Separator
+ index++;
+ break;
+ // Value Tokens
+ case JsonToken.LeftBrace: // Start Object
+ var nested = ParseObject(data, ref index);
+ result.Add(nested);
+ break;
+ case JsonToken.LeftBracket: // Start Array
+ case JsonToken.String:
+ case JsonToken.Number:
+ case JsonToken.True:
+ case JsonToken.False:
+ case JsonToken.Null:
+ var value = ParseValue(data, ref index);
+ result.Add(value);
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+
+ //index++;
+ }
+
+ return result;
+ }
+
+ internal static object ParseNumber(IList<char> data, ref int index)
+ {
+ var symbol = data[index];
+ IgnoreWhitespace(data, ref index, symbol);
+
+ var start = index;
+ var length = 0;
+ while (ParseToken(JsonToken.Number, data, ref index))
+ {
+ length++;
+ index++;
+ }
+
+ var number = new char[length];
+ Array.Copy(data.ToArray(), start, number, 0, length);
+
+ double result;
+ var buffer = new string(number);
+#if NETCF
+ if (!buffer.TryParse(out result))
+ {
+ throw new InvalidJsonException(
+ string.Format("Value '{0}' was not a valid JSON number", buffer)
+ );
+ }
+#else
+ if (!double.TryParse(buffer, JsonNumbers, CultureInfo.InvariantCulture, out result))
+ {
+ throw new InvalidJsonException(
+ string.Format("Value '{0}' was not a valid JSON number", buffer)
+ );
+ }
+#endif
+
+ return result;
+ }
+
+ internal static JsonToken NextToken(IList<char> data, ref int index)
+ {
+ var symbol = data[index];
+ var token = GetTokenFromSymbol(symbol);
+ token = IgnoreWhitespace(data, ref index, ref token, symbol);
+
+ GetKeyword("true", JsonToken.True, data, ref index, ref token);
+ GetKeyword("false", JsonToken.False, data, ref index, ref token);
+ GetKeyword("null", JsonToken.Null, data, ref index, ref token);
+
+ return token;
+ }
+
+ internal static JsonToken GetTokenFromSymbol(char symbol)
+ {
+ return GetTokenFromSymbol(symbol, JsonToken.Unknown);
+ }
+
+ internal static JsonToken GetTokenFromSymbol(char symbol, JsonToken token)
+ {
+ switch (symbol)
+ {
+ case '{':
+ token = JsonToken.LeftBrace;
+ break;
+ case '}':
+ token = JsonToken.RightBrace;
+ break;
+ case ':':
+ token = JsonToken.Colon;
+ break;
+ case ',':
+ token = JsonToken.Comma;
+ break;
+ case '[':
+ token = JsonToken.LeftBracket;
+ break;
+ case ']':
+ token = JsonToken.RightBracket;
+ break;
+ case '"':
+ token = JsonToken.String;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '.':
+ case 'e':
+ case 'E':
+ case '+':
+ case '-':
+ token = JsonToken.Number;
+ break;
+ }
+ return token;
+ }
+
+ internal static void IgnoreWhitespace(IList<char> data, ref int index, char symbol)
+ {
+ var token = JsonToken.Unknown;
+ IgnoreWhitespace(data, ref index, ref token, symbol);
+ return;
+ }
+
+ internal static JsonToken IgnoreWhitespace(IList<char> data, ref int index, ref JsonToken token, char symbol)
+ {
+ switch (symbol)
+ {
+ case ' ':
+ case '\\':
+ case '/':
+ case '\b':
+ case '\f':
+ case '\n':
+ case '\r':
+ case '\t':
+ index++;
+ token = NextToken(data, ref index);
+ break;
+ }
+ return token;
+ }
+
+ internal static void GetKeyword(string word,
+ JsonToken target,
+ IList<char> data,
+ ref int index,
+ ref JsonToken result)
+ {
+ var buffer = data.Count - index;
+ if (buffer < word.Length)
+ {
+ return;
+ }
+
+ for (var i = 0; i < word.Length; i++)
+ {
+ if (data[index + i] != word[i])
+ {
+ return;
+ }
+ }
+
+ result = target;
+ index += word.Length;
+ }
+
+ internal static string BaseConvert(int input, char[] charSet, int minLength)
+ {
+ var sb = new StringBuilder();
+ var @base = charSet.Length;
+
+ while (input > 0)
+ {
+ var index = input % @base;
+ sb.Insert(0, new[] { charSet[index] });
+ input = input / @base;
+ }
+
+ while (sb.Length < minLength)
+ {
+ sb.Insert(0, "0");
+ }
+
+ return sb.ToString();
+ }
+ }
+
+#if NETCF
+ public static class CompactExtensions
+ {
+ private const NumberStyles JsonNumbers = NumberStyles.Float;
+
+ public static bool TryParse(this string input, out double result)
+ {
+ try
+ {
+ result = double.Parse(input, JsonNumbers, CultureInfo.InvariantCulture);
+ return true;
+ }
+ catch (Exception)
+ {
+ result = 0;
+ return false;
+ }
+ }
+ }
+#endif
+}
+
--- /dev/null
+using System;
+using System.Text;
+
+namespace Hammock.Serialization
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class Utf8Serializer
+ {
+ public virtual Encoding ContentEncoding
+ {
+ get { return Encoding.UTF8; }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Hammock.Specifications
+{
+ internal class AndSpecification<T> : CompositeSpecificationBase<T>
+ {
+ public AndSpecification(ISpecification<T> one, ISpecification<T> other) : base(one, other)
+ {
+ }
+
+ public override bool IsSatisfiedBy(T instance)
+ {
+ return One.IsSatisfiedBy(instance) && Other.IsSatisfiedBy(instance);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Hammock.Specifications
+{
+ internal abstract class CompositeSpecificationBase<T> : HammockSpecification<T>
+ {
+ protected CompositeSpecificationBase(ISpecification<T> one, ISpecification<T> other)
+ {
+ One = one;
+ Other = other;
+ }
+
+ public ISpecification<T> One { get; private set; }
+ public ISpecification<T> Other { get; private set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Hammock.Specifications
+{
+ public abstract class HammockSpecification<T> : ISpecification<T>
+ {
+ #region ISpecification<T> Members
+
+ public abstract bool IsSatisfiedBy(T instance);
+
+ public virtual ISpecification<T> And(ISpecification<T> other)
+ {
+ return new AndSpecification<T>(this, other);
+ }
+
+ public virtual ISpecification<T> Or(ISpecification<T> other)
+ {
+ return new OrSpecification<T>(this, other);
+ }
+
+ public virtual ISpecification<T> Not()
+ {
+ return new NotSpecification<T>(this);
+ }
+
+ #endregion
+
+ public static ISpecification<T> operator &(HammockSpecification<T> one, ISpecification<T> other)
+ {
+ return one.And(other);
+ }
+
+ public static ISpecification<T> operator |(HammockSpecification<T> one, ISpecification<T> other)
+ {
+ return one.Or(other);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Hammock.Specifications
+{
+ public interface ISpecification
+ {
+
+ }
+
+ public interface ISpecification<T> : ISpecification
+ {
+ bool IsSatisfiedBy(T instance);
+ ISpecification<T> And(ISpecification<T> other);
+ ISpecification<T> Or(ISpecification<T> other);
+ ISpecification<T> Not();
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Hammock.Specifications
+{
+ internal class NotSpecification<T> : HammockSpecification<T>
+ {
+ private readonly ISpecification<T> _original;
+
+ public NotSpecification(ISpecification<T> original)
+ {
+ _original = original;
+ }
+
+ public override bool IsSatisfiedBy(T instance)
+ {
+ return !_original.IsSatisfiedBy(instance);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Hammock.Specifications
+{
+ internal class OrSpecification<T> : CompositeSpecificationBase<T>
+ {
+ public OrSpecification(ISpecification<T> one, ISpecification<T> other) : base(one, other)
+ {
+ }
+
+ public override bool IsSatisfiedBy(T instance)
+ {
+ return One.IsSatisfiedBy(instance) || Other.IsSatisfiedBy(instance);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Hammock.Streaming
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class StreamOptions
+ {
+ public virtual TimeSpan? Duration { get; set; }
+ public virtual int? ResultsPerCallback { get; set; }
+ }
+}
--- /dev/null
+using System;
+
+
+namespace Hammock.Tasks
+{
+ /// <summary>
+ /// Describes the current status of a rate limited API or other resource
+ /// <remarks>Based mostly on Twitter's rate limit status</remarks>
+ /// </summary>
+ public interface IRateLimitStatus
+ {
+ /// <summary>
+ /// Gets the current number of resource uses available
+ /// </summary>
+ int RemainingUses { get; }
+ /// <summary>
+ /// Gets the next time the <see cref="RemainingUses"/> is due to be refreshed
+ /// </summary>
+ DateTime NextReset { get; }
+ }
+}
--- /dev/null
+using System;
+
+namespace Hammock.Tasks
+{
+ public interface IRateLimitingRule<T>
+ {
+ double? LimitToPercentOfTotal { get; }
+ RateLimitType RateLimitType { get; }
+ Func<T> GetRateLimitStatus { get; set; }
+ Predicate<T> RateLimitIf { get; }
+ bool ShouldSkipForRateLimiting();
+ TimeSpan? CalculateNewInterval();
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Hammock.Tasks
+{
+ public interface ITaskOptions<T>
+ {
+ double? RateLimitPercent { get; set; }
+ RateLimitType RateLimitType { get; }
+ Predicate<T> RateLimitingPredicate { get; }
+ Func<T> GetRateLimitStatus { get; }
+ }
+
+ public interface ITaskOptions
+ {
+ TimeSpan DueTime { get; set; }
+ int RepeatTimes { get; set; }
+ TimeSpan RepeatInterval { get; set; }
+ bool ContinueOnError { get; set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Hammock.Tasks
+{
+ public interface ITaskState
+ {
+ int RepeatCount { get; set; }
+ DateTime? LastRepeat { get; set; }
+ }
+
+ public interface IRetryState :ITaskState
+ {
+ }
+}
--- /dev/null
+using System;
+
+namespace Hammock.Tasks
+{
+ public interface ITimedTask : IDisposable
+ {
+ Action<bool> Action { get; }
+ Exception Exception { get; }
+
+ TimeSpan DueTime { get; }
+ TimeSpan Interval { get; }
+
+ void Start();
+ void Start(TimeSpan dueTime, TimeSpan interval);
+ void Stop();
+ }
+
+ public interface ITimedTask<T> : ITimedTask
+ {
+ bool RateLimited { get; }
+ IRateLimitingRule<T> RateLimitingRule { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.Serialization;
+
+namespace Hammock.Tasks
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public enum RateLimitType
+ {
+#if !SILVERLIGHT && !Smartphone && !ClientProfiles && !NET20 && !MonoTouch && !NETCF
+ [EnumMember] ByPercent,
+ [EnumMember] ByPredicate
+#else
+ ByPercent,
+ ByPredicate
+#endif
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Hammock.Tasks
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class RateLimitingRule<T> : IRateLimitingRule<T>
+ {
+ private readonly RateLimitType _rateLimitType;
+
+ public RateLimitingRule(Predicate<T> rateLimitIf)
+ {
+ _rateLimitType = RateLimitType.ByPredicate;
+ RateLimitIf = rateLimitIf;
+ }
+
+ public RateLimitingRule(double percentOfTotal)
+ {
+ _rateLimitType = RateLimitType.ByPercent;
+ LimitToPercentOfTotal = percentOfTotal;
+ }
+
+ public RateLimitingRule(Func<T> getRateLimitStatus, Predicate<T> rateLimitIf)
+ {
+ _rateLimitType = RateLimitType.ByPredicate;
+ GetRateLimitStatus = getRateLimitStatus;
+ RateLimitIf = rateLimitIf;
+ }
+
+ public RateLimitingRule(Func<T> getRateLimitStatus, double percentOfTotal)
+ {
+ _rateLimitType = RateLimitType.ByPercent;
+ GetRateLimitStatus = getRateLimitStatus;
+ LimitToPercentOfTotal = percentOfTotal;
+ }
+
+ #region IRateLimitingRule Members
+
+ public virtual double? LimitToPercentOfTotal { get; private set; }
+ public virtual RateLimitType RateLimitType
+ {
+ get { return _rateLimitType; }
+ }
+
+ public Func<T> GetRateLimitStatus { get; set; }
+ public Predicate<T> RateLimitIf { get; private set; }
+
+ #endregion
+
+ public bool ShouldSkipForRateLimiting()
+ {
+ // [JD]: Only pre-skip via predicate; percentage based adjusts rate after the call
+ if (RateLimitType != RateLimitType.ByPredicate)
+ {
+ return false;
+ }
+
+ if (RateLimitIf == null)
+ {
+ throw new InvalidOperationException("Rule is set to use predicate, but no predicate is defined.");
+ }
+
+ var status = default(T);
+ if (GetRateLimitStatus != null)
+ {
+ status = GetRateLimitStatus();
+ }
+ return !RateLimitIf(status);
+ }
+
+ public TimeSpan? CalculateNewInterval()
+ {
+ if (RateLimitType != RateLimitType.ByPercent)
+ {
+ return null;
+ }
+
+ if (!LimitToPercentOfTotal.HasValue)
+ {
+ return null;
+ }
+ var currentRateLimit = (IRateLimitStatus)GetRateLimitStatus();
+ if (currentRateLimit.RemainingUses == 0)
+ {
+ return currentRateLimit.NextReset - DateTime.Now;
+ }
+ var secondsUntilNextReset = (currentRateLimit.NextReset - DateTime.Now).TotalSeconds;
+ var desiredRetriesBeforeReset = currentRateLimit.RemainingUses * LimitToPercentOfTotal.Value;
+ var desiredInterval = (int)Math.Floor(secondsUntilNextReset / desiredRetriesBeforeReset);
+ return new TimeSpan(0, 0, 0, desiredInterval);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Hammock.Tasks
+{
+
+
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class TaskOptions<T> : TaskOptions, ITaskOptions<T>
+ {
+ private RateLimitType _rateLimitType = RateLimitType.ByPredicate;
+ private double? _rateLimitPercent;
+
+ public virtual RateLimitType RateLimitType { get { return _rateLimitType; } }
+ public virtual Predicate<T> RateLimitingPredicate { get; set; }
+ public virtual Func<T> GetRateLimitStatus { get; set; }
+ public virtual double? RateLimitPercent
+ {
+ get { return _rateLimitPercent; }
+ set
+ {
+ if ( value != null)
+ {
+ _rateLimitType = RateLimitType.ByPercent;
+ }
+ else
+ {
+ _rateLimitType = RateLimitType.ByPredicate;
+ }
+ _rateLimitPercent = value;
+ }
+ }
+ }
+
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class TaskOptions : ITaskOptions
+ {
+ public virtual TimeSpan DueTime { get; set; }
+ public virtual int RepeatTimes { get; set; }
+ public virtual TimeSpan RepeatInterval { get; set; }
+ public virtual bool ContinueOnError { get; set; }
+ }
+}
--- /dev/null
+using System;
+
+namespace Hammock.Tasks
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class TaskState : IRetryState
+ {
+ #region ITaskState Members
+
+ public int RepeatCount
+ {
+ get;set;
+ }
+
+ public DateTime? LastRepeat
+ {
+ get; set;
+ }
+
+ #endregion
+ }
+}
--- /dev/null
+using System;
+using System.Diagnostics;
+using System.Threading;
+using Hammock.Web;
+
+#if SILVERLIGHT
+using Hammock.Silverlight.Compat;
+#endif
+namespace Hammock.Tasks
+{
+ public class TimedTask : ITimedTask
+ {
+ protected readonly object Lock = new object();
+ protected bool Active;
+ protected int Iterations;
+ protected Timer Timer;
+ protected bool ContinueOnError;
+
+ public Action<bool> Action { get; protected set; }
+ public Exception Exception { get; protected set; }
+ public TimeSpan DueTime { get; protected set; }
+ public TimeSpan Interval { get; protected set; }
+ internal WebQueryAsyncResult AsyncResult { get; set; }
+ public event Action<TimedTask, EventArgs> Stopped;
+
+ public TimedTask(TimeSpan due,
+ TimeSpan interval,
+ int iterations,
+ bool continueOnError,
+ Action<bool> action) :
+ this(due, interval, iterations, action)
+ {
+ ContinueOnError = continueOnError;
+ }
+
+ public TimedTask(TimeSpan due,
+ TimeSpan interval,
+ int iterations,
+ Action<bool> action)
+ {
+ DueTime = due;
+ Interval = interval;
+ Iterations = iterations;
+ Action = action;
+ }
+
+ protected virtual void Start(bool continueOnError)
+ {
+ var count = 0;
+ Timer = new Timer(state =>
+ {
+ try
+ {
+ Action(false);
+ count++;
+ if (Iterations > 0 && count > Iterations)
+ {
+ Stop();
+ }
+ }
+ catch (Exception ex)
+ {
+ Exception = ex;
+ if (!continueOnError)
+ {
+ Stop();
+ }
+ }
+ }, null, DueTime, Interval);
+ }
+
+
+ public virtual void Stop()
+ {
+ if (Active)
+ {
+ lock (Lock)
+ {
+ if (Active)
+ {
+ Active = false;
+ Timer.Change(-1, -1);
+ OnStopped(EventArgs.Empty);
+ if (AsyncResult != null)
+ {
+ AsyncResult.Signal();
+ }
+ }
+ }
+ }
+ }
+
+ public virtual void Start()
+ {
+ if (!Active)
+ {
+ lock (Lock)
+ {
+ if (!Active)
+ {
+ Active = true;
+ if (Timer != null)
+ {
+ Timer.Change(DueTime, Interval);
+ }
+ else
+ {
+ Start(ContinueOnError);
+ }
+ }
+ }
+ }
+ }
+
+ public virtual void Start(TimeSpan dueTime, TimeSpan interval)
+ {
+ if (!Active)
+ {
+ lock (Lock)
+ {
+ if (!Active)
+ {
+ DueTime = dueTime;
+ Interval = interval;
+ Timer.Change(DueTime, Interval);
+ }
+ }
+ }
+ }
+ protected virtual void OnStopped(EventArgs e)
+ {
+ if (Stopped != null)
+ {
+ Stopped(this, e);
+ }
+ }
+
+ public virtual void Dispose()
+ {
+ Stop();
+ Timer.Dispose();
+ }
+ }
+
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class TimedTask<T> : TimedTask, ITimedTask<T>
+ {
+ public TimedTask(TimeSpan due,
+ TimeSpan interval,
+ int iterations,
+ bool continueOnError,
+ Action<bool> action,
+ IRateLimitingRule<T> rateLimitingRule) :
+ base(due, interval, iterations, action)
+ {
+ RateLimitingRule = rateLimitingRule;
+ ContinueOnError = continueOnError;
+ }
+
+ protected override void Start(bool continueOnError)
+ {
+ var count = 0;
+ Timer = new Timer(state =>
+ {
+ try
+ {
+ //[JD]
+ //only allow the task to run once concurrently.
+ //if a second task attempts to enter the monitor while
+ //the first one is still running, simply drop it
+ if (Monitor.TryEnter(Lock))
+ {
+ try
+ {
+#if TRACE
+ Trace.WriteLine("Running a periodic task");
+#endif
+ var skip = RateLimitingRule.ShouldSkipForRateLimiting();
+#if TRACE
+ Trace.WriteLine(string.Format("{0} Evaluated rate limiting predicate and result was {1}",
+ DateTime.Now.ToShortTimeString(),
+ skip ? "'skip'" : "'don't skip'"));
+#endif
+ Action(skip);
+ var newInterval = RateLimitingRule.CalculateNewInterval();
+#if TRACE
+ Trace.WriteLine(string.Format("{0} Calculated new interval for throttled task and result was: {1}",
+ DateTime.Now.ToShortTimeString(),
+ newInterval.HasValue ? newInterval.Value.ToString() : "'no change'"));
+#endif
+ count++;
+
+ if (Iterations > 0 && count >= Iterations)
+ {
+ Stop();
+ }
+ else if (newInterval.HasValue)
+ {
+ Timer.Change((int)newInterval.Value.TotalMilliseconds, (int)newInterval.Value.TotalMilliseconds);
+ }
+ }
+ finally
+ {
+ Monitor.Exit(Lock);
+ }
+ }
+ else
+ {
+#if TRACE
+ Trace.WriteLine("Skipping recurring task because the previous iteration is still active");
+#endif
+ Action(true);
+ }
+ }
+ catch (Exception ex)
+ {
+ Exception = ex;
+ if (!continueOnError)
+ {
+ Stop();
+ }
+ }
+ }, null, DueTime, Interval);
+ }
+
+ #region ITimedTask Members
+
+ public virtual bool RateLimited
+ {
+ get { return RateLimitingRule != null; }
+ }
+
+ public IRateLimitingRule<T> RateLimitingRule { get; set; }
+
+ public override void Dispose()
+ {
+ base.Dispose();
+ }
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<ClassDiagram MajorVersion="1" MinorVersion="1">
+ <Class Name="Hammock.Tasks.RateLimitingRule<T>" BaseTypeListCollapsed="true">
+ <Position X="8" Y="4.75" Width="2" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAAAAAAAAIAAAAAQAAAAAJAAAAAAA=</HashCode>
+ <FileName>Tasks\RateLimitingRule.cs</FileName>
+ </TypeIdentifier>
+ <ShowAsAssociation>
+ <Property Name="RateLimitingType" />
+ </ShowAsAssociation>
+ <Lollipop Position="0.2" />
+ </Class>
+ <Class Name="Hammock.Tasks.TimedTaskCollection<T>">
+ <Position X="8" Y="1.75" Width="2" />
+ <TypeIdentifier>
+ <HashCode>AAoAAAAAAAAAAAAECAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Tasks\TimedTaskCollection.cs</FileName>
+ </TypeIdentifier>
+ <ShowAsCollectionAssociation>
+ <Field Name="_tasks" />
+ </ShowAsCollectionAssociation>
+ </Class>
+ <Class Name="Hammock.Tasks.TimedTask<T>" BaseTypeListCollapsed="true">
+ <Position X="1.5" Y="7.25" Width="2.25" />
+ <Members>
+ <Field Name="_iterations" Hidden="true" />
+ <Field Name="_timer" Hidden="true" />
+ </Members>
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAACAgAAACAIAAAAAgAAAAAAAAKABAAAAAgAQ=</HashCode>
+ <FileName>Tasks\TimedTask.cs</FileName>
+ </TypeIdentifier>
+ <ShowAsAssociation>
+ <Property Name="RateLimitingRule" />
+ </ShowAsAssociation>
+ <Lollipop Position="0.2" />
+ </Class>
+ <Interface Name="Hammock.Tasks.IRateLimitingRule<T>">
+ <Position X="1.5" Y="1.75" Width="2.25" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAAAAAAAAIAAAAAQAAAAAJAAAAAAA=</HashCode>
+ <FileName>Tasks\IRateLimitingRule.cs</FileName>
+ </TypeIdentifier>
+ <ShowAsAssociation>
+ <Property Name="RateLimitingType" />
+ </ShowAsAssociation>
+ </Interface>
+ <Interface Name="Hammock.Tasks.ITimedTask<T>">
+ <Position X="5.5" Y="1.75" Width="1.75" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAACAAAAAAAIAAAAAgAAAAAAAAKABAAAAAAAQ=</HashCode>
+ <FileName>Tasks\ITimedTask.cs</FileName>
+ </TypeIdentifier>
+ <ShowAsAssociation>
+ <Property Name="RateLimitingRule" />
+ </ShowAsAssociation>
+ </Interface>
+ <Enum Name="Hammock.Tasks.RateLimitingType">
+ <Position X="3" Y="5" Width="2" />
+ <TypeIdentifier>
+ <HashCode>iAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Tasks\RateLimitingType.cs</FileName>
+ </TypeIdentifier>
+ </Enum>
+ <Font Name="Segoe UI" Size="9" />
+</ClassDiagram>
\ No newline at end of file
--- /dev/null
+using System.Text.RegularExpressions;
+using Hammock.Specifications;
+
+namespace Hammock.Validation
+{
+ public class ValidEmailSpecification : HammockSpecification<string>
+ {
+ // Accepts names, i.e. John Smith <john@johnsmith.com>
+ private static readonly Regex _names =
+ new Regex(
+ @"\w*<([-_a-z0-9'+*$^&%=~!?{}]+(?:\.[-_a-z0-9'+*$^&%=~!?{}]+)*@(?:(?![-.])[-a-z0-9.]+(?<![-.])\.[a-z]{2,6}|\d{1,3}(?:\.\d{1,3}){3})(?::\d+)?)>",
+#if !SL4 && !MonoTouch
+ RegexOptions.Compiled |
+#endif
+ RegexOptions.IgnoreCase
+ );
+
+ // Just an email address
+ private static readonly Regex _explicit =
+ new Regex(
+ @"^[-_a-z0-9'+*$^&%=~!?{}]+(?:\.[-_a-z0-9'+*$^&%=~!?{}]+)*@(?:(?![-.])[-a-z0-9.]+(?<![-.])\.[a-z]{2,6}|\d{1,3}(?:\.\d{1,3}){3})(?::\d+)?$",
+#if !SL4 && !MonoTouch
+ RegexOptions.Compiled |
+#endif
+ RegexOptions.IgnoreCase
+ );
+
+ public override bool IsSatisfiedBy(string instance)
+ {
+ var result = _explicit.IsMatch(instance) || _names.IsMatch(instance);
+
+ return result;
+ }
+ }
+}
--- /dev/null
+using System;
+
+namespace Hammock.Validation
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class ValidationException : Exception
+ {
+ public ValidationException()
+ {
+
+ }
+
+ public ValidationException(string message) : base(message)
+ {
+
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Net;
+using Hammock.Extensions;
+
+namespace Hammock.Web
+{
+ /// <summary>
+ /// A web query engine for making requests that use basic HTTP authorization.
+ /// </summary>
+ public class BasicAuthWebQuery : WebQuery
+ {
+ private readonly string _password;
+ private readonly string _username;
+
+ public BasicAuthWebQuery(IWebQueryInfo info, string username, string password, bool enableTrace) : this(info, enableTrace)
+ {
+ _username = username;
+ _password = password;
+ }
+
+ public BasicAuthWebQuery(IWebQueryInfo info, bool enableTrace) : base(info, enableTrace)
+ {
+
+ }
+
+ public bool HasAuth
+ {
+ get
+ {
+ return
+ (!_username.IsNullOrBlank()
+ && !String.IsNullOrEmpty(_password));
+ }
+ }
+
+ protected override void SetAuthorizationHeader(WebRequest request, string header)
+ {
+ if (!HasAuth)
+ {
+ return;
+ }
+
+ var credentials = GetAuthorizationHeader();
+ request.Headers[header] = credentials;
+ }
+
+ private string GetAuthorizationHeader()
+ {
+ return WebExtensions.ToBasicAuthorizationHeader(_username, _password);
+ }
+
+ protected override void AuthenticateRequest(WebRequest request)
+ {
+ SetAuthorizationHeader(request, "Authorization");
+ }
+
+ public override string GetAuthorizationContent()
+ {
+ return GetAuthorizationHeader();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Hammock.Web
+{
+ public enum GetDeleteHeadOptions
+ {
+ Get,
+ Delete,
+ Head,
+ Options
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Hammock.Web
+{
+ public class HttpCookieParameter : WebParameter
+ {
+ public virtual Uri Domain { get; set; }
+
+ public HttpCookieParameter(string name, string value) : base(name, value)
+ {
+
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.IO;
+
+namespace Hammock.Web
+{
+ public class HttpPostParameter : WebParameter
+ {
+ public HttpPostParameter(string name, string value) : base(name, value)
+ {
+
+ }
+
+ public virtual HttpPostParameterType Type { get; private set; }
+ public virtual string FileName { get; private set; }
+ public virtual string FilePath { get; private set; }
+ public virtual Stream FileStream { get; set; }
+ public virtual string ContentType { get; private set; }
+ public virtual string ContentDisposition { get; set; }
+
+ public static HttpPostParameter CreateFile(string name,
+ string fileName,
+ string filePath,
+ string contentType,
+ string contentDisposition)
+ {
+ var parameter = new HttpPostParameter(name, string.Empty)
+ {
+ Type = HttpPostParameterType.File,
+ FileName = fileName,
+ FilePath = filePath,
+ ContentType = contentType,
+ ContentDisposition = contentDisposition
+ };
+ return parameter;
+ }
+
+ public static HttpPostParameter CreateFile(string name,
+ string fileName,
+ Stream fileStream,
+ string contentType,
+ string contentDisposition)
+ {
+ var parameter = new HttpPostParameter(name, string.Empty)
+ {
+ Type = HttpPostParameterType.File,
+ FileName = fileName,
+ FileStream = fileStream,
+ ContentType = contentType,
+ ContentDisposition = contentDisposition
+ };
+
+ return parameter;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.Serialization;
+
+namespace Hammock.Web
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public enum HttpPostParameterType
+ {
+#if !SILVERLIGHT && !Smartphone && !ClientProfiles && !NET20 && !MonoTouch && !NETCF
+ [EnumMember] Field,
+ [EnumMember] File
+#else
+ Field,
+ File
+#endif
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Hammock.Web
+{
+ public interface IWebQueryInfo
+ {
+
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Hammock.Web.Mocks
+{
+ public interface IMockable
+ {
+
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Hammock.Web.Mocks
+{
+ public interface IWebResponse
+ {
+ string Response { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.IO;
+using System.Net;
+
+namespace Hammock.Web.Mocks
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class MockHttpWebRequest : WebRequest
+ {
+ private readonly Uri _requestUri;
+
+ public virtual HttpStatusCode ExpectStatusCode { get; protected internal set; }
+ public virtual string ExpectStatusDescription { get; protected internal set; }
+ public virtual WebHeaderCollection ExpectHeaders { get; protected internal set; }
+#if SILVERLIGHT
+ // Need a wrapper around System.Net.WebHeaderCollection to allow headers in mocks
+#endif
+
+ public virtual string Content { get; set; }
+
+#if WindowsPhone
+ public long ContentLength { get; set; }
+#elif !SILVERLIGHT
+ public override long ContentLength { get; set; }
+#elif !WindowsPhone
+ public long ContentLength { get; set; }
+#endif
+ public override string ContentType { get; set; }
+
+ public MockHttpWebRequest(Uri requestUri)
+ {
+ _requestUri = requestUri;
+ Initialize();
+ }
+
+ private void Initialize()
+ {
+ Headers = new System.Net.WebHeaderCollection();
+ ExpectHeaders = new WebHeaderCollection();
+ }
+
+#if !SILVERLIGHT
+ public override WebResponse GetResponse()
+ {
+ return CreateResponse();
+ }
+#endif
+ public override void Abort()
+ {
+
+ }
+
+ private WebResponse CreateResponse()
+ {
+ var response = new MockHttpWebResponse(_requestUri, ContentType)
+ {
+ StatusCode = ExpectStatusCode,
+ StatusDescription = ExpectStatusDescription,
+ Content = Content
+ };
+
+ foreach (var key in ExpectHeaders.AllKeys)
+ {
+ response.MockHeaders.Add(key, ExpectHeaders[key].Value);
+ }
+
+ return response;
+ }
+
+#if !SILVERLIGHT
+ public override Stream GetRequestStream()
+ {
+ return new MemoryStream();
+ }
+#endif
+ public override IAsyncResult BeginGetRequestStream(AsyncCallback callback, object state)
+ {
+ // [DC]: Mock POSTs never write to the request
+ return BeginGetResponse(callback, state);
+
+ /* var result = new WebQueryAsyncResult
+ {
+ AsyncState = new MemoryStream(),
+ IsCompleted = true,
+ CompletedSynchronously = true
+ };*/
+ }
+
+ public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state)
+ {
+ var response = CreateResponse();
+ var result = new WebQueryAsyncResult
+ {
+ AsyncState = response,
+ IsCompleted = true,
+ CompletedSynchronously = true
+ };
+
+ return result;
+ }
+
+ public override Stream EndGetRequestStream(IAsyncResult asyncResult)
+ {
+ var result = (WebQueryAsyncResult) asyncResult;
+ return result.AsyncState as MemoryStream;
+ }
+
+ public override WebResponse EndGetResponse(IAsyncResult asyncResult)
+ {
+ var result = (WebQueryAsyncResult)asyncResult;
+ return result.AsyncState as WebResponse;
+ }
+
+ public override System.Net.WebHeaderCollection Headers { get; set; }
+ public override string Method { get; set; }
+
+ public override Uri RequestUri
+ {
+ get { return _requestUri; }
+ }
+
+#if !SILVERLIGHT
+ public override int Timeout
+ {
+ get
+ {
+ return int.MaxValue;
+ }
+ }
+#endif
+
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.IO;
+using System.Net;
+using System.Text;
+using Hammock.Extensions;
+
+namespace Hammock.Web.Mocks
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class MockHttpWebResponse : WebResponse
+ {
+ private readonly Uri _requestUri;
+ private readonly string _contentType;
+
+ public virtual string Content { get; protected internal set; }
+ public virtual HttpStatusCode StatusCode { get; protected internal set; }
+ public virtual string StatusDescription { get; protected internal set; }
+
+ protected internal WebHeaderCollection MockHeaders { get; set; }
+
+#if !SILVERLIGHT
+ public override System.Net.WebHeaderCollection Headers
+ {
+ get
+ {
+ var headers = new System.Net.WebHeaderCollection();
+ foreach(var key in MockHeaders.AllKeys)
+ {
+ headers.Add(key, MockHeaders[key].Value);
+ }
+ return headers;
+ }
+ }
+#endif
+
+ public override Stream GetResponseStream()
+ {
+ if(Content.IsNullOrBlank())
+ {
+ return new MemoryStream();
+ }
+ var bytes = Encoding.UTF8.GetBytes(Content);
+ var stream = new MemoryStream(bytes);
+ stream.Seek(0, SeekOrigin.Begin);
+ return stream;
+ }
+
+ public override void Close()
+ {
+
+ }
+
+ public override long ContentLength
+ {
+ get { return Content != null ? Content.Length : 0; }
+ }
+
+ public override string ContentType
+ {
+ get { return _contentType; }
+ }
+
+ public override Uri ResponseUri
+ {
+ get { return _requestUri; }
+ }
+
+ public MockHttpWebResponse(Uri requestUri,
+ string contentType)
+ {
+ _requestUri = requestUri;
+ _contentType = contentType;
+
+ MockHeaders = new WebHeaderCollection(0);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Net;
+using System.Linq;
+using Hammock.Extensions;
+
+#if !SILVERLIGHT && !ClientProfiles && !MonoTouch
+#if !NETCF
+using System.Web;
+#endif
+using System.Collections.Specialized;
+#endif
+
+#if Silverlight
+using Hammock.Silverlight.Compat;
+#endif
+
+#if ClientProfiles || MonoTouch
+using System.Collections.Specialized;
+using System.Compat.Web;
+#endif
+
+#if SL3 || SL4
+using System.Windows.Browser;
+#endif
+
+namespace Hammock.Web.Mocks
+{
+ internal class MockWebRequestFactory : IWebRequestCreate
+ {
+ public const string MockScheme = "mockScheme";
+ public const string MockStatusCode = "mockStatusCode";
+ public const string MockStatusDescription = "mockStatusDescription";
+ public const string MockContent = "mockContent";
+ public const string MockContentType = "mockContentType";
+ public const string MockHeaderNames = "mockHeaderNames";
+ public const string MockHeaderValues = "mockHeaderValues";
+ public const string MockHttpMethod = "mockHttpMethod";
+
+ public WebRequest Create(Uri uri)
+ {
+#if !SILVERLIGHT && !MonoTouch && !NETCF
+ var query = HttpUtility.ParseQueryString(uri.Query);
+#else
+ var query = uri.Query.ParseQueryString();
+#endif
+ var scheme = query[MockScheme];
+ var statusCode = query[MockStatusCode];
+ var statusDescription = query[MockStatusDescription];
+ var content = query[MockContent];
+ var contentType = query[MockContentType];
+ var headerNames = query[MockHeaderNames];
+ var headerValues = query[MockHeaderValues];
+
+ // Remove mocks parameters
+ var queryString = new NameValueCollection();
+#if !SILVERLIGHT && !MonoTouch && !NETCF
+ foreach(var key in query.AllKeys)
+#else
+ foreach (var key in query.Keys)
+#endif
+ {
+ if(key.EqualsAny(
+ MockScheme,
+ MockStatusCode,
+ MockStatusDescription,
+ MockContent,
+ MockContentType,
+ MockHeaderNames,
+ MockHeaderValues,
+ MockHttpMethod
+ ))
+ {
+ continue;
+ }
+ queryString.Add(key, query[key]);
+ }
+
+ // [DC] Silverlight does not have uri.Authority
+ var uriQuery = queryString.ToQueryString();
+ var authority = "{0}{1}".FormatWith(
+ uri.Host,
+ (uri.Scheme.EqualsIgnoreCase("http") && uri.Port != 80 ||
+ uri.Scheme.EqualsIgnoreCase("https") && uri.Port != 443)
+ ? ":" + uri.Port
+ : "");
+
+ var built = "{0}://{1}{2}{3}".FormatWithInvariantCulture(
+ scheme, authority, uri.AbsolutePath, uriQuery
+ );
+
+ Uri mockUri;
+ var request = Uri.TryCreate(
+ built, UriKind.RelativeOrAbsolute, out mockUri
+ ) ? new MockHttpWebRequest(mockUri)
+ : new MockHttpWebRequest(
+ new Uri(uri.ToString().Replace(
+ "mock", scheme))
+ );
+
+ int statusCodeValue;
+#if !NETCF
+ int.TryParse(statusCode, out statusCodeValue);
+#else
+ try
+ {
+ statusCodeValue = int.Parse(statusCode);
+ }
+ catch (Exception)
+ {
+ statusCodeValue = 0;
+ }
+#endif
+ if (!statusCode.IsNullOrBlank()) request.ExpectStatusCode = (HttpStatusCode)statusCodeValue;
+ if (!statusDescription.IsNullOrBlank()) request.ExpectStatusDescription = statusDescription;
+ if (!content.IsNullOrBlank()) request.Content = content;
+ if (!contentType.IsNullOrBlank()) request.ContentType = contentType;
+
+ if(!headerNames.IsNullOrBlank() && !headerValues.IsNullOrBlank())
+ {
+ var headers = new NameValueCollection();
+ var names = headerNames.Split(',').Where(n => !n.IsNullOrBlank()).ToArray();
+ var values = headerValues.Split(',').Where(v => !v.IsNullOrBlank()).ToArray();
+ if(names.Count() == values.Count())
+ {
+ for(var i = 0; i < names.Count(); i++)
+ {
+ headers.Add(names[i], values[i]);
+ }
+ }
+
+ foreach(var key in headers.AllKeys)
+ {
+ request.ExpectHeaders.Add(key, headers[key]);
+ }
+ }
+ return request;
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<ClassDiagram MajorVersion="1" MinorVersion="1">
+ <Class Name="Hammock.Web.Mocks.MockWebRequest" Collapsed="true">
+ <Position X="2.25" Y="2" Width="1.5" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAQAAAAAACAAAAAAAAAAAAAEAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Web\Mocks\MockWebRequest.cs</FileName>
+ </TypeIdentifier>
+ </Class>
+ <Class Name="Hammock.Web.Mocks.MockWebResponse">
+ <Position X="5.25" Y="2" Width="1.75" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAQAAgAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Web\Mocks\MockWebResponse.cs</FileName>
+ </TypeIdentifier>
+ </Class>
+ <Class Name="System.Net.WebResponse" Collapsed="true">
+ <Position X="5.25" Y="0.5" Width="1.75" />
+ <TypeIdentifier />
+ <Lollipop Position="0.2" />
+ </Class>
+ <Class Name="System.Net.WebRequest" Collapsed="true">
+ <Position X="2.25" Y="0.5" Width="1.5" />
+ <TypeIdentifier />
+ <Lollipop Position="0.2" />
+ </Class>
+ <Interface Name="Hammock.Web.Mocks.IWebResponse">
+ <Position X="2.25" Y="3" Width="1.5" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Web\Mocks\IWebResponse.cs</FileName>
+ </TypeIdentifier>
+ </Interface>
+ <Interface Name="Hammock.Web.Mocks.IMockable" Collapsed="true">
+ <Position X="8" Y="0.5" Width="1.5" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>Web\Mocks\IMockable.cs</FileName>
+ </TypeIdentifier>
+ </Interface>
+ <Font Name="Segoe UI" Size="9" />
+</ClassDiagram>
\ No newline at end of file
--- /dev/null
+namespace Hammock.Web
+{
+ public class Pair<TFirst, TSecond>
+ {
+ public TFirst First { get; set; }
+ public TSecond Second { get; set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Hammock.Web
+{
+ public enum PostOrPut
+ {
+ Post,
+ Put
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Hammock.Web
+{
+ internal class Triplet<TFirst, TSecond, TThird>
+ {
+ public TFirst First { get; set; }
+ public TSecond Second { get; set; }
+ public TThird Third { get; set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Hammock.Web
+{
+ public delegate void WebCallback(object sender, WebQueryResponseEventArgs e);
+}
\ No newline at end of file
--- /dev/null
+using System.Text;
+
+namespace Hammock.Web
+{
+ public class WebEntity
+ {
+ public string Content { get; set; }
+ public string ContentType { get; set; }
+ public Encoding ContentEncoding { get; set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Diagnostics;
+
+namespace Hammock.Web
+{
+#if !Smartphone && !NETCF
+ [DebuggerDisplay("{Name}:{Value}")]
+#endif
+#if !Silverlight
+ [Serializable]
+#endif
+ public class WebHeader : WebPair
+ {
+ public WebHeader(string name, string value) : base(name, value)
+ {
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+#if !SILVERLIGHT
+using System.Collections.Specialized;
+#else
+using Hammock.Silverlight.Compat;
+#endif
+using System.Linq;
+
+namespace Hammock.Web
+{
+ public class WebHeaderCollection : WebPairCollection
+ {
+ public WebHeaderCollection(NameValueCollection collection) : base(collection)
+ {
+ }
+
+ public WebHeaderCollection(IEnumerable<WebPair> parameters) : base(parameters)
+ {
+ }
+
+ public WebHeaderCollection()
+ {
+ }
+
+ public WebHeaderCollection(IDictionary<string, string> collection) : base(collection)
+ {
+ }
+
+ public WebHeaderCollection(int capacity) : base(capacity)
+ {
+ }
+
+ public override WebPair this[string name]
+ {
+ // Headers can be non-unique
+ get { return this.First(p => p.Name.Equals(name)); }
+ }
+
+ public IEnumerable<string> AllKeys
+ {
+ get
+ {
+ return Names;
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Hammock.Web
+{
+ public enum WebMethod
+ {
+ Get,
+ Post,
+ Delete,
+ Put,
+ Head,
+ Options
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Hammock.Web
+{
+ public class WebPair
+ {
+ public WebPair(string name, string value)
+ {
+ Name = name;
+ Value = value;
+ }
+
+ public string Value { get; set; }
+ public string Name { get; private set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+
+#if !SILVERLIGHT
+using System.Collections.Specialized;
+#else
+using Hammock.Silverlight.Compat;
+#endif
+
+namespace Hammock.Web
+{
+ public class WebPairCollection : IList<WebPair>
+ {
+ private IList<WebPair> _parameters;
+
+ public virtual WebPair this[string name]
+ {
+ get
+ {
+ var parameters = this.Where(p => p.Name.Equals(name));
+
+ if(parameters.Count() == 0)
+ {
+ return null;
+ }
+
+ if(parameters.Count() == 1)
+ {
+ return parameters.Single();
+ }
+
+ var value = string.Join(",", parameters.Select(p => p.Value).ToArray());
+ return new WebPair(name, value);
+ }
+ }
+
+ public virtual IEnumerable<string> Names
+ {
+ get { return _parameters.Select(p => p.Name); }
+ }
+
+ public virtual IEnumerable<string> Values
+ {
+ get { return _parameters.Select(p => p.Value); }
+ }
+
+ public WebPairCollection(IEnumerable<WebPair> parameters)
+ {
+ _parameters = new List<WebPair>(parameters);
+ }
+
+ public WebPairCollection(NameValueCollection collection) : this()
+ {
+ AddCollection(collection);
+ }
+
+ public virtual void AddRange(NameValueCollection collection)
+ {
+ AddCollection(collection);
+ }
+
+ private void AddCollection(NameValueCollection collection)
+ {
+ var parameters = collection.AllKeys.Select(key => new WebPair(key, collection[key]));
+ foreach (var parameter in parameters)
+ {
+ _parameters.Add(parameter);
+ }
+ }
+
+ public WebPairCollection(IDictionary<string, string> collection) : this()
+ {
+ AddCollection(collection);
+ }
+
+ public void AddCollection(IDictionary<string, string> collection)
+ {
+ foreach (var parameter in collection.Keys.Select(key => new WebPair(key, collection[key])))
+ {
+ _parameters.Add(parameter);
+ }
+ }
+
+ public WebPairCollection()
+ {
+ _parameters = new List<WebPair>(0);
+ }
+
+ public WebPairCollection(int capacity)
+ {
+ _parameters = new List<WebPair>(capacity);
+ }
+
+ private void AddCollection(IEnumerable<WebPair> collection)
+ {
+ foreach (var pair in collection.Select(parameter => new WebPair(parameter.Name, parameter.Value)))
+ {
+ _parameters.Add(pair);
+ }
+ }
+
+ public virtual void AddRange(WebPairCollection collection)
+ {
+ AddCollection(collection);
+ }
+
+ public virtual void AddRange(IEnumerable<WebPair> collection)
+ {
+ AddCollection(collection);
+ }
+
+ public virtual void Sort(Comparison<WebPair> comparison)
+ {
+ var sorted = new List<WebPair>(_parameters);
+ sorted.Sort(comparison);
+ _parameters = sorted;
+ }
+
+ public virtual bool RemoveAll(IEnumerable<WebPair> parameters)
+ {
+ var array = parameters.ToArray();
+ var success = array.Aggregate(true, (current, parameter) => current & _parameters.Remove(parameter));
+ return success && array.Length > 0;
+ }
+
+ public virtual void Add(string name, string value)
+ {
+ var pair = new WebPair(name, value);
+ _parameters.Add(pair);
+ }
+
+ #region IList<WebParameter> Members
+
+ public virtual IEnumerator<WebPair> GetEnumerator()
+ {
+ return _parameters.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ public virtual void Add(WebPair parameter)
+ {
+
+ _parameters.Add(parameter);
+ }
+
+ public virtual void Clear()
+ {
+ _parameters.Clear();
+ }
+
+ public virtual bool Contains(WebPair parameter)
+ {
+ return _parameters.Contains(parameter);
+ }
+
+ public virtual void CopyTo(WebPair[] parameters, int arrayIndex)
+ {
+ _parameters.CopyTo(parameters, arrayIndex);
+ }
+
+ public virtual bool Remove(WebPair parameter)
+ {
+ return _parameters.Remove(parameter);
+ }
+
+ public virtual int Count
+ {
+ get { return _parameters.Count; }
+ }
+
+ public virtual bool IsReadOnly
+ {
+ get { return _parameters.IsReadOnly; }
+ }
+
+ public virtual int IndexOf(WebPair parameter)
+ {
+ return _parameters.IndexOf(parameter);
+ }
+
+ public virtual void Insert(int index, WebPair parameter)
+ {
+ _parameters.Insert(index, parameter);
+ }
+
+ public virtual void RemoveAt(int index)
+ {
+ _parameters.RemoveAt(index);
+ }
+
+ public virtual WebPair this[int index]
+ {
+ get { return _parameters[index]; }
+ set { _parameters[index] = value; }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+#if !Smartphone && !NETCF
+using System.Diagnostics;
+#endif
+using System;
+namespace Hammock.Web
+{
+#if !Smartphone && !NETCF
+ [DebuggerDisplay("{Name}:{Value}")]
+#endif
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class WebParameter : WebPair
+ {
+ public WebParameter(string name, string value) : base(name, value)
+ {
+
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+#if !SILVERLIGHT
+using System.Collections.Specialized;
+#else
+using Hammock.Silverlight.Compat;
+#endif
+
+namespace Hammock.Web
+{
+ public class WebParameterCollection : WebPairCollection
+ {
+ public WebParameterCollection(IEnumerable<WebPair> parameters)
+ : base(parameters)
+ {
+
+ }
+
+ public WebParameterCollection(NameValueCollection collection) : base(collection)
+ {
+ }
+
+ public WebParameterCollection()
+ {
+ }
+
+ public WebParameterCollection(int capacity) : base(capacity)
+ {
+ }
+
+ public WebParameterCollection(IDictionary<string, string> collection) : base(collection)
+ {
+
+ }
+
+ public override void Add(string name, string value)
+ {
+ var parameter = new WebParameter(name, value);
+ base.Add(parameter);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Net;
+using System.Text;
+using System.Threading;
+using Hammock.Caching;
+using Hammock.Extensions;
+using Hammock.Web.Mocks;
+#if SILVERLIGHT
+using Hammock.Silverlight.Compat;
+#endif
+namespace Hammock.Web
+{
+ public partial class WebQuery
+ {
+ protected virtual WebQueryAsyncResult ExecuteGetOrDeleteAsync(GetDeleteHeadOptions method, string url, object userState)
+ {
+ WebResponse = null;
+
+ var request = BuildGetDeleteHeadOptionsWebRequest(method, url);
+ var state = new Triplet<WebRequest, object, object>
+ {
+ First = request,
+ Second = null,
+ Third = userState
+ };
+
+ var args = new WebQueryRequestEventArgs(url);
+ OnQueryRequest(args);
+
+ var inner = request.BeginGetResponse(GetAsyncResponseCallback, state);
+ RegisterAbortTimer(request, inner);
+ var result = new WebQueryAsyncResult { InnerResult = inner };
+ return result;
+ }
+
+ private WebQueryAsyncResult ExecuteGetOrDeleteAsync(ICache cache,
+ string key,
+ string url,
+ WebRequest request,
+ object userState)
+ {
+ var fetch = cache.Get<Stream>(key);
+ if (fetch != null)
+ {
+ var args = new WebQueryResponseEventArgs(fetch);
+ OnQueryResponse(args);
+
+ var result = new WebQueryAsyncResult
+ {
+ CompletedSynchronously = true
+ };
+ return result;
+ }
+ else
+ {
+ var state = new Triplet<WebRequest, Pair<ICache, string>, object>
+ {
+ First = request,
+ Second = new Pair<ICache, string>
+ {
+ First = cache,
+ Second = key
+ },
+ Third = userState
+ };
+
+ var args = new WebQueryRequestEventArgs(url);
+ OnQueryRequest(args);
+
+ var inner = request.BeginGetResponse(GetAsyncResponseCallback, state);
+ RegisterAbortTimer(request, inner);
+ var result = new WebQueryAsyncResult { InnerResult = inner };
+ return result;
+ }
+ }
+
+ private WebQueryAsyncResult ExecuteGetOrDeleteAsync(ICache cache,
+ string key,
+ string url,
+ DateTime absoluteExpiration,
+ WebRequest request,
+ object userState)
+ {
+ var fetch = cache.Get<Stream>(key);
+ if (fetch != null)
+ {
+ var args = new WebQueryResponseEventArgs(fetch);
+ OnQueryResponse(args);
+
+ var result = new WebQueryAsyncResult
+ {
+ CompletedSynchronously = true,
+ AsyncState = this
+ };
+ return result;
+ }
+ else
+ {
+ var state = new Triplet<WebRequest, Pair<ICache, Pair<string, DateTime>>, object>
+ {
+ First = request,
+ Second = new Pair<ICache, Pair<string, DateTime>>
+ {
+ First = cache,
+ Second = new Pair<string, DateTime>
+ {
+ First = key,
+ Second = absoluteExpiration
+ }
+ },
+ Third = userState
+ };
+
+ var args = new WebQueryRequestEventArgs(url);
+ OnQueryRequest(args);
+
+ var inner = request.BeginGetResponse(GetAsyncResponseCallback, state);
+ RegisterAbortTimer(request, inner);
+ var result = new WebQueryAsyncResult { InnerResult = inner };
+ return result;
+ }
+ }
+
+ private WebQueryAsyncResult ExecuteGetOrDeleteAsync(ICache cache,
+ string key,
+ string url,
+ TimeSpan slidingExpiration,
+ WebRequest request,
+ object userState)
+ {
+ var fetch = cache.Get<Stream>(key);
+ if (fetch != null)
+ {
+ var args = new WebQueryResponseEventArgs(fetch);
+ OnQueryResponse(args);
+
+ var result = new WebQueryAsyncResult
+ {
+ CompletedSynchronously = true
+ };
+ return result;
+ }
+ else
+ {
+ var state = new Triplet<WebRequest, Pair<ICache, Pair<string, TimeSpan>>, object>
+ {
+ First = request,
+ Second = new Pair<ICache, Pair<string, TimeSpan>>
+ {
+ First = cache,
+ Second = new Pair<string, TimeSpan>
+ {
+ First = key,
+ Second = slidingExpiration
+ }
+ },
+ Third = userState
+ };
+
+ var args = new WebQueryRequestEventArgs(url);
+ OnQueryRequest(args);
+
+ var inner = request.BeginGetResponse(GetAsyncResponseCallback, state);
+ RegisterAbortTimer(request, inner);
+ var result = new WebQueryAsyncResult { InnerResult = inner };
+ return result;
+ }
+ }
+
+ // [DC] This is necessary to inform the client handle that a POST has timed out
+ private readonly List<WebQueryAsyncResult> _postHandles = new List<WebQueryAsyncResult>();
+
+ protected virtual void RegisterAbortTimer(WebRequest request, IAsyncResult result)
+ {
+ if(request is MockHttpWebRequest)
+ {
+ return;
+ }
+
+#if !Smartphone && !WindowsPhone && !SL4 && !NETCF
+ // [DC] request.Timeout is ignored with async
+ var timeout = RequestTimeout != null ?
+ (int)RequestTimeout.Value.TotalMilliseconds
+ : 300000; // Default ReadWriteTimeout
+
+ var isPost = result is WebQueryAsyncResult;
+ if (isPost)
+ {
+ _postHandles.Add((WebQueryAsyncResult)result);
+ }
+ var handle = isPost
+ ? ((WebQueryAsyncResult) result).InnerResult.AsyncWaitHandle
+ : result.AsyncWaitHandle;
+
+ var state = new Pair<WebRequest, IAsyncResult>
+ {
+ First = request,
+ Second = result
+ };
+
+ // Async operations ignore the WebRequest's Timeout property
+ ThreadPool.RegisterWaitForSingleObject(handle,
+ TimedOutCallback,
+ state,
+ timeout,
+ true /* executeOnlyOnce */);
+#endif
+ }
+
+ private void TimedOutCallback(object state, bool timedOut)
+ {
+ if (!timedOut)
+ {
+ return;
+ }
+
+ var pair = state as Pair<WebRequest, IAsyncResult>;
+ if (pair != null)
+ {
+ var request = pair.First;
+ var result = pair.Second;
+
+ TimedOut = true;
+ request.Abort();
+
+ // [DC] LSP violation necessary for POST functionality;
+ // [DC] We did not get far enough along to prepare a response
+ if (result is WebQueryAsyncResult)
+ {
+ var response = new RestResponse
+ {
+ TimedOut = true,
+ StatusCode = 0
+ };
+#if TRACE
+ // Just for cosmetic purposes
+ Trace.WriteLineIf(TraceEnabled, string.Concat("RESPONSE: ", response.StatusCode));
+ Trace.WriteLineIf(TraceEnabled, "\r\n");
+#endif
+ foreach(var postHandle in _postHandles)
+ {
+ postHandle.AsyncState = response;
+ postHandle.Signal();
+ }
+ _postHandles.Clear();
+ }
+ }
+ }
+
+ protected virtual WebQueryAsyncResult ExecuteGetOrDeleteAsync(GetDeleteHeadOptions method,
+ string url,
+ string prefixKey,
+ ICache cache,
+ object userState)
+ {
+ WebResponse = null;
+
+ var request = BuildGetDeleteHeadOptionsWebRequest(method, url);
+ var key = CreateCacheKey(prefixKey, url);
+
+ return ExecuteGetOrDeleteAsync(cache, key, url, request, userState);
+ }
+
+ protected virtual WebQueryAsyncResult ExecuteGetOrDeleteAsync(GetDeleteHeadOptions method,
+ string url,
+ string prefixKey,
+ ICache cache,
+ DateTime absoluteExpiration,
+ object userState)
+ {
+ WebResponse = null;
+
+ var request = BuildGetDeleteHeadOptionsWebRequest(method, url);
+ var key = CreateCacheKey(prefixKey, url);
+
+ return ExecuteGetOrDeleteAsync(cache, key, url, absoluteExpiration, request, userState);
+ }
+
+ protected virtual WebQueryAsyncResult ExecuteGetOrDeleteAsync(GetDeleteHeadOptions method,
+ string url,
+ string prefixKey,
+ ICache cache,
+ TimeSpan slidingExpiration,
+ object userState)
+ {
+ WebResponse = null;
+
+ var request = BuildGetDeleteHeadOptionsWebRequest(method, url);
+ var key = CreateCacheKey(prefixKey, url);
+
+ return ExecuteGetOrDeleteAsync(cache, key, url, slidingExpiration, request, userState);
+ }
+
+ protected virtual void GetAsyncResponseCallback(IAsyncResult asyncResult)
+ {
+ object store;
+ var request = GetAsyncCacheStore(asyncResult, out store);
+
+ try
+ {
+ var response = request.EndGetResponse(asyncResult);
+ using (response)
+ {
+#if SILVERLIGHT
+ if (DecompressionMethods == Silverlight.Compat.DecompressionMethods.GZip ||
+ DecompressionMethods == Silverlight.Compat.DecompressionMethods.Deflate ||
+ DecompressionMethods == (Silverlight.Compat.DecompressionMethods.GZip | Silverlight.Compat.DecompressionMethods.Deflate)
+ )
+ {
+ response = new GzipHttpWebResponse((HttpWebResponse)response);
+ }
+#endif
+ WebResponse = response;
+
+ ContentStream = response.GetResponseStream();
+
+ if (store != null)
+ {
+ // No expiration specified
+ if (store is Pair<ICache, string>)
+ {
+ var cache = store as Pair<ICache, string>;
+ cache.First.Insert(cache.Second, ContentStream);
+ }
+
+ // Absolute expiration specified
+ if (store is Pair<ICache, Pair<string, DateTime>>)
+ {
+ var cache = store as Pair<ICache, Pair<string, DateTime>>;
+ cache.First.Insert(cache.Second.First, ContentStream, cache.Second.Second);
+ }
+
+ // Sliding expiration specified
+ if (store is Pair<ICache, Pair<string, TimeSpan>>)
+ {
+ var cache = store as Pair<ICache, Pair<string, TimeSpan>>;
+ cache.First.Insert(cache.Second.First, ContentStream, cache.Second.Second);
+ }
+ }
+
+ // Only send query when caching is complete
+ var args = new WebQueryResponseEventArgs(ContentStream);
+ OnQueryResponse(args);
+ }
+ }
+ catch (WebException ex)
+ {
+ HandleWebException(ex);
+ }
+ }
+
+ private static WebRequest GetAsyncCacheStore(IAsyncResult asyncResult, out object store)
+ {
+ /*
+ var state = asyncResult.AsyncState as Triplet<WebRequest, Triplet<ICache, object, string>, object>;
+ if (state == null)
+ {
+ throw new ArgumentNullException("asyncResult",
+ "The asynchronous post failed to return its state");
+ }
+
+ var request = state.First;
+ if (request == null)
+ {
+ throw new ArgumentNullException("asyncResult",
+ "The asynchronous post failed to return a request");
+ }
+ */
+
+
+ WebRequest request;
+
+ var noCache = asyncResult.AsyncState as Triplet<WebRequest, object, object>;
+ if(noCache != null)
+ {
+ request = noCache.First;
+ store = noCache.Second;
+ }
+ else
+ {
+ var absoluteCache = asyncResult.AsyncState as Triplet<WebRequest, Pair<ICache, Pair<string, DateTime>>, object>;
+ if(absoluteCache != null)
+ {
+ request = absoluteCache.First;
+ store = absoluteCache.Second;
+ }
+ else
+ {
+ var slidingCache = asyncResult.AsyncState as Triplet<WebRequest, Pair<ICache, Pair<string, TimeSpan>>, object>;
+ if(slidingCache != null)
+ {
+ request = slidingCache.First;
+ store = slidingCache.Second;
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException(
+ "asyncResult", "Wrong cache signature found."
+ );
+ }
+ }
+ }
+ return request;
+ }
+
+ private bool _isStreaming;
+ private readonly byte[] _endStreamBytes = Encoding.UTF8.GetBytes("END STREAMING");
+
+ public virtual bool IsStreaming
+ {
+ get
+ {
+ lock(_sync)
+ {
+ return _isStreaming;
+ }
+ }
+ set
+ {
+ lock(_sync)
+ {
+ _isStreaming = value;
+ }
+ }
+ }
+
+ public virtual bool TimedOut { get; set; }
+
+ private void AsyncStreamCallback(IAsyncResult asyncResult)
+ {
+ var state = asyncResult.AsyncState as Pair<WebRequest, Pair<TimeSpan, int>>;
+ if (state == null)
+ {
+ // Unrecognized state signature
+ throw new ArgumentNullException("asyncResult",
+ "The asynchronous post failed to return its state");
+ }
+
+ var request = state.First;
+ var duration = state.Second.First;
+ var resultCount = state.Second.Second;
+
+ WebResponse response = null;
+ Stream stream = null;
+
+ try
+ {
+ using (response = request.EndGetResponse(asyncResult))
+ {
+#if SILVERLIGHT
+ if (DecompressionMethods == Silverlight.Compat.DecompressionMethods.GZip ||
+ DecompressionMethods == Silverlight.Compat.DecompressionMethods.Deflate ||
+ DecompressionMethods == (Silverlight.Compat.DecompressionMethods.GZip | Silverlight.Compat.DecompressionMethods.Deflate)
+ )
+ {
+ response = new GzipHttpWebResponse((HttpWebResponse)response);
+ }
+#endif
+ StreamImpl(out stream, request, response, duration, resultCount);
+ }
+ }
+ catch (WebException ex)
+ {
+ HandleWebException(ex);
+ }
+ finally
+ {
+ if (stream != null)
+ {
+ stream.Close();
+ stream.Dispose();
+ }
+
+ WebResponse = response;
+ }
+ }
+
+ public delegate void NewStreamMessage(Stream message);
+ public event NewStreamMessage NewStreamMessageEvent;
+
+ private void StreamImpl(out Stream stream,
+ WebRequest request, WebResponse response,
+ TimeSpan duration, int resultCount)
+ {
+
+ using (stream = response.GetResponseStream())
+ {
+ if (stream == null)
+ {
+ return;
+ }
+
+ NewStreamMessageEvent += WebQueryNewStreamMessageEvent;
+
+ _isStreaming = true;
+
+ var count = 0;
+ var results = new List<string>();
+ var start = DateTime.UtcNow;
+ var bufferString = string.Empty;
+
+ while (stream.CanRead)
+ {
+ var data = new byte[4096];
+ try
+ {
+ int read;
+ while ((read = stream.Read(data, 0, data.Length)) > 0)
+ {
+ var readString = Encoding.UTF8.GetString(data, 0, read);
+ bufferString = ProcessBuffer(bufferString + readString);
+ if (!_isStreaming)
+ {
+ // [DC] Streaming was cancelled out of band
+ EndStreaming(request);
+ return;
+ }
+
+ if (readString.Equals(Environment.NewLine))
+ {
+ // Keep-Alive
+ continue;
+ }
+
+ if (readString.Equals("<html>"))
+ {
+ // We're looking at a 401 or similar; construct error result?
+ EndStreaming(request);
+ return;
+ }
+
+ results.Add(readString);
+
+ count++;
+ if (count < resultCount)
+ {
+ // Result buffer
+ continue;
+ }
+
+ var sb = new StringBuilder();
+ foreach (var result in results)
+ {
+ sb.AppendLine(result);
+ }
+
+ results.Clear();
+
+ count = 0;
+
+ var now = DateTime.UtcNow;
+
+ if (duration == new TimeSpan() || now.Subtract(start) < duration)
+ {
+ continue;
+ }
+
+ // Time elapsed
+ EndStreaming(request);
+ return;
+ }
+ }
+ catch (Exception)
+ {
+ EndStreaming(request);
+ }
+ // Stream dried up
+ }
+ EndStreaming(request);
+ }
+ }
+
+ private void WebQueryNewStreamMessageEvent(Stream message)
+ {
+ var args = new WebQueryResponseEventArgs(message);
+ OnQueryResponse(args);
+ }
+
+ // TODO make part of StreamOptions
+ private const char StreamResultDelimiter = '\r';
+
+ private string ProcessBuffer(string bufferString)
+ {
+ var buffer = bufferString;
+ var position = buffer.IndexOf(StreamResultDelimiter);
+
+ while (position >= 0)
+ {
+ string message = buffer.Substring(0, position).Replace(StreamResultDelimiter.ToString(),"");
+ var messageBytes = Encoding.UTF8.GetBytes(message);
+
+ buffer = buffer.Length <= position + 1 ?
+ string.Empty : buffer.Substring(position + 1);
+
+ if (message.Trim().Length > 1 && NewStreamMessageEvent != null)
+ {
+ NewStreamMessageEvent(new MemoryStream(messageBytes));
+ }
+
+ position = buffer.IndexOf(StreamResultDelimiter);
+ }
+
+ return buffer;
+ }
+
+ private void EndStreaming(WebRequest request)
+ {
+ _isStreaming = false;
+
+ var stream = new MemoryStream(_endStreamBytes);
+ var args = new WebQueryResponseEventArgs(stream);
+ OnQueryResponse(args);
+ request.Abort();
+ }
+
+ protected virtual void PostAsyncStreamRequestCallback(IAsyncResult asyncResult)
+ {
+ var state = asyncResult.AsyncState as Triplet<WebRequest, byte[], Pair<TimeSpan, int>>;
+ if (state == null)
+ {
+ // Unrecognized state signature
+ throw new ArgumentNullException("asyncResult",
+ "The asynchronous post failed to return its state");
+ }
+
+ var request = state.First;
+ var content = state.Second;
+
+ using (var stream = request.EndGetRequestStream(asyncResult))
+ {
+ if (content != null)
+ {
+ stream.Write(content, 0, content.Length);
+ stream.Flush();
+ }
+ stream.Close();
+
+ request.BeginGetResponse(AsyncStreamCallback,
+ new Pair<WebRequest, Pair<TimeSpan, int>>
+ {
+ First = request,
+ Second = state.Third
+ }
+ );
+ }
+ }
+
+ protected virtual void PostAsyncRequestCallback(IAsyncResult asyncResult)
+ {
+ WebRequest request;
+ byte[] post;
+ object userState;
+ Triplet<ICache, object, string> store;
+
+ var state = asyncResult.AsyncState as Triplet<WebRequest, byte[], object>;
+ if (state == null)
+ {
+ // No expiration specified
+ if (asyncResult is Triplet<WebRequest, Triplet<byte[], ICache, string>, object>)
+ {
+ var cacheScheme = (Triplet<WebRequest, Triplet<byte[], ICache, string>, object>)asyncResult;
+ var cache = cacheScheme.Second.Second;
+
+ var url = cacheScheme.First.RequestUri.ToString();
+ var prefix = cacheScheme.Second.Third;
+ var key = CreateCacheKey(prefix, url);
+
+ var fetch = cache.Get<Stream>(key);
+ if (fetch != null)
+ {
+ var args = new WebQueryResponseEventArgs(fetch);
+ OnQueryResponse(args);
+ return;
+ }
+
+ request = cacheScheme.First;
+ post = cacheScheme.Second.First;
+ userState = cacheScheme.Third;
+ store = new Triplet<ICache, object, string>
+ {
+ First = cache,
+ Second = null,
+ Third = prefix
+ };
+ }
+ else
+ // Absolute expiration specified
+ if (asyncResult is Triplet<WebRequest, Pair<byte[], Triplet<ICache, DateTime, string>>, object>)
+ {
+ var cacheScheme = (Triplet<WebRequest, Pair<byte[], Triplet<ICache, DateTime, string>>, object>)asyncResult;
+ var url = cacheScheme.First.RequestUri.ToString();
+ var cache = cacheScheme.Second.Second.First;
+ var expiry = cacheScheme.Second.Second.Second;
+
+ var prefix = cacheScheme.Second.Second.Third;
+ var key = CreateCacheKey(prefix, url);
+
+ var fetch = cache.Get<Stream>(key);
+ if (fetch != null)
+ {
+ var args = new WebQueryResponseEventArgs(fetch);
+ OnQueryResponse(args);
+ return;
+ }
+
+ request = cacheScheme.First;
+ post = cacheScheme.Second.First;
+ userState = cacheScheme.Third;
+ store = new Triplet<ICache, object, string>
+ {
+ First = cache,
+ Second = expiry,
+ Third = prefix
+ };
+ }
+ else
+ // Sliding expiration specified
+ if (asyncResult is Triplet<WebRequest, Pair<byte[], Triplet<ICache, TimeSpan, string>>, object>)
+ {
+ var cacheScheme = (Triplet<WebRequest, Pair<byte[], Triplet<ICache, TimeSpan, string>>, object>)asyncResult;
+ var url = cacheScheme.First.RequestUri.ToString();
+ var cache = cacheScheme.Second.Second.First;
+ var expiry = cacheScheme.Second.Second.Second;
+
+ var prefix = cacheScheme.Second.Second.Third;
+ var key = CreateCacheKey(prefix, url);
+
+ var fetch = cache.Get<Stream>(key);
+ if (fetch != null)
+ {
+ var args = new WebQueryResponseEventArgs(fetch);
+ OnQueryResponse(args);
+ return;
+ }
+
+ request = cacheScheme.First;
+ post = cacheScheme.Second.First;
+ userState = cacheScheme.Third;
+ store = new Triplet<ICache, object, string>
+ {
+ First = cache,
+ Second = expiry,
+ Third = prefix
+ };
+ }
+ else
+ {
+ // Unrecognized state signature
+ throw new ArgumentNullException("asyncResult",
+ "The asynchronous post failed to return its state");
+ }
+ }
+ else
+ {
+ request = state.First;
+ post = state.Second;
+ userState = state.Third;
+ store = null;
+ }
+
+ // No cached response
+ using (var stream = request.EndGetRequestStream(asyncResult))
+ {
+ WritePostContentToRequestStream(post, stream);
+
+ var inner = request.BeginGetResponse(PostAsyncResponseCallback,
+ new Triplet<WebRequest, Triplet<ICache, object, string>, object>
+ {
+ First = request,
+ Second = store,
+ Third = userState
+ });
+
+ RegisterAbortTimer(request, new WebQueryAsyncResult { InnerResult = inner });
+ }
+ }
+
+ private void WritePostContentToRequestStream(byte[] post, Stream stream)
+ {
+ if (post != null)
+ {
+ stream.Write(post, 0, post.Length);
+ stream.Flush();
+ }
+ stream.Close();
+#if TRACE
+ var encoding = Encoding ?? new UTF8Encoding();
+ if (post != null)
+ {
+ Trace.WriteLineIf(TraceEnabled, encoding.GetString(post, 0, post.Length));
+ }
+#endif
+ }
+
+ protected virtual void PostAsyncRequestCallbackMultiPart(IAsyncResult asyncResult)
+ {
+ WebRequest request;
+ string boundary;
+ IEnumerable<HttpPostParameter> parameters;
+ object userState;
+ Triplet<ICache, object, string> store;
+
+ var state = asyncResult.AsyncState as Triplet<WebRequest, Pair<string, IEnumerable<HttpPostParameter>>, object>;
+ if (state == null)
+ {
+ // No expiration specified
+ if (asyncResult is Triplet<WebRequest, Triplet<Pair<string, IEnumerable<HttpPostParameter>>, ICache, string>, object>)
+ {
+ #region No Expiration
+ var cacheScheme = (Triplet<WebRequest, Triplet<Pair<string, IEnumerable<HttpPostParameter>>, ICache, string>, object>)asyncResult;
+ var cache = cacheScheme.Second.Second;
+
+ var url = cacheScheme.First.RequestUri.ToString();
+ var prefix = cacheScheme.Second.Third;
+ var key = CreateCacheKey(prefix, url);
+
+ var fetch = cache.Get<Stream>(key);
+ if (fetch != null)
+ {
+ var args = new WebQueryResponseEventArgs(fetch);
+ OnQueryResponse(args);
+ return;
+ }
+
+ request = cacheScheme.First;
+ boundary = cacheScheme.Second.First.First;
+ parameters = cacheScheme.Second.First.Second;
+ userState = cacheScheme.Third;
+ store = new Triplet<ICache, object, string>
+ {
+ First = cache,
+ Second = null,
+ Third = prefix
+ };
+ #endregion
+ }
+ else
+ // Absolute expiration specified
+ if (asyncResult is Triplet<WebRequest, Pair<Pair<string, IEnumerable<HttpPostParameter>>, Triplet<ICache, DateTime, string>>, object>)
+ {
+ #region Absolute Expiration
+ var cacheScheme = (Triplet<WebRequest, Pair<Pair<string, IEnumerable<HttpPostParameter>>, Triplet<ICache, DateTime, string>>, object>)asyncResult;
+ var url = cacheScheme.First.RequestUri.ToString();
+ var cache = cacheScheme.Second.Second.First;
+ var expiry = cacheScheme.Second.Second.Second;
+
+ var prefix = cacheScheme.Second.Second.Third;
+ var key = CreateCacheKey(prefix, url);
+
+ var fetch = cache.Get<Stream>(key);
+ if (fetch != null)
+ {
+ var args = new WebQueryResponseEventArgs(fetch);
+ OnQueryResponse(args);
+ return;
+ }
+
+ request = cacheScheme.First;
+ boundary = cacheScheme.Second.First.First;
+ parameters = cacheScheme.Second.First.Second;
+ userState = cacheScheme.Third;
+ store = new Triplet<ICache, object, string>
+ {
+ First = cache,
+ Second = expiry,
+ Third = prefix
+ };
+ #endregion
+ }
+ else
+ // Sliding expiration specified
+ if (asyncResult is Triplet<WebRequest, Pair<Pair<string, IEnumerable<HttpPostParameter>>, Triplet<ICache, TimeSpan, string>>, object>)
+ {
+ #region Sliding Expiration
+ var cacheScheme = (Triplet<WebRequest, Pair<Pair<string, IEnumerable<HttpPostParameter>>, Triplet<ICache, TimeSpan, string>>, object>)asyncResult;
+ var url = cacheScheme.First.RequestUri.ToString();
+ var cache = cacheScheme.Second.Second.First;
+ var expiry = cacheScheme.Second.Second.Second;
+
+ var prefix = cacheScheme.Second.Second.Third;
+ var key = CreateCacheKey(prefix, url);
+
+ var fetch = cache.Get<Stream>(key);
+ if (fetch != null)
+ {
+ var args = new WebQueryResponseEventArgs(fetch);
+ OnQueryResponse(args);
+ return;
+ }
+
+ request = cacheScheme.First;
+ boundary = cacheScheme.Second.First.First;
+ parameters = cacheScheme.Second.First.Second;
+ userState = cacheScheme.Third;
+ store = new Triplet<ICache, object, string>
+ {
+ First = cache,
+ Second = expiry,
+ Third = prefix
+ };
+ #endregion
+ }
+ else
+ {
+ // Unrecognized state signature
+ throw new ArgumentNullException("asyncResult",
+ "The asynchronous post failed to return its state");
+ }
+ }
+ else
+ {
+ request = state.First;
+ boundary = state.Second.First;
+ parameters = state.Second.Second;
+ userState = state.Third;
+ store = null;
+ }
+
+#if !Smartphone
+ var encoding = Encoding ?? Encoding.GetEncoding("ISO-8859-1");
+#else
+ var encoding = Encoding ?? Encoding.GetEncoding(1252);
+#endif
+ var expected = WriteMultiPartImpl(
+ false /* write */, parameters, boundary, encoding, null
+ );
+
+ // No cached response
+ using (var requestStream = request.EndGetRequestStream(asyncResult))
+ {
+ var actual = WriteMultiPartImpl(
+ true /* write */, parameters, boundary, encoding, requestStream
+ );
+
+ Debug.Assert(expected == actual, string.Format("Expected {0} bytes but wrote {1}!", expected, actual));
+
+ var inner = request.BeginGetResponse(PostAsyncResponseCallback,
+ new Triplet<WebRequest, Triplet<ICache, object, string>, object>
+ {
+ First = request,
+ Second = store,
+ Third = userState
+ });
+
+ RegisterAbortTimer(request, new WebQueryAsyncResult { InnerResult = inner });
+ }
+ }
+
+ protected virtual void PostAsyncResponseCallback(IAsyncResult asyncResult)
+ {
+ WebRequest request;
+ Triplet<WebRequest, Triplet<ICache, object, string>, object> state;
+ try
+ {
+ state = asyncResult.AsyncState as Triplet<WebRequest, Triplet<ICache, object, string>, object>;
+ if (state == null)
+ {
+ throw new ArgumentNullException("asyncResult", "The asynchronous post failed to return its state");
+ }
+
+ request = state.First;
+ if (request == null)
+ {
+ throw new ArgumentNullException("asyncResult", "The asynchronous post failed to return a request");
+ }
+ }
+ catch(Exception ex)
+ {
+ var args = new WebQueryResponseEventArgs(new MemoryStream(), ex);
+ OnQueryResponse(args);
+ return;
+ }
+
+ try
+ {
+ // Avoid disposing until no longer needed to build results
+ var response = request.EndGetResponse(asyncResult);
+
+#if SILVERLIGHT
+ if (DecompressionMethods == Silverlight.Compat.DecompressionMethods.GZip ||
+ DecompressionMethods == Silverlight.Compat.DecompressionMethods.Deflate ||
+ DecompressionMethods == (Silverlight.Compat.DecompressionMethods.GZip | Silverlight.Compat.DecompressionMethods.Deflate)
+ )
+ {
+ response = new GzipHttpWebResponse((HttpWebResponse)response);
+ }
+#endif
+ WebResponse = response;
+
+ ContentStream = response.GetResponseStream();
+ if (state.Second != null)
+ {
+ var cache = state.Second.First;
+ var expiry = state.Second.Second;
+ var url = request.RequestUri.ToString();
+
+ var prefix = state.Second.Third;
+ var key = CreateCacheKey(prefix, url);
+
+ if (expiry is DateTime)
+ {
+ // absolute
+ cache.Insert(key, ContentStream, (DateTime)expiry);
+ }
+
+ if (expiry is TimeSpan)
+ {
+ // sliding
+ cache.Insert(key, ContentStream, (TimeSpan)expiry);
+ }
+ }
+
+ var args = new WebQueryResponseEventArgs(ContentStream);
+ OnQueryResponse(args);
+ }
+ catch (WebException ex)
+ {
+ HandleWebException(ex);
+ }
+ }
+
+ protected virtual WebQueryAsyncResult ExecutePostOrPutAsync(PostOrPut method, string url, object userState)
+ {
+ WebResponse = null;
+
+ byte[] content;
+ var request = BuildPostOrPutWebRequest(method, url, out content);
+
+ var state = new Triplet<WebRequest, byte[], object>
+ {
+ First = request,
+ Second = content,
+ Third = userState
+ };
+
+ var args = new WebQueryRequestEventArgs(url);
+ OnQueryRequest(args);
+
+ var inner = request.BeginGetRequestStream(PostAsyncRequestCallback, state);
+ var result = new WebQueryAsyncResult { InnerResult = inner };
+ RegisterAbortTimer(request, result);
+ return result;
+ }
+
+ protected virtual WebQueryAsyncResult ExecutePostOrPutAsync(PostOrPut method,
+ string url,
+ IEnumerable<HttpPostParameter> parameters,
+ object userState)
+ {
+ WebResponse = null;
+
+ string boundary;
+ var request = BuildMultiPartFormRequest(method, url, parameters, out boundary);
+
+ var state = new Triplet<WebRequest, Pair<string, IEnumerable<HttpPostParameter>>, object>
+ {
+ First = request,
+ Second = new Pair<string, IEnumerable<HttpPostParameter>>
+ {
+ First = boundary,
+ Second = parameters
+ },
+ Third = userState
+ };
+ var args = new WebQueryRequestEventArgs(url);
+
+ OnQueryRequest(args);
+
+ var inner = request.BeginGetRequestStream(PostAsyncRequestCallbackMultiPart, state);
+ var result = new WebQueryAsyncResult { InnerResult = inner };
+ RegisterAbortTimer(request, result);
+ return result;
+ }
+
+ protected virtual WebQueryAsyncResult ExecutePostOrPutAsync(PostOrPut method,
+ string url,
+ string prefixKey,
+ ICache cache,
+ object userState)
+ {
+ WebResponse = null;
+
+ byte[] content;
+ var request = BuildPostOrPutWebRequest(method, url, out content);
+
+ var state = new Triplet<WebRequest, Triplet<byte[], ICache, string>, object>
+ {
+ First = request,
+ Second = new Triplet<byte[], ICache, string>
+ {
+ First = content,
+ Second = cache,
+ Third = prefixKey
+ },
+ Third = userState
+ };
+
+ var args = new WebQueryRequestEventArgs(url);
+ OnQueryRequest(args);
+
+ var inner = request.BeginGetRequestStream(PostAsyncRequestCallback, state);
+ var result = new WebQueryAsyncResult { InnerResult = inner };
+ RegisterAbortTimer(request, result);
+ return result;
+ }
+
+ protected virtual WebQueryAsyncResult ExecutePostOrPutAsync(PostOrPut method,
+ string url,
+ string prefixKey,
+ ICache cache,
+ DateTime absoluteExpiration,
+ object userState)
+ {
+ WebResponse = null;
+
+ byte[] content;
+ var request = BuildPostOrPutWebRequest(method, url, out content);
+
+ var state = new Triplet<WebRequest, Pair<byte[], Triplet<ICache, DateTime, string>>, object>
+ {
+ First = request,
+ Second = new Pair<byte[], Triplet<ICache, DateTime, string>>
+ {
+ First = content,
+ Second = new Triplet<ICache, DateTime, string>
+ {
+ First = cache,
+ Second = absoluteExpiration,
+ Third = prefixKey
+ }
+ },
+ Third = userState
+ };
+
+ var args = new WebQueryRequestEventArgs(url);
+ OnQueryRequest(args);
+
+ var inner = request.BeginGetRequestStream(PostAsyncRequestCallback, state);
+ var result = new WebQueryAsyncResult { InnerResult = inner };
+ RegisterAbortTimer(request, result);
+ return result;
+ }
+
+ protected virtual WebQueryAsyncResult ExecutePostOrPutAsync(PostOrPut method,
+ string url,
+ string prefixKey,
+ ICache cache,
+ TimeSpan slidingExpiration,
+ object userState)
+ {
+ WebResponse = null;
+
+ byte[] content;
+ var request = BuildPostOrPutWebRequest(method, url, out content);
+
+ var state = new Triplet<WebRequest, Pair<byte[], Triplet<ICache, TimeSpan, string>>, object>
+ {
+ First = request,
+ Second = new Pair<byte[], Triplet<ICache, TimeSpan, string>>
+ {
+ First = content,
+ Second = new Triplet<ICache, TimeSpan, string>
+ {
+ First = cache,
+ Second = slidingExpiration,
+ Third = prefixKey
+ }
+ },
+ Third = userState
+ };
+
+ var args = new WebQueryRequestEventArgs(url);
+ OnQueryRequest(args);
+
+ var inner = request.BeginGetRequestStream(PostAsyncRequestCallback, state);
+ var result = new WebQueryAsyncResult { InnerResult = inner };
+ RegisterAbortTimer(request, result);
+ return result;
+ }
+
+ public virtual WebQueryAsyncResult ExecuteStreamGetAsync(string url,
+ TimeSpan duration,
+ int resultCount)
+ {
+ WebResponse = null;
+
+ var request = BuildGetDeleteHeadOptionsWebRequest(GetDeleteHeadOptions.Get, url);
+ var state = OnGetStreamQueryRequest(url, request, duration, resultCount);
+
+#if SILVERLIGHT
+ var httpRequest = request as HttpWebRequest;
+ if (httpRequest != null)
+ {
+ httpRequest.AllowReadStreamBuffering = false;
+ }
+#endif
+
+ var inner = request.BeginGetResponse(AsyncStreamCallback, state);
+ var result = new WebQueryAsyncResult { InnerResult = inner };
+ return result;
+ }
+
+ private Pair<WebRequest, Pair<TimeSpan, int>> OnGetStreamQueryRequest(string url, WebRequest request, TimeSpan duration, int resultCount)
+ {
+ var state = new Pair<WebRequest, Pair<TimeSpan, int>>
+ {
+ First = request,
+ Second = new Pair<TimeSpan, int>
+ {
+ First = duration,
+ Second = resultCount
+ }
+ };
+
+ var args = new WebQueryRequestEventArgs(url);
+ OnQueryRequest(args);
+ return state;
+ }
+
+ private Triplet<WebRequest, byte[], Pair<TimeSpan, int>> OnPostStreamQueryRequest(string url, WebRequest request, byte[] content, TimeSpan duration, int resultCount)
+ {
+ var state = new Triplet<WebRequest, byte[], Pair<TimeSpan, int>>
+ {
+ First = request,
+ Second = content,
+ Third = new Pair<TimeSpan, int>
+ {
+ First = duration,
+ Second = resultCount
+ }
+ };
+
+ var args = new WebQueryRequestEventArgs(url);
+ OnQueryRequest(args);
+ return state;
+ }
+
+ public virtual WebQueryAsyncResult ExecuteStreamPostAsync(string url,
+ TimeSpan duration,
+ int resultCount)
+ {
+ WebResponse = null;
+
+ byte[] content;
+ var request = BuildPostOrPutWebRequest(PostOrPut.Post, url, out content);
+ var state = OnPostStreamQueryRequest(url, request, content, duration, resultCount);
+
+#if SILVERLIGHT
+ var httpRequest = request as HttpWebRequest;
+ if (httpRequest != null)
+ {
+ httpRequest.AllowReadStreamBuffering = false;
+ }
+#endif
+
+ var inner = request.BeginGetRequestStream(PostAsyncStreamRequestCallback, state);
+ var result = new WebQueryAsyncResult { InnerResult = inner };
+ return result;
+ }
+
+ private object ResponseAsHttpWebResponse(out string version,
+ out int statusCode,
+ out string statusDescription,
+ out string contentType,
+ out long contentLength,
+ out Uri responseUri,
+ out System.Net.WebHeaderCollection headers)
+ {
+ var httpWebResponse = WebResponse != null &&
+ (WebResponse is HttpWebResponse)
+ ? (HttpWebResponse) WebResponse
+ : null;
+
+ if(httpWebResponse == null)
+ {
+ version = null;
+ statusCode = 0;
+ statusDescription = null;
+ contentType = null;
+ contentLength = 0;
+ responseUri = null;
+ headers = null;
+ return null;
+ }
+
+#if !SILVERLIGHT
+ version = string.Concat("HTTP/", httpWebResponse.ProtocolVersion);
+#else
+ version = "HTTP/1.1";
+#endif
+ statusCode = Convert.ToInt32(httpWebResponse.StatusCode, CultureInfo.InvariantCulture);
+ statusDescription = httpWebResponse.StatusDescription;
+ contentType = httpWebResponse.ContentType;
+ contentLength = httpWebResponse.ContentLength;
+ responseUri = httpWebResponse.ResponseUri;
+ headers = httpWebResponse.Headers;
+ return httpWebResponse;
+ }
+
+ private object ResponseAsMockHttpWebResponse(out int statusCode,
+ out string statusDescription,
+ out string contentType,
+ out long contentLength,
+ out Uri responseUri,
+ out System.Net.WebHeaderCollection headers)
+ {
+ var httpWebResponse = WebResponse != null && WebResponse is MockHttpWebResponse
+ ? (MockHttpWebResponse)WebResponse
+ : null;
+
+ if (httpWebResponse == null)
+ {
+ statusCode = 0;
+ statusDescription = null;
+ contentType = null;
+ contentLength = 0;
+ responseUri = null;
+ headers = null;
+ return null;
+ }
+
+ statusCode = Convert.ToInt32(httpWebResponse.StatusCode, CultureInfo.InvariantCulture);
+ statusDescription = httpWebResponse.StatusDescription;
+ contentType = httpWebResponse.ContentType;
+ contentLength = httpWebResponse.ContentLength;
+ responseUri = httpWebResponse.ResponseUri;
+ headers = httpWebResponse.Headers;
+ return httpWebResponse;
+ }
+
+ private void CastWebResponse(out string version,
+ out int statusCode,
+ out string statusDescription,
+ out System.Net.WebHeaderCollection headers,
+ out string contentType,
+ out long contentLength,
+ out Uri responseUri)
+ {
+ var response = ResponseAsHttpWebResponse(
+ out version, out statusCode, out statusDescription,
+ out contentType, out contentLength,
+ out responseUri, out headers
+ );
+ if (response != null)
+ {
+ return;
+ }
+
+ response = ResponseAsMockHttpWebResponse(
+ out statusCode, out statusDescription,
+ out contentType, out contentLength,
+ out responseUri, out headers
+ );
+
+ // [DC]: Caching would result in a null response
+ if(response == null)
+ {
+ headers = new System.Net.WebHeaderCollection();
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Reflection;
+using System.Text;
+using Hammock.Attributes.Specialized;
+using Hammock.Caching;
+using Hammock.Extensions;
+using Hammock.Validation;
+using Hammock.Web.Mocks;
+
+#if SILVERLIGHT
+using Hammock.Silverlight.Compat;
+using System.IO.IsolatedStorage;
+#endif
+
+#if SILVERLIGHT && !WindowsPhone
+using System.Windows.Browser;
+using System.Net.Browser;
+#endif
+
+namespace Hammock.Web
+{
+ public abstract partial class WebQuery: IDisposable
+ {
+ private const string AcceptEncodingHeader = "Accept-Encoding";
+ private static readonly object _sync = new object();
+ private readonly WebHeaderCollection _restrictedHeaders = new WebHeaderCollection(0);
+
+ public virtual Encoding Encoding { get; protected internal set; }
+ public virtual IWebQueryInfo Info { get; protected set; }
+ public virtual string UserAgent { get; protected internal set; }
+ public virtual WebHeaderCollection Headers { get; protected set; }
+ public virtual WebParameterCollection Parameters { get; protected set; }
+ public virtual WebParameterCollection Cookies { get; protected set; }
+
+ private WebEntity _entity;
+ protected internal virtual WebEntity Entity
+ {
+ get
+ {
+ return _entity;
+ }
+ set
+ {
+ _entity = value;
+ HasEntity = _entity != null;
+ }
+ }
+
+ public virtual WebMethod Method { get; set; }
+ public virtual string Proxy { get; set; }
+ public virtual string AuthorizationHeader { get; internal set; }
+ public DecompressionMethods? DecompressionMethods { get; set; }
+ public virtual TimeSpan? RequestTimeout { get; set; }
+ public virtual WebQueryResult Result { get; internal set; }
+ public virtual object UserState { get; internal set; }
+
+#if SILVERLIGHT
+ public virtual bool HasElevatedPermissions { get; set; }
+
+ // [DC]: Headers to use when access isn't direct
+ public virtual string SilverlightUserAgentHeader { get; set; }
+ public virtual string SilverlightAcceptEncodingHeader { get; set; }
+#endif
+
+#if !Silverlight
+ public virtual ServicePoint ServicePoint { get; set; }
+ public virtual bool KeepAlive { get; set; }
+ public virtual bool FollowRedirects { get; internal set; }
+#endif
+
+ private WebResponse _webResponse;
+ public virtual WebResponse WebResponse
+ {
+ get
+ {
+ lock (_sync)
+ {
+ return _webResponse;
+ }
+ }
+ set
+ {
+ lock (_sync)
+ {
+ _webResponse = value;
+ }
+ }
+ }
+
+ protected virtual Stream ContentStream { get; set; }
+ public virtual bool HasEntity { get; set; }
+ public virtual byte[] PostContent { get; set; }
+
+#if SL3 || SL4
+ static WebQuery()
+ {
+ // [DC]: Opt-in to the networking stack so we can get headers for proxies
+ WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);
+ WebRequest.RegisterPrefix("https://", WebRequestCreator.ClientHttp);
+ }
+#endif
+
+ protected WebQuery(bool enableTrace) : this(null, enableTrace)
+ {
+
+ }
+
+ protected WebQuery(IWebQueryInfo info, bool enableTrace)
+ {
+ TraceEnabled = enableTrace;
+ SetQueryMeta(info);
+ InitializeResult();
+ }
+
+ protected bool TraceEnabled { get; private set; }
+
+ private void SetQueryMeta(IWebQueryInfo info)
+ {
+ Cookies = new WebParameterCollection(0);
+
+ if(info == null)
+ {
+ Headers = new WebHeaderCollection(0);
+ Parameters = new WebParameterCollection(0);
+ return;
+ }
+
+ Info = info;
+ IEnumerable<PropertyInfo> properties;
+ IDictionary<string, string> transforms;
+
+ ParseTransforms(out properties, out transforms);
+ Headers = ParseInfoHeaders(properties, transforms);
+ Parameters = ParseInfoParameters(properties, transforms);
+ ParseUserAgent(properties);
+ ParseWebEntity(properties);
+ }
+
+ private void ParseTransforms(out IEnumerable<PropertyInfo> properties,
+ out IDictionary<string, string> transforms)
+ {
+ properties = Info.GetType().GetProperties();
+ transforms = new Dictionary<string, string>(0);
+ Info.ParseValidationAttributes(properties, transforms);
+ }
+
+ private void InitializeResult()
+ {
+ Result = new WebQueryResult();
+ QueryRequest += (s, e) => SetRequestResults(e);
+ QueryResponse += (s, e) => SetResponseResults(e);
+ }
+
+ private void SetResponseResults(WebQueryResponseEventArgs e)
+ {
+ Result.ContentStream = e.Response;
+ Result.ResponseDate = DateTime.UtcNow;
+ Result.RequestHttpMethod = Method.ToUpper();
+ Result.IsMock = WebResponse is MockHttpWebResponse;
+ Result.TimedOut = TimedOut;
+
+ string version;
+ int statusCode;
+ string statusDescription;
+ System.Net.WebHeaderCollection headers;
+ string contentType;
+ long contentLength;
+ Uri responseUri;
+ CastWebResponse(
+ out version, out statusCode, out statusDescription, out headers,
+ out contentType, out contentLength, out responseUri
+ );
+
+#if !MonoTouch
+ TraceResponse(
+ responseUri, version, headers, statusCode, statusDescription
+ );
+#endif
+
+ Result.WebResponse = WebResponse;
+ Result.ResponseHttpStatusCode = statusCode;
+ Result.ResponseHttpStatusDescription = statusDescription;
+ Result.ResponseType = contentType;
+ Result.ResponseLength = contentLength;
+ Result.ResponseUri = responseUri;
+ Result.Exception = e.Exception;
+ }
+
+#if !MonoTouch
+ [Conditional("TRACE")]
+ private void TraceResponse(Uri uri, string version, System.Net.WebHeaderCollection headers, int statusCode, string statusDescription)
+ {
+ if(!TraceEnabled)
+ {
+ return;
+ }
+
+ Trace.WriteLine(
+ String.Concat("\r\n--RESPONSE:", " ", uri)
+ );
+ Trace.WriteLine(
+ String.Concat(version, " ", statusCode, " ", statusDescription)
+ );
+ foreach (var trace in headers.AllKeys.Select(
+ key => String.Concat(key, ": ", headers[key])))
+ {
+ Trace.WriteLine(trace);
+ }
+ }
+#endif
+
+ private void SetRequestResults(WebQueryRequestEventArgs e)
+ {
+ Result.RequestDate = DateTime.UtcNow;
+ Result.RequestUri = new Uri(e.Request);
+#if !SILVERLIGHT
+ Result.RequestKeptAlive = KeepAlive;
+#endif
+ }
+
+#if !SILVERLIGHT
+ protected virtual void SetWebProxy(WebRequest request)
+ {
+#if !Smartphone && !NETCF
+ var proxyUriBuilder = new UriBuilder(Proxy);
+ request.Proxy = new WebProxy(proxyUriBuilder.Host,
+ proxyUriBuilder.Port);
+
+ if (!proxyUriBuilder.UserName.IsNullOrBlank())
+ {
+ request.Headers["Proxy-Authorization"] = WebExtensions.ToBasicAuthorizationHeader(proxyUriBuilder.UserName,
+ proxyUriBuilder.Password);
+ }
+#else
+ var uri = new Uri(Proxy);
+ request.Proxy = new WebProxy(uri.Host, uri.Port);
+ var userParts = uri.UserInfo.Split(new[] { ':' }).Where(ui => !ui.IsNullOrBlank()).ToArray();
+ if (userParts.Length == 2)
+ {
+ request.Proxy.Credentials = new NetworkCredential(userParts[0], userParts[1]);
+ }
+#endif
+ }
+#endif
+
+ protected virtual WebRequest BuildPostOrPutWebRequest(PostOrPut method, string url, out byte[] content)
+ {
+ return !HasEntity
+ ? BuildPostOrPutFormWebRequest(method, url, out content)
+ : BuildPostOrPutEntityWebRequest(method, url, out content);
+ }
+
+ protected virtual Func<string, string> BeforeBuildPostOrPutFormWebRequest()
+ {
+ return url => AppendParameters(url).Replace(url + "?", "");
+ }
+
+ protected virtual WebRequest BuildPostOrPutFormWebRequest(PostOrPut method, string url, out byte[] content)
+ {
+ var post = BeforeBuildPostOrPutFormWebRequest().Invoke(url);
+
+ var request = WebRequest.Create(url);
+
+ AuthenticateRequest(request);
+
+ SetMethod(method.ToString(), request);
+
+ // It should be possible to override the content type in the case of AddPostContent
+ var hasContentType = Headers.AllKeys.Where(
+ key => key.Equals("Content-Type", StringComparison.InvariantCultureIgnoreCase)
+ ).Count() > 0;
+
+ if(!hasContentType)
+ {
+ request.ContentType = "application/x-www-form-urlencoded";
+ }
+
+ HandleRequestMeta(request);
+
+#if !MonoTouch
+ TraceRequest(request);
+#endif
+ content = BuildPostOrPutContent(request, post);
+
+#if !SILVERLIGHT
+ request.ContentLength = content.Length;
+#endif
+ return request;
+ }
+
+ protected virtual byte[] BuildPostOrPutContent(WebRequest request, string post)
+ {
+ var encoding = Encoding ?? Encoding.UTF8;
+
+ var content = PostContent ?? encoding.GetBytes(post);
+
+#if TRACE
+ Trace.WriteLineIf(TraceEnabled, string.Concat("\r\n", content));
+#endif
+ return content;
+ }
+
+ protected virtual Func<string, string> BeforeBuildPostOrPutEntityWebRequest()
+ {
+ return AppendParameters;
+ }
+
+ protected virtual WebRequest BuildPostOrPutEntityWebRequest(PostOrPut method, string url, out byte[] content)
+ {
+ url = BeforeBuildPostOrPutEntityWebRequest().Invoke(url);
+
+ var request = WebRequest.Create(url);
+
+ SetMethod(method.ToString(), request);
+
+ AuthenticateRequest(request);
+
+ HandleRequestMeta(request);
+
+#if !MonoTouch
+ TraceRequest(request);
+#endif
+
+ if (Entity != null)
+ {
+ var entity = Entity.Content;
+
+ var encoding = Entity.ContentEncoding ?? Encoding ?? Encoding.UTF8;
+
+ content = encoding.GetBytes(entity);
+
+ request.ContentType = Entity.ContentType;
+#if TRACE
+ Trace.WriteLineIf(TraceEnabled, string.Concat("\r\n", entity));
+#endif
+
+#if !SILVERLIGHT
+ // [DC]: This is set by Silverlight
+ request.ContentLength = content.Length;
+#endif
+ }
+ else
+ {
+ using(var ms = new MemoryStream())
+ {
+ content = ms.ToArray();
+ }
+ }
+
+ return request;
+ }
+
+ protected virtual Func<string, string> BeforeBuildGetDeleteHeadOptionsWebRequest()
+ {
+ return AppendParameters;
+ }
+
+ protected virtual WebRequest BuildGetDeleteHeadOptionsWebRequest(GetDeleteHeadOptions method, string url)
+ {
+ url = BeforeBuildGetDeleteHeadOptionsWebRequest().Invoke(url);
+
+ var request = WebRequest.Create(url);
+
+ SetMethod(method.ToString(), request);
+
+ AuthenticateRequest(request);
+
+ HandleRequestMeta(request);
+
+#if !MonoTouch
+ TraceRequest(request);
+#endif
+ return request;
+ }
+
+ private void SetMethod(string method, WebRequest request)
+ {
+ request.Method = method.ToUpper();
+ }
+
+ private void HandleRequestMeta(WebRequest request)
+ {
+ // [DC] LSP violation necessary for "pure" mocks
+ if (request is HttpWebRequest)
+ {
+ SetRequestMeta((HttpWebRequest)request);
+ }
+ else
+ {
+ AppendHeaders(request);
+ SetUserAgent(request);
+ }
+ }
+
+ protected virtual void SetUserAgent(WebRequest request)
+ {
+ if (!UserAgent.IsNullOrBlank())
+ {
+#if SILVERLIGHT && !WindowsPhone
+ // [DC] User-Agent is still restricted in elevated mode
+ request.Headers[SilverlightUserAgentHeader ?? "X-User-Agent"] = UserAgent;
+#else
+ if(request is HttpWebRequest)
+ {
+ ((HttpWebRequest) request).UserAgent = UserAgent;
+ }
+ else
+ {
+ request.Headers["User-Agent"] = UserAgent;
+ }
+#endif
+ }
+ }
+
+ protected virtual void SetRequestMeta(HttpWebRequest request)
+ {
+ AppendHeaders(request);
+ AppendCookies(request);
+
+#if !SILVERLIGHT
+ if (ServicePoint != null)
+ {
+#if !Smartphone && !NETCF
+ request.ServicePoint.ConnectionLeaseTimeout = ServicePoint.ConnectionLeaseTimeout;
+ request.ServicePoint.ReceiveBufferSize = ServicePoint.ReceiveBufferSize;
+ request.ServicePoint.UseNagleAlgorithm = ServicePoint.UseNagleAlgorithm;
+ request.ServicePoint.BindIPEndPointDelegate = ServicePoint.BindIPEndPointDelegate;
+#endif
+ request.ServicePoint.ConnectionLimit = ServicePoint.ConnectionLimit;
+ request.ServicePoint.Expect100Continue = ServicePoint.Expect100Continue;
+ request.ServicePoint.MaxIdleTime = ServicePoint.MaxIdleTime;
+ }
+#endif
+
+#if !SILVERLIGHT
+ if (!Proxy.IsNullOrBlank())
+ {
+ SetWebProxy(request);
+ }
+ request.AllowAutoRedirect = FollowRedirects;
+#endif
+
+ SetUserAgent(request);
+
+ if (DecompressionMethods.HasValue)
+ {
+ var decompressionMethods = DecompressionMethods.Value;
+
+#if !SILVERLIGHT && !WindowsPhone
+ request.AutomaticDecompression = decompressionMethods;
+#else
+
+#if !WindowsPhone
+ if (HasElevatedPermissions)
+ {
+#endif
+ switch (decompressionMethods)
+ {
+ case Silverlight.Compat.DecompressionMethods.GZip:
+ request.Headers[SilverlightAcceptEncodingHeader ?? "X-Accept-Encoding"] = "gzip";
+ break;
+ case Silverlight.Compat.DecompressionMethods.Deflate:
+ request.Headers[SilverlightAcceptEncodingHeader ?? "X-Accept-Encoding"] = "deflate";
+ break;
+ case Silverlight.Compat.DecompressionMethods.GZip | Silverlight.Compat.DecompressionMethods.Deflate:
+ request.Headers[SilverlightAcceptEncodingHeader ?? "X-Accept-Encoding"] = "gzip,deflate";
+ break;
+ }
+
+#if !WindowsPhone
+ }
+ else
+ {
+ switch (decompressionMethods)
+ {
+ case Silverlight.Compat.DecompressionMethods.GZip:
+ request.Headers[SilverlightAcceptEncodingHeader ?? "X-Accept-Encoding"] = "gzip";
+ break;
+ case Silverlight.Compat.DecompressionMethods.Deflate:
+ request.Headers[SilverlightAcceptEncodingHeader ?? "X-Accept-Encoding"] = "deflate";
+ break;
+ case Silverlight.Compat.DecompressionMethods.GZip | Silverlight.Compat.DecompressionMethods.Deflate:
+ request.Headers[SilverlightAcceptEncodingHeader ?? "X-Accept-Encoding"] = "gzip,deflate";
+ break;
+ }
+ }
+#endif
+
+#endif
+ }
+#if !SILVERLIGHT
+ if (RequestTimeout.HasValue)
+ {
+ // [DC] Need to synchronize these as Timeout is ignored in async requests
+ request.Timeout = (int)RequestTimeout.Value.TotalMilliseconds;
+ request.ReadWriteTimeout = (int)RequestTimeout.Value.TotalMilliseconds;
+ }
+
+ if (KeepAlive)
+ {
+ request.KeepAlive = true;
+ }
+#endif
+ }
+
+ private void AppendCookies(HttpWebRequest request)
+ {
+#if !NETCF
+ request.CookieContainer = new CookieContainer();
+
+ foreach(var cookie in Cookies.OfType<HttpCookieParameter>())
+ {
+ var value = new Cookie(cookie.Name, cookie.Value);
+ if(cookie.Domain != null)
+ {
+ request.CookieContainer.Add(cookie.Domain, value);
+ }
+#if !SILVERLIGHT
+ else
+ {
+ request.CookieContainer.Add(value);
+ }
+#endif
+ }
+#endif
+ }
+
+ protected virtual void AppendHeaders(WebRequest request)
+ {
+ if (!(request is HttpWebRequest) &&
+ !(request is MockHttpWebRequest))
+ {
+ return;
+ }
+
+ // [DC]: Combine all duplicate headers into CSV
+ var headers = new Dictionary<string, string>(0);
+ foreach(var header in Headers)
+ {
+ string value;
+ if(headers.ContainsKey(header.Name))
+ {
+ value = String.Concat(headers[header.Name], ",", header.Value);
+ headers.Remove(header.Name);
+ }
+ else
+ {
+ value = header.Value;
+ }
+
+ headers.Add(header.Name, value);
+ }
+
+ foreach (var header in headers)
+ {
+ if (_restrictedHeaderActions.ContainsKey(header.Key))
+ {
+ if(request is HttpWebRequest)
+ {
+#if SILVERLIGHT
+ if(header.Key.EqualsIgnoreCase("User-Agent"))
+ {
+ // [DC]: User-Agent is still restricted in elevated mode
+ request.Headers[SilverlightUserAgentHeader ?? "X-User-Agent"] = UserAgent;
+ continue;
+ }
+#endif
+ _restrictedHeaderActions[header.Key].Invoke((HttpWebRequest) request, header.Value);
+ _restrictedHeaders.Add(header.Key, header.Value);
+ }
+ if(request is MockHttpWebRequest)
+ {
+ AddHeader(header, request);
+ }
+ }
+ else
+ {
+ AddHeader(header, request);
+ }
+ }
+ }
+
+#if !MonoTouch
+ [Conditional("TRACE")]
+ private void TraceHeaders(WebRequest request)
+ {
+ if (!TraceEnabled)
+ {
+ return;
+ }
+
+ var restricted = _restrictedHeaders.AllKeys.Select(key => String.Concat(key, ": ", request.Headers[key]));
+ var remaining = request.Headers.AllKeys.Except(_restrictedHeaders.AllKeys).Select(key => String.Concat(key, ": ", request.Headers[key]));
+ var all = restricted.ToList();
+ all.AddRange(remaining);
+ all.Sort();
+
+ foreach (var trace in all)
+ {
+ Trace.WriteLine(trace);
+ }
+ }
+#endif
+
+ private static void AddHeader(KeyValuePair<string, string> header, WebRequest request)
+ {
+#if !SILVERLIGHT
+ request.Headers.Add(header.Key, header.Value);
+#else
+ request.Headers[header.Key] = header.Value;
+#endif
+ }
+
+#if !SILVERLIGHT
+ private readonly IDictionary<string, Action<HttpWebRequest, string>> _restrictedHeaderActions
+ = new Dictionary<string, Action<HttpWebRequest, string>>(StringComparer.OrdinalIgnoreCase)
+ {
+ {"Accept", (r, v) => r.Accept = v},
+ {"Connection", (r, v) => r.Connection = v},
+ {"Content-Length", (r, v) => r.ContentLength = Convert.ToInt64(v)},
+ {"Content-Type", (r, v) => r.ContentType = v},
+ {"Expect", (r, v) => r.Expect = v},
+ {"Date", (r, v) => { /* Set by system */ }},
+ {"Host", (r, v) => { /* Set by system */ }},
+ {"If-Modified-Since", (r, v) => r.IfModifiedSince = Convert.ToDateTime(v)},
+ {"Range", (r, v) => { throw new NotSupportedException( /* r.AddRange() */); }},
+ {"Referer", (r, v) => r.Referer = v},
+ {"Transfer-Encoding", (r, v) => { r.TransferEncoding = v; r.SendChunked = true; }},
+ {"User-Agent", (r, v) => r.UserAgent = v }
+ };
+#else
+ private readonly IDictionary<string, Action<HttpWebRequest, string>> _restrictedHeaderActions
+ = new Dictionary<string, Action<HttpWebRequest, string>>(StringComparer.OrdinalIgnoreCase) {
+ { "Accept", (r, v) => r.Accept = v },
+ { "Connection", (r, v) => { /* Set by Silverlight */ }},
+ { "Content-Length", (r, v) => { /* Set by Silverlight */ }},
+ { "Content-Type", (r, v) => r.ContentType = v },
+ { "Expect", (r, v) => { /* Set by Silverlight */ }},
+ { "Date", (r, v) => { /* Set by Silverlight */ }},
+ { "Host", (r, v) => { /* Set by Silverlight */ }},
+ { "If-Modified-Since", (r, v) => { /* Not supported */ }},
+ { "Range", (r, v) => { /* Not supported */ }},
+ { "Referer", (r, v) => { /* Not supported */ }},
+ { "Transfer-Encoding", (r, v) => { /* Not supported */ }},
+ { "User-Agent", (r, v) => { /* Not supported here */ }}
+ };
+#endif
+
+ protected virtual string AppendParameters(string url)
+ {
+ var count = 0;
+
+ var parameters = Parameters.Where(
+ parameter => !(parameter is HttpPostParameter) || Method == WebMethod.Post).Where(
+ parameter => !string.IsNullOrEmpty(parameter.Name) && !string.IsNullOrEmpty(parameter.Value)
+ );
+
+ foreach (var parameter in parameters)
+ {
+ // GET parameters in URL
+ url = url.Then(count > 0 || url.Contains("?") ? "&" : "?");
+ url = url.Then("{0}={1}".FormatWith(parameter.Name, parameter.Value.UrlEncode()));
+ count++;
+ }
+
+ return url;
+ }
+
+ // [DC] Headers don't need to be unique, this should change
+ protected virtual WebHeaderCollection ParseInfoHeaders(IEnumerable<PropertyInfo> properties,
+ IDictionary<string, string> transforms)
+ {
+ var headers = new Dictionary<string, string>();
+
+ Info.ParseNamedAttributes<HeaderAttribute>(properties, transforms, headers);
+
+ var collection = new WebHeaderCollection();
+ headers.ForEach(p => collection.Add(new WebHeader(p.Key, p.Value)));
+
+ return collection;
+ }
+
+ protected virtual WebParameterCollection ParseInfoParameters(IEnumerable<PropertyInfo> properties,
+ IDictionary<string, string> transforms)
+ {
+ var parameters = new Dictionary<string, string>();
+
+ Info.ParseNamedAttributes<ParameterAttribute>(properties, transforms, parameters);
+
+ var collection = new WebParameterCollection();
+ parameters.ForEach(p => collection.Add(new WebParameter(p.Key, p.Value)));
+
+ return collection;
+ }
+
+ protected virtual WebParameterCollection ParseInfoParameters()
+ {
+ IEnumerable<PropertyInfo> properties;
+ IDictionary<string, string> transforms;
+ ParseTransforms(out properties, out transforms);
+ return ParseInfoParameters(properties, transforms);
+ }
+
+ private void ParseUserAgent(IEnumerable<PropertyInfo> properties)
+ {
+ var count = 0;
+ foreach (var property in properties)
+ {
+ var attributes = property.GetCustomAttributes<UserAgentAttribute>(true);
+ count += attributes.Count();
+ if (count > 1)
+ {
+ throw new ArgumentException("Cannot declare more than one user agent per query");
+ }
+
+ if (count < 1)
+ {
+ continue;
+ }
+
+ if (!UserAgent.IsNullOrBlank())
+ {
+ continue;
+ }
+
+ var value = property.GetValue(Info, null);
+ UserAgent = value != null ? value.ToString() : null;
+ }
+ }
+
+ private void ParseWebEntity(IEnumerable<PropertyInfo> properties)
+ {
+ if (Entity != null)
+ {
+ // Already set by client or request
+ return;
+ }
+
+ var count = 0;
+ foreach (var property in properties)
+ {
+ var attributes = property.GetCustomAttributes<EntityAttribute>(true);
+ count += attributes.Count();
+ if (count > 1)
+ {
+ throw new ValidationException("Cannot declare more than one entity per query");
+ }
+
+ if (count < 1)
+ {
+ continue;
+ }
+
+ if (Entity != null)
+ {
+ // Already set in this pass
+ continue;
+ }
+
+ var value = property.GetValue(Info, null);
+
+ var content = value != null ? value.ToString() : null;
+ var contentEncoding = attributes.Single().ContentEncoding;
+ var contentType = attributes.Single().ContentType;
+
+ Entity = new WebEntity
+ {
+ Content = content,
+ ContentEncoding = contentEncoding,
+ ContentType = contentType
+ };
+ }
+ }
+
+ protected void HandleWebException(WebException exception)
+ {
+ if (!(exception.Response is HttpWebResponse))
+ {
+ return;
+ }
+
+ var response = exception.Response;
+#if SILVERLIGHT
+ if (DecompressionMethods == Silverlight.Compat.DecompressionMethods.GZip ||
+ DecompressionMethods == Silverlight.Compat.DecompressionMethods.Deflate ||
+ DecompressionMethods == (Silverlight.Compat.DecompressionMethods.GZip | Silverlight.Compat.DecompressionMethods.Deflate)
+ )
+ {
+ response = new GzipHttpWebResponse((HttpWebResponse)response);
+ }
+#endif
+ WebResponse = response;
+ var stream = WebResponse.GetResponseStream();
+
+ if (stream == null)
+ {
+ return;
+ }
+
+ var args = new WebQueryResponseEventArgs(stream, exception);
+ OnQueryResponse(args);
+ }
+
+ protected abstract void SetAuthorizationHeader(WebRequest request, string header);
+
+ protected abstract void AuthenticateRequest(WebRequest request);
+
+ public abstract string GetAuthorizationContent();
+
+ private static string CreateCacheKey(string prefix, string url)
+ {
+ return !prefix.IsNullOrBlank() ? "{0}_{1}".FormatWith(prefix, url) : url;
+ }
+
+ protected virtual void ExecuteWithCache(ICache cache,
+ string url,
+ string key,
+ Action<ICache, string> cacheScheme)
+ {
+ var fetch = cache.Get<Stream>(CreateCacheKey(key, url));
+ if (fetch != null)
+ {
+ // [DC]: In order to build results, an event must still raise
+ var responseArgs = new WebQueryResponseEventArgs(fetch);
+ OnQueryResponse(responseArgs);
+ }
+ else
+ {
+ cacheScheme.Invoke(cache, url);
+ }
+ }
+
+ protected virtual void ExecuteWithCacheAndAbsoluteExpiration(ICache cache,
+ string url,
+ string key,
+ DateTime expiry,
+ Action<ICache, string, DateTime> cacheScheme)
+ {
+ var fetch = cache.Get<Stream>(CreateCacheKey(key, url));
+ if (fetch != null)
+ {
+ // [DC]: In order to build results, an event must still raise
+ var responseArgs = new WebQueryResponseEventArgs(fetch);
+ OnQueryResponse(responseArgs);
+ }
+ else
+ {
+ cacheScheme.Invoke(cache, url, expiry);
+ }
+ }
+
+ protected virtual void ExecuteWithCacheAndSlidingExpiration(ICache cache,
+ string url,
+ string key,
+ TimeSpan expiry,
+ Action<ICache, string, TimeSpan> cacheScheme)
+ {
+ var fetch = cache.Get<Stream>(CreateCacheKey(key, url));
+ if (fetch != null)
+ {
+ // [DC]: In order to build results, an event must still raise
+ var responseArgs = new WebQueryResponseEventArgs(fetch);
+ OnQueryResponse(responseArgs);
+ }
+ else
+ {
+ cacheScheme.Invoke(cache, url, expiry);
+ }
+ }
+
+#if !SILVERLIGHT
+ protected virtual void ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions method, string url, string key, ICache cache, out WebException exception)
+ {
+ WebException ex = null;
+ ExecuteWithCache(cache, url, key, (c, u) => ExecuteGetDeleteHeadOptions(method, cache, url, key, out ex));
+ exception = ex;
+ }
+
+ protected virtual void ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions method,
+ string url,
+ string key,
+ ICache cache,
+ DateTime absoluteExpiration,
+ out WebException exception)
+ {
+ WebException ex = null;
+ ExecuteWithCacheAndAbsoluteExpiration(cache, url, key, absoluteExpiration,
+ (c, u, e) =>
+ ExecuteGetDeleteHeadOptions(method, cache, url, key, absoluteExpiration, out ex));
+ exception = ex;
+ }
+
+ protected virtual void ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions method,
+ string url,
+ string key,
+ ICache cache,
+ TimeSpan slidingExpiration,
+ out WebException exception)
+ {
+ WebException ex = null;
+ ExecuteWithCacheAndSlidingExpiration(cache, url, key, slidingExpiration,
+ (c, u, e) =>
+ ExecuteGetDeleteHeadOptions(method, cache, url, key, slidingExpiration, out ex));
+ exception = ex;
+ }
+
+ private void ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions method,
+ ICache cache,
+ string url,
+ string key,
+ out WebException exception)
+ {
+ ExecuteGetDeleteHeadOptions(method, url, out exception);
+ if (exception == null)
+ {
+ cache.Insert(CreateCacheKey(key, url), ContentStream);
+ }
+ }
+
+ private void ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions method,
+ ICache cache,
+ string url,
+ string key,
+ DateTime absoluteExpiration,
+ out WebException exception)
+ {
+ ExecuteGetDeleteHeadOptions(method, url, out exception);
+ if (exception == null)
+ {
+ cache.Insert(CreateCacheKey(key, url), ContentStream, absoluteExpiration);
+ }
+ }
+
+ private void ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions method, ICache cache, string url, string key,
+ TimeSpan slidingExpiration, out WebException exception)
+ {
+ ExecuteGetDeleteHeadOptions(method, url, out exception);
+ if (exception == null)
+ {
+ cache.Insert(CreateCacheKey(key, url), ContentStream, slidingExpiration);
+ }
+ }
+#endif
+
+ public virtual event EventHandler<WebQueryRequestEventArgs> QueryRequest;
+ public virtual void OnQueryRequest(WebQueryRequestEventArgs args)
+ {
+ var handler = QueryRequest;
+ if (handler != null)
+ {
+ handler(this, args);
+ }
+ }
+
+ public virtual event EventHandler<WebQueryResponseEventArgs> QueryResponse;
+ public virtual void OnQueryResponse(WebQueryResponseEventArgs args)
+ {
+ var handler = QueryResponse;
+ if (handler != null)
+ {
+ handler(this, args);
+ }
+ }
+
+ internal virtual event EventHandler<PostProgressEventArgs> PostProgress;
+ internal virtual void OnPostProgress(PostProgressEventArgs args)
+ {
+ var handler = PostProgress;
+ if (handler != null)
+ {
+ handler(this, args);
+ }
+ }
+#if !SILVERLIGHT
+ protected virtual void ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions method, string url, out WebException exception)
+ {
+ WebResponse = null;
+ var request = BuildGetDeleteHeadOptionsWebRequest(method, url);
+
+ var requestArgs = new WebQueryRequestEventArgs(url);
+ OnQueryRequest(requestArgs);
+
+ ExecuteGetDeleteHeadOptions(request, out exception);
+ }
+
+ private void ExecuteGetDeleteHeadOptions(WebRequest request, out WebException exception)
+ {
+ try
+ {
+ // [DC] Avoid disposing until no longer needed to build results
+ var response = request.GetResponse();
+ WebResponse = response;
+
+ if (response != null)
+ {
+ ContentStream = response.GetResponseStream();
+ if (ContentStream != null)
+ {
+ var args = new WebQueryResponseEventArgs(ContentStream);
+ OnQueryResponse(args);
+ }
+ }
+
+ exception = null;
+ }
+ catch (WebException ex)
+ {
+ exception = ex;
+ HandleWebException(ex);
+ }
+ }
+
+#endif
+ protected virtual WebRequest BuildMultiPartFormRequest(PostOrPut method, string url, IEnumerable<HttpPostParameter> parameters, out string boundary)
+ {
+ url = AppendParameters(url);
+
+ boundary = Guid.NewGuid().ToString();
+ var request = WebRequest.Create(url);
+ AuthenticateRequest(request);
+
+ request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
+ request.Method = method == PostOrPut.Post ? "POST" : "PUT";
+
+ HandleRequestMeta(request);
+
+#if !MonoTouch
+ TraceRequest(request);
+#endif
+
+ return request;
+ }
+
+#if !MonoTouch
+ [Conditional("TRACE")]
+ protected void TraceRequest(WebRequest request)
+ {
+ if (!TraceEnabled)
+ {
+ return;
+ }
+
+ var version = request is HttpWebRequest ?
+#if SILVERLIGHT
+ "HTTP/v1.1" :
+#else
+ string.Concat("HTTP/", ((HttpWebRequest)request).ProtocolVersion) :
+#endif
+ "HTTP/v1.1";
+
+ Trace.WriteLine(
+ String.Concat("--REQUEST: ", request.RequestUri.Scheme, "://", request.RequestUri.Host)
+ );
+ var pathAndQuery = String.Concat(
+ request.RequestUri.AbsolutePath, string.IsNullOrEmpty(request.RequestUri.Query)
+ ? ""
+ : string.Concat(request.RequestUri.Query)
+ );
+ Trace.WriteLine(
+ String.Concat(request.Method, " ", pathAndQuery, " ", version
+ ));
+
+ TraceHeaders(request);
+ }
+#endif
+
+#if !SILVERLIGHT
+ protected virtual void ExecutePostOrPut(PostOrPut method, string url, out WebException exception)
+ {
+ WebResponse = null;
+ exception = null;
+ byte[] post;
+ var request = BuildPostOrPutWebRequest(method, url, out post);
+
+ var requestArgs = new WebQueryRequestEventArgs(url);
+ OnQueryRequest(requestArgs);
+
+ try
+ {
+ using (var stream = request.GetRequestStream())
+ {
+ stream.Write(post, 0, post.Length);
+ stream.Close();
+
+#if TRACE
+ var encoding = Encoding ?? new UTF8Encoding();
+#if NETCF
+ Trace.WriteLineIf(TraceEnabled, encoding.GetString(post, 0, post.Length));
+#else
+ Trace.WriteLineIf(TraceEnabled, encoding.GetString(post));
+#endif
+#endif
+
+ // [DC] Avoid disposing until no longer needed to build results
+ var response = request.GetResponse();
+ WebResponse = response;
+
+ if (response != null)
+ {
+ ContentStream = response.GetResponseStream();
+ if (ContentStream != null)
+ {
+ var args = new WebQueryResponseEventArgs(ContentStream);
+ OnQueryResponse(args);
+ }
+ }
+ }
+ }
+ catch (WebException ex)
+ {
+ exception = ex;
+ HandleWebException(ex);
+ }
+ }
+
+ protected virtual void ExecutePostOrPut(PostOrPut method,
+ string url,
+ IEnumerable<HttpPostParameter> parameters,
+ out WebException exception)
+ {
+ WebResponse = null;
+
+ string boundary;
+ var request = BuildMultiPartFormRequest(method, url, parameters, out boundary);
+
+#if !Smartphone
+ var encoding = Encoding ?? Encoding.GetEncoding("ISO-8859-1");
+#else
+ var encoding = Encoding ?? Encoding.GetEncoding(1252);
+#endif
+ var expected = WriteMultiPartImpl(
+ false /* write */, parameters, boundary, encoding, null
+ );
+
+ request.ContentLength = expected;
+
+ try
+ {
+ using (var requestStream = request.GetRequestStream())
+ {
+#if DEBUG
+ var actual = WriteMultiPartImpl(
+ true /* write */, parameters, boundary, encoding, requestStream
+ );
+
+ Debug.Assert(expected == actual, string.Format("Expected {0} bytes but wrote {1}!", expected, actual));
+#else
+ WriteMultiPartImpl(
+ true /* write */, parameters, boundary, encoding, requestStream
+ );
+#endif
+
+ // [DC] Avoid disposing until no longer needed to build results
+ var response = request.GetResponse();
+ WebResponse = response;
+
+ if (response != null)
+ {
+ ContentStream = response.GetResponseStream();
+ if (ContentStream != null)
+ {
+ var args = new WebQueryResponseEventArgs(ContentStream);
+ OnQueryResponse(args);
+ }
+ }
+
+ exception = null;
+ }
+ }
+ catch (WebException ex)
+ {
+ exception = ex;
+ HandleWebException(ex);
+ }
+ }
+#endif
+
+ private static int Write(bool write, Encoding encoding, Stream requestStream, string input)
+ {
+ var dataBytes = encoding.GetBytes(input);
+ if(write)
+ {
+ requestStream.Write(dataBytes, 0, dataBytes.Length);
+ }
+ return dataBytes.Length;
+ }
+
+ private static int WriteLine(bool write, Encoding encoding, Stream requestStream, string input)
+ {
+ var sb = new StringBuilder();
+ sb.AppendLine(input);
+
+ var dataBytes = encoding.GetBytes(sb.ToString());
+ if (write)
+ {
+ requestStream.Write(dataBytes, 0, dataBytes.Length);
+ }
+ return dataBytes.Length;
+ }
+
+ private long WriteMultiPartImpl(bool write, IEnumerable<HttpPostParameter> parameters, string boundary, Encoding encoding, Stream requestStream)
+ {
+ Stream fs = null;
+ var header = string.Format("--{0}", boundary);
+ var footer = string.Format("--{0}--", boundary);
+ long written = 0;
+
+ foreach (var parameter in parameters)
+ {
+ written += WriteLine(write, encoding, requestStream, header);
+#if TRACE
+ if(write)
+ {
+ Trace.WriteLineIf(TraceEnabled, header);
+ }
+#endif
+ switch (parameter.Type)
+ {
+ case HttpPostParameterType.File:
+ {
+ var disposition = parameter.ContentDisposition ?? "form-data";
+ var fileMask = "Content-Disposition: " + disposition + "; name=\"{0}\"; filename=\"{1}\"";
+ var fileHeader = fileMask.FormatWith(parameter.Name, parameter.FileName);
+ var fileLine = "Content-Type: {0}".FormatWith(parameter.ContentType.ToLower());
+
+ written += WriteLine(write, encoding, requestStream, fileHeader);
+ written += WriteLine(write, encoding, requestStream, fileLine);
+ written += WriteLine(write, encoding, requestStream, "");
+#if TRACE
+ if (write)
+ {
+ Trace.WriteLineIf(TraceEnabled, fileHeader);
+ Trace.WriteLineIf(TraceEnabled, fileLine);
+ Trace.WriteLineIf(TraceEnabled, "");
+ Trace.WriteLineIf(TraceEnabled, "[FILE DATA]");
+ }
+#endif
+
+#if !SILVERLIGHT
+ fs = parameter.FileStream ?? new FileStream(parameter.FilePath, FileMode.Open, FileAccess.Read);
+#else
+ if (parameter.FileStream == null)
+ {
+ var store = IsolatedStorageFile.GetUserStoreForApplication();
+ var stream = store.OpenFile(parameter.FilePath, FileMode.Open, FileAccess.Read);
+ parameter.FileStream = stream;
+ }
+
+ fs = parameter.FileStream; // <-- WP7 requires a stream
+#endif
+ {
+ if(!write)
+ {
+ written += fs.Length;
+ }
+ else
+ {
+ var fileWritten = default(long);
+ using (var br = new BinaryReader(fs))
+ {
+ while (fileWritten < fs.Length)
+ {
+ var buffer = br.ReadBytes(8192);
+ requestStream.Write(buffer, 0, buffer.Length);
+ written += buffer.Length;
+ fileWritten += buffer.Length;
+
+ var args = new PostProgressEventArgs
+ {
+ FileName = parameter.FileName,
+ BytesWritten = fileWritten,
+ TotalBytes = fs.Length
+ };
+ OnPostProgress(args);
+ }
+ }
+ }
+ }
+ written += WriteLine(write, encoding, requestStream, "");
+ break;
+ }
+ case HttpPostParameterType.Field:
+ {
+ var fieldLine = "Content-Disposition: form-data; name=\"{0}\"".FormatWith(parameter.Name);
+
+ written += WriteLine(write, encoding, requestStream, fieldLine);
+ written += WriteLine(write, encoding, requestStream, "");
+ written += WriteLine(write, encoding, requestStream, parameter.Value);
+#if TRACE
+ if(write)
+ {
+ Trace.WriteLineIf(TraceEnabled, fieldLine);
+ Trace.WriteLineIf(TraceEnabled, "");
+ Trace.WriteLineIf(TraceEnabled, parameter.Value);
+ }
+#endif
+ break;
+ }
+ }
+ }
+
+ written += Write(write, encoding, requestStream, footer);
+#if TRACE
+ if(write)
+ {
+ Trace.WriteLineIf(TraceEnabled, footer);
+ }
+#endif
+ if(write)
+ {
+ requestStream.Flush();
+ requestStream.Close();
+ if (fs != null)
+ {
+ fs.Dispose();
+ }
+ }
+
+ return written;
+ }
+
+#if !SILVERLIGHT
+ public virtual void Request(string url, out WebException exception)
+ {
+ switch (Method)
+ {
+ case WebMethod.Get:
+ ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Get, url, out exception);
+ break;
+ case WebMethod.Put:
+ ExecutePostOrPut(PostOrPut.Put, url, out exception);
+ break;
+ case WebMethod.Post:
+ ExecutePostOrPut(PostOrPut.Post, url, out exception);
+ break;
+ case WebMethod.Delete:
+ ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Delete, url, out exception);
+ break;
+ case WebMethod.Head:
+ ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Head, url, out exception);
+ break;
+ case WebMethod.Options:
+ ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Options, url, out exception);
+ break;
+ default:
+ throw new NotSupportedException("Unsupported web method");
+ }
+ }
+
+ public virtual void Request(string url, string key, ICache cache, out WebException exception)
+ {
+ switch (Method)
+ {
+ case WebMethod.Get:
+ ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Get, url, key, cache, out exception);
+ break;
+ case WebMethod.Put:
+ ExecutePostOrPut(PostOrPut.Put, url, key, cache, out exception);
+ break;
+ case WebMethod.Post:
+ ExecutePostOrPut(PostOrPut.Post, url, key, cache, out exception);
+ break;
+ case WebMethod.Delete:
+ ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Delete, url, key, cache, out exception);
+ break;
+ case WebMethod.Head:
+ ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Head, url, key, cache, out exception);
+ break;
+ case WebMethod.Options:
+ ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Options, url, key, cache, out exception);
+ break;
+ default:
+ throw new NotSupportedException("Unsupported web method");
+ }
+ }
+
+ public virtual void Request(string url, string key, ICache cache, DateTime absoluteExpiration, out WebException exception)
+ {
+ switch (Method)
+ {
+ case WebMethod.Get:
+ ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Get, url, key, cache, absoluteExpiration, out exception);
+ break;
+ case WebMethod.Put:
+ ExecutePostOrPut(PostOrPut.Put, url, key, cache, absoluteExpiration, out exception);
+ break;
+ case WebMethod.Post:
+ ExecutePostOrPut(PostOrPut.Post, url, key, cache, absoluteExpiration, out exception);
+ break;
+ case WebMethod.Delete:
+ ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Delete, url, key, cache, absoluteExpiration, out exception);
+ break;
+ case WebMethod.Head:
+ ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Head, url, key, cache, absoluteExpiration, out exception);
+ break;
+ case WebMethod.Options:
+ ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Options, url, key, cache, absoluteExpiration, out exception);
+ break;
+ default:
+ throw new NotSupportedException("Unsupported web method");
+ }
+ }
+
+ public virtual void Request(string url, string key, ICache cache, TimeSpan slidingExpiration, out WebException exception)
+ {
+ switch (Method)
+ {
+ case WebMethod.Get:
+ ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Get, url, key, cache, slidingExpiration, out exception);
+ break;
+ case WebMethod.Put:
+ ExecutePostOrPut(PostOrPut.Put, url, key, cache, slidingExpiration, out exception);
+ break;
+ case WebMethod.Post:
+ ExecutePostOrPut(PostOrPut.Post, url, key, cache, slidingExpiration, out exception);
+ break;
+ case WebMethod.Delete:
+ ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Delete, url, key, cache, slidingExpiration, out exception);
+ break;
+ case WebMethod.Head:
+ ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Head, url, key, cache, slidingExpiration, out exception);
+ break;
+ case WebMethod.Options:
+ ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Options, url, key, cache, slidingExpiration, out exception);
+ break;
+ default:
+ throw new NotSupportedException("Unsupported web method");
+ }
+ }
+
+ public virtual void Request(string url, IEnumerable<HttpPostParameter> parameters, out WebException exception)
+ {
+ switch (Method)
+ {
+ case WebMethod.Put:
+ ExecutePostOrPut(PostOrPut.Put, url, parameters, out exception);
+ break;
+ case WebMethod.Post:
+ ExecutePostOrPut(PostOrPut.Post, url, parameters, out exception);
+ break;
+ default:
+ throw new NotSupportedException("Only HTTP POSTs and PUTs can use multi-part parameters");
+ }
+ }
+#endif
+
+#if !WindowsPhone
+ public virtual WebQueryAsyncResult RequestAsync(string url, object userState)
+ {
+ UserState = userState;
+
+ switch (Method)
+ {
+ case WebMethod.Get:
+ return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Get, url, userState);
+ case WebMethod.Put:
+ return ExecutePostOrPutAsync(PostOrPut.Put, url, userState);
+ case WebMethod.Post:
+ return ExecutePostOrPutAsync(PostOrPut.Post, url, userState);
+ case WebMethod.Delete:
+ return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Delete, url, userState);
+ case WebMethod.Head:
+ return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Head, url, userState);
+ case WebMethod.Options:
+ return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Options, url, userState);
+ default:
+ throw new NotSupportedException("Unknown web method");
+ }
+ }
+#else
+ public virtual void RequestAsync(string url, object userState)
+ {
+ UserState = userState;
+
+ switch (Method)
+ {
+ case WebMethod.Get:
+ ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Get, url, userState);
+ break;
+ case WebMethod.Put:
+ ExecutePostOrPutAsync(PostOrPut.Put, url, userState);
+ break;
+ case WebMethod.Post:
+ ExecutePostOrPutAsync(PostOrPut.Post, url, userState);
+ break;
+ case WebMethod.Delete:
+ ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Delete, url, userState);
+ break;
+ case WebMethod.Head:
+ ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Head, url, userState);
+ break;
+ case WebMethod.Options:
+ ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Options, url, userState);
+ break;
+ default:
+ throw new NotSupportedException("Unknown web method");
+ }
+ }
+#endif
+
+#if !WindowsPhone
+ public virtual WebQueryAsyncResult RequestAsync(string url,
+ string key,
+ ICache cache,
+ object userState)
+ {
+ UserState = userState;
+
+ switch (Method)
+ {
+ case WebMethod.Get:
+ return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Get, url, key, cache, userState);
+ case WebMethod.Put:
+ return ExecutePostOrPutAsync(PostOrPut.Put, url, key, cache, userState);
+ case WebMethod.Post:
+ return ExecutePostOrPutAsync(PostOrPut.Post, url, key, cache, userState);
+ case WebMethod.Delete:
+ return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Delete, url, key, cache, userState);
+ case WebMethod.Head:
+ return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Head, url, key, cache, userState);
+ case WebMethod.Options:
+ return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Options, url, key, cache, userState);
+ default:
+ throw new NotSupportedException(
+ "Unsupported web method: {0}".FormatWith(Method.ToUpper())
+ );
+ }
+ }
+#else
+ public virtual void RequestAsync(string url,
+ string key,
+ ICache cache,
+ object userState)
+ {
+ UserState = userState;
+
+ switch (Method)
+ {
+ case WebMethod.Get:
+ ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Get, url, key, cache, userState);
+ break;
+ case WebMethod.Put:
+ ExecutePostOrPutAsync(PostOrPut.Put, url, key, cache, userState);
+ break;
+ case WebMethod.Post:
+ ExecutePostOrPutAsync(PostOrPut.Post, url, key, cache, userState);
+ break;
+ case WebMethod.Delete:
+ ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Delete, url, key, cache, userState);
+ break;
+ case WebMethod.Head:
+ ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Head, url, key, cache, userState);
+ break;
+ case WebMethod.Options:
+ ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Options, url, key, cache, userState);
+ break;
+ default:
+ throw new NotSupportedException(
+ "Unsupported web method: {0}".FormatWith(Method.ToUpper())
+ );
+ }
+ }
+#endif
+
+#if !WindowsPhone
+ public virtual WebQueryAsyncResult RequestAsync(string url,
+ string key,
+ ICache cache,
+ DateTime absoluteExpiration,
+ object userState)
+ {
+ UserState = userState;
+
+ switch (Method)
+ {
+ case WebMethod.Get:
+ return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Get, url, key, cache, absoluteExpiration, userState);
+ case WebMethod.Put:
+ return ExecutePostOrPutAsync(PostOrPut.Put, url, key, cache, absoluteExpiration, userState);
+ case WebMethod.Post:
+ return ExecutePostOrPutAsync(PostOrPut.Post, url, key, cache, absoluteExpiration, userState);
+ case WebMethod.Delete:
+ return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Delete, url, key, cache, absoluteExpiration, userState);
+ default:
+ throw new NotSupportedException(
+ "Unsupported web method: {0}".FormatWith(Method.ToUpper())
+ );
+ }
+ }
+#else
+ public virtual void RequestAsync(string url,
+ string key,
+ ICache cache,
+ DateTime absoluteExpiration,
+ object userState)
+ {
+ UserState = userState;
+
+ switch (Method)
+ {
+ case WebMethod.Get:
+ ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Get, url, key, cache, absoluteExpiration, userState);
+ break;
+ case WebMethod.Put:
+ ExecutePostOrPutAsync(PostOrPut.Put, url, key, cache, absoluteExpiration, userState);
+ break;
+ case WebMethod.Post:
+ ExecutePostOrPutAsync(PostOrPut.Post, url, key, cache, absoluteExpiration, userState);
+ break;
+ case WebMethod.Delete:
+ ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Delete, url, key, cache, absoluteExpiration, userState);
+ break;
+ case WebMethod.Head:
+ ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Head, url, key, cache, absoluteExpiration, userState);
+ break;
+ case WebMethod.Options:
+ ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Options, url, key, cache, absoluteExpiration, userState);
+ break;
+ default:
+ throw new NotSupportedException(
+ "Unsupported web method: {0}".FormatWith(Method.ToUpper())
+ );
+ }
+ }
+#endif
+
+#if !WindowsPhone
+ public virtual WebQueryAsyncResult RequestAsync(string url,
+ string key,
+ ICache cache,
+ TimeSpan slidingExpiration,
+ object userState)
+ {
+ UserState = userState;
+
+ switch (Method)
+ {
+ case WebMethod.Get:
+ return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Get, url, key, cache, slidingExpiration, userState);
+ case WebMethod.Post:
+ return ExecutePostOrPutAsync(PostOrPut.Post, url, key, cache, slidingExpiration, userState);
+ case WebMethod.Put:
+ return ExecutePostOrPutAsync(PostOrPut.Put, url, key, cache, slidingExpiration, userState);
+ case WebMethod.Delete:
+ return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Delete, url, key, cache, slidingExpiration, userState);
+ case WebMethod.Head:
+ return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Head, url, key, cache, slidingExpiration, userState);
+ case WebMethod.Options:
+ return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Options, url, key, cache, slidingExpiration, userState);
+ default:
+ throw new NotSupportedException(
+ "Unsupported web method: {0}".FormatWith(Method.ToUpper())
+ );
+ }
+ }
+#else
+ public virtual void RequestAsync(string url,
+ string key,
+ ICache cache,
+ TimeSpan slidingExpiration,
+ object userState)
+ {
+ UserState = userState;
+
+ switch (Method)
+ {
+ case WebMethod.Get:
+ ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Get, url, key, cache, slidingExpiration, userState);
+ break;
+ case WebMethod.Post:
+ ExecutePostOrPutAsync(PostOrPut.Post, url, key, cache, slidingExpiration, userState);
+ break;
+ case WebMethod.Put:
+ ExecutePostOrPutAsync(PostOrPut.Put, url, key, cache, slidingExpiration, userState);
+ break;
+ case WebMethod.Delete:
+ ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Delete, url, key, cache, slidingExpiration, userState);
+ break;
+ case WebMethod.Head:
+ ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Head, url, key, cache, slidingExpiration, userState);
+ break;
+ case WebMethod.Options:
+ ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Options, url, key, cache, slidingExpiration, userState);
+ break;
+ default:
+ throw new NotSupportedException(
+ "Unsupported web method: {0}".FormatWith(Method.ToUpper())
+ );
+ }
+ }
+#endif
+
+#if !WindowsPhone
+ public virtual WebQueryAsyncResult RequestAsync(string url,
+ IEnumerable<HttpPostParameter> parameters,
+ object userState)
+ {
+ UserState = userState;
+
+ switch (Method)
+ {
+ case WebMethod.Put:
+ return ExecutePostOrPutAsync(PostOrPut.Put, url, parameters, userState);
+ case WebMethod.Post:
+ return ExecutePostOrPutAsync(PostOrPut.Post, url, parameters, userState);
+ default:
+ throw new NotSupportedException("Only HTTP POSTS can use multi-part forms");
+ }
+ }
+#else
+ public virtual void RequestAsync(string url,
+ IEnumerable<HttpPostParameter> parameters,
+ object userState)
+ {
+ UserState = userState;
+
+ switch (Method)
+ {
+ case WebMethod.Put:
+ ExecutePostOrPutAsync(PostOrPut.Put, url, parameters, userState);
+ break;
+ case WebMethod.Post:
+ ExecutePostOrPutAsync(PostOrPut.Post, url, parameters, userState);
+ break;
+ default:
+ throw new NotSupportedException("Only HTTP POSTS can use multi-part forms");
+ }
+ }
+#endif
+
+#if !SILVERLIGHT
+ public virtual void ExecutePostOrPut(PostOrPut method,
+ string url,
+ string key,
+ ICache cache,
+ out WebException exception)
+ {
+ WebException ex = null;
+ ExecuteWithCache(cache, url, key, (c, u) => ExecutePostOrPut(method, cache, url, key, out ex));
+ exception = ex;
+ }
+
+ public virtual void ExecutePostOrPut(PostOrPut method, string url, string key, ICache cache, DateTime absoluteExpiration, out WebException exception)
+ {
+ WebException ex = null;
+ ExecuteWithCacheAndAbsoluteExpiration(cache, url, key, absoluteExpiration,
+ (c, u, e) =>
+ ExecutePostOrPut(method, cache, url, key, absoluteExpiration, out ex));
+ exception = ex;
+ }
+
+ public virtual void ExecutePostOrPut(PostOrPut method, string url, string key, ICache cache, TimeSpan slidingExpiration, out WebException exception)
+ {
+ WebException ex = null;
+ ExecuteWithCacheAndSlidingExpiration(cache, url, key, slidingExpiration,
+ (c, u, e) =>
+ ExecutePostOrPut(method, cache, url, key, slidingExpiration, out ex));
+ exception = ex;
+ }
+
+ private void ExecutePostOrPut(PostOrPut method,
+ ICache cache,
+ string url,
+ string key,
+ out WebException exception)
+ {
+ ExecutePostOrPut(method, url, out exception);
+ if (exception == null)
+ {
+ cache.Insert(CreateCacheKey(key, url), ContentStream);
+ }
+ }
+
+ private void ExecutePostOrPut(PostOrPut method,
+ ICache cache,
+ string url,
+ string key,
+ DateTime absoluteExpiration,
+ out WebException exception)
+ {
+ ExecutePostOrPut(method, url, out exception);
+ if (exception == null)
+ {
+ cache.Insert(CreateCacheKey(key, url), ContentStream, absoluteExpiration);
+ }
+ }
+
+ private void ExecutePostOrPut(PostOrPut method, ICache cache, string url, string key,
+ TimeSpan slidingExpiration, out WebException exception)
+ {
+ ExecutePostOrPut(method, url, out exception);
+ if (exception == null)
+ {
+ cache.Insert(CreateCacheKey(key, url), ContentStream, slidingExpiration);
+ }
+ }
+#endif
+
+ public void Dispose()
+ {
+ if(ContentStream != null)
+ {
+ ContentStream.Dispose();
+ }
+ }
+ }
+
+ internal class PostProgressEventArgs : EventArgs
+ {
+ public virtual string FileName { get; set; }
+ public virtual long BytesWritten { get; set; }
+ public virtual long TotalBytes { get; set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Threading;
+
+namespace Hammock.Web
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class WebQueryAsyncResult : IAsyncResult, IDisposable
+ {
+ public virtual bool IsCompleted { get; protected internal set; }
+ public virtual WaitHandle AsyncWaitHandle { get; protected internal set; }
+ public virtual object AsyncState { get; protected internal set; }
+ public virtual bool CompletedSynchronously { get; protected internal set; }
+
+ public virtual IAsyncResult InnerResult { get; set; }
+ public virtual object Tag { get; set; }
+
+#if !SILVERLIGHT
+ [NonSerialized]
+#endif
+ private AutoResetEvent _block;
+
+ public WebQueryAsyncResult()
+ {
+ Initialize();
+ }
+
+ private void Initialize()
+ {
+ _block = new AutoResetEvent(false);
+ AsyncWaitHandle = _block;
+ }
+
+ protected internal void Signal()
+ {
+ _block.Set();
+ }
+
+ public void Dispose()
+ {
+
+ }
+ }
+}
--- /dev/null
+using System;
+
+namespace Hammock.Web
+{
+ public class WebQueryRequestEventArgs : EventArgs
+ {
+ public WebQueryRequestEventArgs(string request)
+ {
+ Request = request;
+ }
+
+ public string Request { get; private set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.IO;
+using System.Net;
+
+namespace Hammock.Web
+{
+ public class WebQueryResponseEventArgs : EventArgs
+ {
+ public WebQueryResponseEventArgs(Stream response)
+ {
+ Response = response;
+ }
+
+ public WebQueryResponseEventArgs(Stream response, Exception exception)
+ {
+ Response = response;
+ Exception = exception;
+ }
+
+ public Stream Response { get; set; }
+ public Exception Exception { get; set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.IO;
+using System.Net;
+
+namespace Hammock.Web
+{
+#if !SILVERLIGHT
+ [Serializable]
+#endif
+ public class WebQueryResult
+ {
+ public virtual Stream ContentStream { get; set; }
+
+ // Set by WebQuery
+ public virtual DateTime? RequestDate { get; set; }
+ public virtual Uri RequestUri { get; set; }
+ public virtual string RequestHttpMethod { get; set; }
+ public virtual bool RequestKeptAlive { get; set; }
+
+ public virtual DateTime? ResponseDate { get; set; }
+ public virtual WebResponse WebResponse { get; set; }
+ public virtual string ResponseType { get; set; }
+ public virtual int ResponseHttpStatusCode { get; set; }
+ public virtual string ResponseHttpStatusDescription { get; set; }
+ public virtual long ResponseLength { get; set; }
+ public virtual Uri ResponseUri { get; set; }
+ public virtual bool IsMock { get; set; }
+ public virtual bool TimedOut { get; set; }
+
+ // Set by RestClient
+ public virtual int TimesTried { get; set; }
+ public virtual Exception Exception { get; set; }
+ public virtual bool WasRateLimited { get; set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<ClassDiagram MajorVersion="1" MinorVersion="1">
+ <Class Name="Hammock.RestClient">
+ <Position X="6" Y="7.5" Width="3" />
+ <Members>
+ <Field Name="_firstTry" Hidden="true" />
+ <Field Name="_remainingRetries" Hidden="true" />
+ <Field Name="_task" Hidden="true" />
+ <Method Name="BeginRequestFunction" Hidden="true" />
+ <Method Name="BeginRequestMultiPart" Hidden="true" />
+ <Method Name="BeginRequestWithCache" Hidden="true" />
+ <Method Name="BeginRequestWithTask" Hidden="true" />
+ <Method Name="BuildBaseResponse" Hidden="true" />
+ <Method Name="BuildMockRequestUrl" Hidden="true" />
+ <Method Name="BuildRateLimitingTask" Hidden="true" />
+ <Method Name="BuildRateLimitingTaskImpl" Hidden="true" />
+ <Method Name="BuildResponseFromResult" Hidden="true" />
+ <Method Name="CompleteWithMockWebResponse" Hidden="true" />
+ <Method Name="CompleteWithQuery" Hidden="true" />
+ <Method Name="DeserializeEntityBody" Hidden="true" />
+ <Method Name="EndRequestImpl" Hidden="true" />
+ <Method Name="GetCache" Hidden="true" />
+ <Method Name="GetCacheKeyFunction" Hidden="true" />
+ <Method Name="GetCacheOptions" Hidden="true" />
+ <Method Name="GetInfo" Hidden="true" />
+ <Method Name="GetPostParameters" Hidden="true" />
+ <Method Name="GetProxy" Hidden="true" />
+ <Method Name="GetQueryFor" Hidden="true" />
+ <Method Name="GetRetryPolicy" Hidden="true" />
+ <Method Name="GetSerializer" Hidden="true" />
+ <Method Name="GetTaskOptions" Hidden="true" />
+ <Method Name="GetTimeout" Hidden="true" />
+ <Method Name="GetUserAgent" Hidden="true" />
+ <Method Name="GetWebCredentials" Hidden="true" />
+ <Method Name="GetWebMethod" Hidden="true" />
+ <Method Name="RequestExpectsMock" Hidden="true" />
+ <Method Name="RequestImpl" Hidden="true" />
+ <Method Name="RequestMultiPart" Hidden="true" />
+ <Method Name="RequestWithCache" Hidden="true" />
+ <Method Name="SerializeEntityBody" Hidden="true" />
+ <Method Name="SerializeExpectEntity" Hidden="true" />
+ <Method Name="SetQueryMeta" Hidden="true" />
+ </Members>
+ <TypeIdentifier>
+ <HashCode>IIkAKAAAAAgQJASKAQAgJJAgEDEhgkAMEIAAAhABEAA=</HashCode>
+ <FileName>RestClient.cs</FileName>
+ </TypeIdentifier>
+ <Lollipop Position="0.2" />
+ </Class>
+ <Class Name="Hammock.RestRequest">
+ <Position X="2.75" Y="7.5" Width="2.5" />
+ <Members>
+ <Field Name="_entity" Hidden="true" />
+ </Members>
+ <TypeIdentifier>
+ <HashCode>EABAgAAQAAAABQEAAAAAAAgAAAAoAAAAAJAAEAAAAAA=</HashCode>
+ <FileName>RestRequest.cs</FileName>
+ </TypeIdentifier>
+ </Class>
+ <Class Name="Hammock.RestResponse">
+ <Position X="8.5" Y="3.5" Width="1.75" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+ <FileName>RestResponse.cs</FileName>
+ </TypeIdentifier>
+ </Class>
+ <Class Name="Hammock.RestResponseBase">
+ <Position X="8.5" Y="0.5" Width="1.75" />
+ <TypeIdentifier>
+ <HashCode>AAAAAgAAAgQAAAAAAAAAAAAIAAAAABAAIAAQAAAAAAA=</HashCode>
+ <FileName>RestResponse.cs</FileName>
+ </TypeIdentifier>
+ </Class>
+ <Class Name="Hammock.RestBase">
+ <Position X="5.25" Y="0.5" Width="2" />
+ <TypeIdentifier>
+ <HashCode>AgAAABAkCAASASIAIAAgAAACCAFEAAIAAIgAAECACQA=</HashCode>
+ <FileName>RestBase.cs</FileName>
+ </TypeIdentifier>
+ </Class>
+ <Interface Name="Hammock.IRestClient">
+ <Position X="1.75" Y="0.5" Width="2.5" />
+ <TypeIdentifier>
+ <HashCode>AAAAAAAAAAAABAAAAAAAAAAAAAAAgAAAAAAAAAAAAAA=</HashCode>
+ <FileName>IRestClient.cs</FileName>
+ </TypeIdentifier>
+ </Interface>
+ <Font Name="Segoe UI" Size="9" />
+</ClassDiagram>
\ No newline at end of file
--- /dev/null
+using System;
+using System.IO;
+using ICSharpCode.SharpZipLib.Silverlight.BZip2;
+using NUnit.Framework;
+
+namespace ICSharpCode.SharpZipLib.Tests.BZip2
+{
+ /// <summary>
+ /// This class contains test cases for Bzip2 compression
+ /// </summary>
+ [TestFixture]
+ public class BZip2Suite
+ {
+ /// <summary>
+ /// Basic compress/decompress test BZip2
+ /// </summary>
+ [Test]
+ [Category("BZip2")]
+ public void BasicRoundTrip()
+ {
+ MemoryStream ms = new MemoryStream();
+ BZip2OutputStream outStream = new BZip2OutputStream(ms);
+
+ byte[] buf = new byte[10000];
+ System.Random rnd = new Random();
+ rnd.NextBytes(buf);
+
+ outStream.Write(buf, 0, buf.Length);
+ outStream.Close();
+ ms = new MemoryStream(ms.GetBuffer());
+ ms.Seek(0, SeekOrigin.Begin);
+
+ using (BZip2InputStream inStream = new BZip2InputStream(ms))
+ {
+ byte[] buf2 = new byte[buf.Length];
+ int pos = 0;
+ while (true)
+ {
+ int numRead = inStream.Read(buf2, pos, 4096);
+ if (numRead <= 0)
+ {
+ break;
+ }
+ pos += numRead;
+ }
+
+ for (int i = 0; i < buf.Length; ++i)
+ {
+ Assert.AreEqual(buf2[i], buf[i]);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Check that creating an empty archive is handled ok
+ /// </summary>
+ [Test]
+ [Category("BZip2")]
+ public void CreateEmptyArchive()
+ {
+ MemoryStream ms = new MemoryStream();
+ BZip2OutputStream outStream = new BZip2OutputStream(ms);
+ outStream.Close();
+ ms = new MemoryStream(ms.GetBuffer());
+
+ ms.Seek(0, SeekOrigin.Begin);
+
+ using (BZip2InputStream inStream = new BZip2InputStream(ms))
+ {
+ byte[] buffer = new byte[1024];
+ int pos = 0;
+ while (true)
+ {
+ int numRead = inStream.Read(buffer, 0, buffer.Length);
+ if (numRead <= 0)
+ {
+ break;
+ }
+ pos += numRead;
+ }
+
+ Assert.AreEqual(pos, 0);
+ }
+ }
+ }
+}
--- /dev/null
+using System;
+using System.IO;
+using System.Text;
+using System.Security;
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression;
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression.Streams;
+using NUnit.Framework;
+
+using ICSharpCode.SharpZipLib.Tests.TestSupport;
+
+namespace ICSharpCode.SharpZipLib.Tests.Base
+{
+ /// <summary>
+ /// This class contains test cases for Deflater/Inflater streams.
+ /// </summary>
+ [TestFixture]
+ public class InflaterDeflaterTestSuite
+ {
+ void Inflate(MemoryStream ms, byte[] original, int level, bool zlib)
+ {
+ ms.Seek(0, SeekOrigin.Begin);
+
+ Inflater inflater = new Inflater(!zlib);
+ InflaterInputStream inStream = new InflaterInputStream(ms, inflater);
+ byte[] buf2 = new byte[original.Length];
+
+ int currentIndex = 0;
+ int count = buf2.Length;
+
+ try
+ {
+ while (true)
+ {
+ int numRead = inStream.Read(buf2, currentIndex, count);
+ if (numRead <= 0)
+ {
+ break;
+ }
+ currentIndex += numRead;
+ count -= numRead;
+ }
+ }
+ catch(Exception ex)
+ {
+ Console.WriteLine("Unexpected exception - '{0}'", ex.Message);
+ throw;
+ }
+
+ if ( currentIndex != original.Length )
+ {
+ Console.WriteLine("Original {0}, new {1}", original.Length, currentIndex);
+ Assert.Fail("Lengths different");
+ }
+
+ for (int i = 0; i < original.Length; ++i)
+ {
+ if ( buf2[i] != original[i] )
+ {
+ string description = string.Format("Difference at {0} level {1} zlib {2} ", i, level, zlib);
+ if ( original.Length < 2048 )
+ {
+ StringBuilder builder = new StringBuilder(description);
+ for (int d = 0; d < original.Length; ++d)
+ {
+ builder.AppendFormat("{0} ", original[d]);
+ }
+
+ Assert.Fail(builder.ToString());
+ }
+ else
+ {
+ Assert.Fail(description);
+ }
+ }
+ }
+ }
+
+ MemoryStream Deflate(byte[] data, int level, bool zlib)
+ {
+ MemoryStream memoryStream = new MemoryStream();
+
+ Deflater deflater = new Deflater(level, !zlib);
+ using ( DeflaterOutputStream outStream = new DeflaterOutputStream(memoryStream, deflater) )
+ {
+ outStream.IsStreamOwner = false;
+ outStream.Write(data, 0, data.Length);
+ outStream.Flush();
+ outStream.Finish();
+ }
+ return memoryStream;
+ }
+
+ void RandomDeflateInflate(int size, int level, bool zlib)
+ {
+ byte[] buffer = new byte[size];
+ System.Random rnd = new Random();
+ rnd.NextBytes(buffer);
+
+ MemoryStream ms = Deflate(buffer, level, zlib);
+ Inflate(ms, buffer, level, zlib);
+ }
+
+ /// <summary>
+ /// Basic inflate/deflate test
+ /// </summary>
+ [Test]
+ [Category("Base")]
+ public void InflateDeflateZlib()
+ {
+ for (int level = 0; level < 10; ++level)
+ {
+ RandomDeflateInflate(100000, level, true);
+ }
+ }
+
+ delegate void RunCompress(byte[] buffer);
+
+ int runLevel;
+ bool runZlib;
+ long runCount = 0;
+ Random runRandom = new Random(5);
+
+ void DeflateAndInflate(byte[] buffer)
+ {
+ ++runCount;
+ MemoryStream ms = Deflate(buffer, runLevel, runZlib);
+ Inflate(ms, buffer, runLevel, runZlib);
+ }
+
+ void TryVariants(RunCompress test, byte[] buffer, int index)
+ {
+ int worker = 0;
+ while ( worker <= 255 )
+ {
+ buffer[index] = (byte)worker;
+ if ( index < buffer.Length - 1)
+ {
+ TryVariants(test, buffer, index + 1);
+ }
+ else
+ {
+ test(buffer);
+ }
+
+ worker += runRandom.Next(256);
+ }
+ }
+
+ void TryManyVariants(int level, bool zlib, RunCompress test, byte[] buffer)
+ {
+ runLevel = level;
+ runZlib = zlib;
+ TryVariants(test, buffer, 0);
+ }
+
+
+ [Test]
+ [Category("Base")]
+ public void SmallBlocks()
+ {
+ byte[] buffer = new byte[10];
+ Array.Clear(buffer, 0, buffer.Length);
+ TryManyVariants(0, false, new RunCompress(DeflateAndInflate), buffer);
+ }
+
+ [Test]
+ [Explicit]
+ [Category("Base")]
+ [Category("ExcludeFromAutoBuild")]
+ public void FindBug()
+ {
+ using ( FileStream fs = File.OpenRead("c:\\tmp\\original.dat") )
+ {
+ long readOffset = 0;
+ long readLength = fs.Length - readOffset;
+// readLength -= 5567; // 5568 works 5567 doesnt....
+
+ fs.Seek(readOffset, SeekOrigin.Begin);
+
+ byte[] original = new byte[readLength];
+
+ int bytesRead = fs.Read(original, 0, original.Length);
+ Assert.AreEqual(bytesRead, original.Length);
+
+ MemoryStream ms = Deflate(original, Deflater.BEST_SPEED, true);
+ Inflate(ms, original, Deflater.BEST_SPEED, true);
+ }
+ }
+
+ /// <summary>
+ /// Basic inflate/deflate test
+ /// </summary>
+ [Test]
+ [Category("Base")]
+ public void InflateDeflateNonZlib()
+ {
+ for (int level = 0; level < 10; ++level)
+ {
+ RandomDeflateInflate(100000, level, false);
+ }
+ }
+
+ [Test]
+ [Category("Base")]
+ public void CloseDeflatorWithNestedUsing()
+ {
+ string tempFile = null;
+ try
+ {
+ tempFile = Path.GetTempPath();
+ }
+ catch (SecurityException)
+ {
+ }
+
+ Assert.IsNotNull(tempFile, "No permission to execute this test?");
+ if (tempFile != null)
+ {
+ tempFile = Path.Combine(tempFile, "SharpZipTest.Zip");
+ using (FileStream diskFile = File.Create(tempFile))
+ using (DeflaterOutputStream deflator = new DeflaterOutputStream(diskFile))
+ using (StreamWriter txtFile = new StreamWriter(deflator))
+ {
+ txtFile.Write("Hello");
+ txtFile.Flush();
+ }
+
+ File.Delete(tempFile);
+ }
+ }
+
+ [Test]
+ [Category("Base")]
+ public void DeflatorStreamOwnership()
+ {
+ MemoryStreamEx memStream = new MemoryStreamEx();
+ DeflaterOutputStream s = new DeflaterOutputStream(memStream);
+
+ Assert.IsFalse(memStream.IsClosed, "Shouldnt be closed initially");
+ Assert.IsFalse(memStream.IsDisposed, "Shouldnt be disposed initially");
+
+ s.Close();
+
+ Assert.IsTrue(memStream.IsClosed, "Should be closed after parent owner close");
+ Assert.IsTrue(memStream.IsDisposed, "Should be disposed after parent owner close");
+
+ memStream = new MemoryStreamEx();
+ s = new DeflaterOutputStream(memStream);
+
+ Assert.IsFalse(memStream.IsClosed, "Shouldnt be closed initially");
+ Assert.IsFalse(memStream.IsDisposed, "Shouldnt be disposed initially");
+
+ s.IsStreamOwner = false;
+ s.Close();
+
+ Assert.IsFalse(memStream.IsClosed, "Should not be closed after parent owner close");
+ Assert.IsFalse(memStream.IsDisposed, "Should not be disposed after parent owner close");
+
+ }
+
+ [Test]
+ [Category("Base")]
+ public void InflatorStreamOwnership()
+ {
+ MemoryStreamEx memStream = new MemoryStreamEx();
+ InflaterInputStream s = new InflaterInputStream(memStream);
+
+ Assert.IsFalse(memStream.IsClosed, "Shouldnt be closed initially");
+ Assert.IsFalse(memStream.IsDisposed, "Shouldnt be disposed initially");
+
+ s.Close();
+
+ Assert.IsTrue(memStream.IsClosed, "Should be closed after parent owner close");
+ Assert.IsTrue(memStream.IsDisposed, "Should be disposed after parent owner close");
+
+ memStream = new MemoryStreamEx();
+ s = new InflaterInputStream(memStream);
+
+ Assert.IsFalse(memStream.IsClosed, "Shouldnt be closed initially");
+ Assert.IsFalse(memStream.IsDisposed, "Shouldnt be disposed initially");
+
+ s.IsStreamOwner = false;
+ s.Close();
+
+ Assert.IsFalse(memStream.IsClosed, "Should not be closed after parent owner close");
+ Assert.IsFalse(memStream.IsDisposed, "Should not be disposed after parent owner close");
+
+ }
+
+ [Test]
+ [Category("Base")]
+ public void CloseInflatorWithNestedUsing()
+ {
+ string tempFile = null;
+ try
+ {
+ tempFile = Path.GetTempPath();
+ }
+ catch (SecurityException)
+ {
+ }
+
+ Assert.IsNotNull(tempFile, "No permission to execute this test?");
+
+ if (tempFile != null)
+ {
+ tempFile = Path.Combine(tempFile, "SharpZipTest.Zip");
+ using (FileStream diskFile = File.Create(tempFile))
+ using (DeflaterOutputStream deflator = new DeflaterOutputStream(diskFile))
+ using (StreamWriter textWriter = new StreamWriter(deflator))
+ {
+ textWriter.Write("Hello");
+ textWriter.Flush();
+ }
+
+ using (FileStream diskFile = File.OpenRead(tempFile))
+ using (InflaterInputStream deflator = new InflaterInputStream(diskFile))
+ using (StreamReader textReader = new StreamReader(deflator))
+ {
+ char[] buffer = new char[5];
+ int readCount = textReader.Read(buffer, 0, 5);
+ Assert.AreEqual(5, readCount);
+
+ StringBuilder b = new StringBuilder();
+ b.Append(buffer);
+ Assert.AreEqual("Hello", b.ToString());
+
+ }
+
+ File.Delete(tempFile);
+ }
+ }
+ }
+}
--- /dev/null
+using System;
+using System.IO;
+using System.Threading;
+using ICSharpCode.SharpZipLib.Silverlight.GZip;
+using NUnit.Framework;
+
+using ICSharpCode.SharpZipLib.Tests.TestSupport;
+
+namespace ICSharpCode.SharpZipLib.Tests.GZip
+{
+ /// <summary>
+ /// This class contains test cases for GZip compression
+ /// </summary>
+ [TestFixture]
+ public class GZipTestSuite
+ {
+ /// <summary>
+ /// Basic compress/decompress test
+ /// </summary>
+ [Test]
+ [Category("GZip")]
+ public void TestGZip()
+ {
+ MemoryStream ms = new MemoryStream();
+ GZipOutputStream outStream = new GZipOutputStream(ms);
+
+ byte[] buf = new byte[100000];
+ System.Random rnd = new Random();
+ rnd.NextBytes(buf);
+
+ outStream.Write(buf, 0, buf.Length);
+ outStream.Flush();
+ outStream.Finish();
+
+ ms.Seek(0, SeekOrigin.Begin);
+
+ GZipInputStream inStream = new GZipInputStream(ms);
+ byte[] buf2 = new byte[buf.Length];
+ int currentIndex = 0;
+ int count = buf2.Length;
+
+ while (true) {
+ int numRead = inStream.Read(buf2, currentIndex, count);
+ if (numRead <= 0) {
+ break;
+ }
+ currentIndex += numRead;
+ count -= numRead;
+ }
+
+ Assert.AreEqual(0, count);
+
+ for (int i = 0; i < buf.Length; ++i) {
+ Assert.AreEqual(buf2[i], buf[i]);
+ }
+ }
+
+ /// <summary>
+ /// Writing GZip headers is delayed so that this stream can be used with HTTP/IIS.
+ /// </summary>
+ [Test]
+ [Category("GZip")]
+ public void DelayedHeaderWriteNoData()
+ {
+ MemoryStream ms = new MemoryStream();
+ Assert.AreEqual(0, ms.Length);
+
+ using (GZipOutputStream outStream = new GZipOutputStream(ms)) {
+ Assert.AreEqual(0, ms.Length);
+ }
+
+ byte[] data = ms.ToArray();
+
+ Assert.IsTrue(data.Length > 0);
+ }
+
+ /// <summary>
+ /// Writing GZip headers is delayed so that this stream can be used with HTTP/IIS.
+ /// </summary>
+ [Test]
+ [Category("GZip")]
+ public void DelayedHeaderWriteWithData()
+ {
+ MemoryStream ms = new MemoryStream();
+ Assert.AreEqual(0, ms.Length);
+ using (GZipOutputStream outStream = new GZipOutputStream(ms)) {
+ Assert.AreEqual(0, ms.Length);
+ outStream.WriteByte(45);
+
+ // Should in fact contain header right now with
+ // 1 byte in the compression pipeline
+ Assert.AreEqual(10, ms.Length);
+ }
+ byte[] data = ms.ToArray();
+
+ Assert.IsTrue(data.Length > 0);
+ }
+
+ [Test]
+ [Category("GZip")]
+ public void ZeroLengthInputStream()
+ {
+ GZipInputStream gzi = new GZipInputStream(new MemoryStream());
+ bool exception = false;
+ try {
+ gzi.ReadByte();
+ }
+ catch {
+ exception = true;
+ }
+
+ Assert.IsTrue(exception, "reading from an empty stream should cause an exception");
+ }
+
+ [Test]
+ [Category("GZip")]
+ public void OutputStreamOwnership()
+ {
+ MemoryStreamEx memStream = new MemoryStreamEx();
+ GZipOutputStream s = new GZipOutputStream(memStream);
+
+ Assert.IsFalse(memStream.IsClosed, "Shouldnt be closed initially");
+ Assert.IsFalse(memStream.IsDisposed, "Shouldnt be disposed initially");
+
+ s.Close();
+
+ Assert.IsTrue(memStream.IsClosed, "Should be closed after parent owner close");
+ Assert.IsTrue(memStream.IsDisposed, "Should be disposed after parent owner close");
+
+ memStream = new MemoryStreamEx();
+ s = new GZipOutputStream(memStream);
+
+ Assert.IsFalse(memStream.IsClosed, "Shouldnt be closed initially");
+ Assert.IsFalse(memStream.IsDisposed, "Shouldnt be disposed initially");
+
+ s.IsStreamOwner = false;
+ s.Close();
+
+ Assert.IsFalse(memStream.IsClosed, "Should not be closed after parent owner close");
+ Assert.IsFalse(memStream.IsDisposed, "Should not be disposed after parent owner close");
+ }
+
+ [Test]
+ [Category("GZip")]
+ public void InputStreamOwnership()
+ {
+ MemoryStreamEx memStream = new MemoryStreamEx();
+ GZipInputStream s = new GZipInputStream(memStream);
+
+ Assert.IsFalse(memStream.IsClosed, "Shouldnt be closed initially");
+ Assert.IsFalse(memStream.IsDisposed, "Shouldnt be disposed initially");
+
+ s.Close();
+
+ Assert.IsTrue(memStream.IsClosed, "Should be closed after parent owner close");
+ Assert.IsTrue(memStream.IsDisposed, "Should be disposed after parent owner close");
+
+ memStream = new MemoryStreamEx();
+ s = new GZipInputStream(memStream);
+
+ Assert.IsFalse(memStream.IsClosed, "Shouldnt be closed initially");
+ Assert.IsFalse(memStream.IsDisposed, "Shouldnt be disposed initially");
+
+ s.IsStreamOwner = false;
+ s.Close();
+
+ Assert.IsFalse(memStream.IsClosed, "Should not be closed after parent owner close");
+ Assert.IsFalse(memStream.IsDisposed, "Should not be disposed after parent owner close");
+
+ }
+
+ [Test]
+ [Category("GZip")]
+ [Category("Long Running")]
+ public void BigStream()
+ {
+ window_ = new WindowedStream(0x3ffff);
+ outStream_ = new GZipOutputStream(window_);
+ inStream_ = new GZipInputStream(window_);
+
+ long target = 0x10000000;
+ readTarget_ = writeTarget_ = target;
+
+ Thread reader = new Thread(Reader);
+ reader.Name = "Reader";
+ reader.Start();
+
+ Thread writer = new Thread(Writer);
+ writer.Name = "Writer";
+
+ DateTime startTime = DateTime.Now;
+ writer.Start();
+
+ writer.Join();
+ reader.Join();
+
+ DateTime endTime = DateTime.Now;
+
+ TimeSpan span = endTime - startTime;
+ Console.WriteLine("Time {0} processes {1} KB/Sec", span, (target / 1024) / span.TotalSeconds);
+ }
+
+ void Reader()
+ {
+ const int Size = 8192;
+ int readBytes = 1;
+ byte[] buffer = new byte[Size];
+
+ long passifierLevel = readTarget_ - 0x10000000;
+
+ while ( (readTarget_ > 0) && (readBytes > 0) ) {
+ int count = Size;
+ if (count > readTarget_) {
+ count = (int)readTarget_;
+ }
+
+ readBytes = inStream_.Read(buffer, 0, count);
+ readTarget_ -= readBytes;
+
+ if (readTarget_ <= passifierLevel) {
+ Console.WriteLine("Reader {0} bytes remaining", readTarget_);
+ passifierLevel = readTarget_ - 0x10000000;
+ }
+ }
+
+ Assert.IsTrue(window_.IsClosed, "Window should be closed");
+
+ // This shouldnt read any data but should read the footer
+ readBytes = inStream_.Read(buffer, 0, 1);
+ Assert.AreEqual(0, readBytes, "Stream should be empty");
+ Assert.AreEqual(0, window_.Length, "Window should be closed");
+ inStream_.Close();
+ }
+
+ void Writer()
+ {
+ const int Size = 8192;
+
+ byte[] buffer = new byte[Size];
+
+ while (writeTarget_ > 0) {
+ int thisTime = Size;
+ if (thisTime > writeTarget_) {
+ thisTime = (int)writeTarget_;
+ }
+
+ outStream_.Write(buffer, 0, thisTime);
+ writeTarget_-= thisTime;
+ }
+ outStream_.Close();
+ }
+
+ WindowedStream window_;
+ GZipOutputStream outStream_;
+ GZipInputStream inStream_;
+ long readTarget_;
+ long writeTarget_;
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Condition="'$(MSBuildToolsVersion)' == '3.5'">
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ </PropertyGroup>
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{3808F0EB-14CF-4919-87F3-97FB9D225A80}</ProjectGuid>
+ <ProjectTypeGuids>{A1591282-1198-4647-A2B1-27E5FF5F6F3B};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>SharpZipLibTests.Silverlight</RootNamespace>
+ <AssemblyName>SharpZipLibTests.Silverlight</AssemblyName>
+ <TargetFrameworkVersion>v3.0</TargetFrameworkVersion>
+ <SilverlightApplication>false</SilverlightApplication>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>3.5</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ <IsWebBootstrapper>false</IsWebBootstrapper>
+ <SignAssembly>true</SignAssembly>
+ <AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
+ <TargetFrameworkIdentifier>Silverlight</TargetFrameworkIdentifier>
+ <SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion>
+ <PublishUrl>publish\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Disk</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>ClientBin\</OutputPath>
+ <DefineConstants>DEBUG;TRACE;SILVERLIGHT</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>ClientBin\</OutputPath>
+ <DefineConstants>TRACE;SILVERLIGHT</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System.Runtime.Serialization" />
+ <Reference Include="System.ServiceModel" />
+ <Reference Include="System.ServiceModel.Web" />
+ <Reference Include="System.Windows">
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="mscorlib" />
+ <Reference Include="system">
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="System.Core">
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="System.Xml">
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="System.Windows.Browser">
+ <Private>True</Private>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Base\InflaterDeflaterTests.cs" />
+ <Compile Include="BZip2\Bzip2Tests.cs" />
+ <Compile Include="GZip\GZipTests.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Tar\TarTests.cs" />
+ <Compile Include="TestSupport\RingBuffer.cs" />
+ <Compile Include="TestSupport\Streams.cs" />
+ <Compile Include="Zip\ZipTests.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 2.0 %28x86%29</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.0 %28x86%29</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+ <Visible>False</Visible>
+ <ProductName>Windows Installer 3.1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\ICSharpCode.SharpZipLib.Silverlight\ICSharpCode.SharpZipLib.Silverlight.csproj">
+ <Project>{2E420750-6124-473B-808D-41755C907648}</Project>
+ <Name>ICSharpCode.SharpZipLib.Silverlight %28.NET 3.5\SharpZipLib\ICSharpCode.SharpZipLib.Silverlight%29</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="key.snk" />
+ <None Include="packages.config" />
+ </ItemGroup>
+ <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\$(SilverlightVersion)\Microsoft.Silverlight.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+ <ProjectExtensions>
+ <VisualStudio>
+ <FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
+ <SilverlightProjectProperties />
+ </FlavorProperties>
+ </VisualStudio>
+ </ProjectExtensions>
+</Project>
\ No newline at end of file
--- /dev/null
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 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("SharpZipLibTests.Silverlight")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("SharpZipLibTests.Silverlight")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("5aa62b43-d301-483f-ae12-acf0612bedae")]
+
+// 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.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null
+using System;
+using System.IO;
+using System.Text;
+using ICSharpCode.SharpZipLib.Silverlight.Tar;
+using NUnit.Framework;
+
+namespace ICSharpCode.SharpZipLib.Tests.Tar {
+
+ /// <summary>
+ /// This class contains test cases for Tar archive handling
+ /// </summary>
+ [TestFixture]
+ public class TarTestSuite
+ {
+ int entryCount;
+
+ void EntryCounter(TarArchive archive, TarEntry entry, string message)
+ {
+ entryCount++;
+ }
+
+ /// <summary>
+ /// Test that an empty archive can be created and when read has 0 entries in it
+ /// </summary>
+ [Test]
+ [Category("Tar")]
+ public void EmptyTar()
+ {
+ MemoryStream ms = new MemoryStream();
+ int recordSize = 0;
+ using ( TarArchive tarOut = TarArchive.CreateOutputTarArchive(ms) )
+ {
+ recordSize = tarOut.RecordSize;
+ }
+
+ Assert.IsTrue(ms.GetBuffer().Length > 0, "Archive size must be > zero");
+ Assert.AreEqual(ms.GetBuffer().Length % recordSize, 0, "Archive size must be a multiple of record size");
+
+ MemoryStream ms2 = new MemoryStream();
+ ms2.Write(ms.GetBuffer(), 0, ms.GetBuffer().Length);
+ ms2.Seek(0, SeekOrigin.Begin);
+
+ using ( TarArchive tarIn = TarArchive.CreateInputTarArchive(ms2) )
+ {
+ entryCount = 0;
+ tarIn.ProgressMessageEvent += new ProgressMessageHandler(EntryCounter);
+ tarIn.ListContents();
+ Assert.AreEqual(0, entryCount, "Expected 0 tar entries");
+ }
+ }
+ /// <summary>
+ /// Check that the tar block factor can be varied successfully.
+ /// </summary>
+ [Test]
+ public void BlockFactorHandling()
+ {
+ const int MinimumBlockFactor = 1;
+ const int MaximumBlockFactor = 64;
+ const int FillFactor = 2;
+
+ for ( int factor = MinimumBlockFactor; factor < MaximumBlockFactor; ++factor)
+ {
+ MemoryStream ms = new MemoryStream();
+
+ using ( TarOutputStream tarOut = new TarOutputStream(ms, factor) )
+ {
+ TarEntry entry = TarEntry.CreateTarEntry("TestEntry");
+ entry.Size = (TarBuffer.BlockSize * factor * FillFactor);
+ tarOut.PutNextEntry(entry);
+
+ byte[] buffer = new byte[TarBuffer.BlockSize];
+
+ Random r = new Random();
+ r.NextBytes(buffer);
+
+ // Last block is a partial one
+ for ( int i = 0; i < factor * FillFactor; ++i)
+ {
+ tarOut.Write(buffer, 0, buffer.Length);
+ }
+ }
+
+ byte[] tarData = ms.ToArray();
+ Assert.IsNotNull(tarData, "Data written is null");
+
+ // Blocks = Header + Data Blocks + Zero block + Record trailer
+ int usedBlocks = 1 + (factor * FillFactor) + 1;
+ int totalBlocks = usedBlocks + (factor - 1);
+ totalBlocks /= factor;
+ totalBlocks *= factor;
+
+ Assert.AreEqual(TarBuffer.BlockSize * totalBlocks, tarData.Length, "Tar file should contain {0} blocks in length",
+ totalBlocks);
+
+ if ( usedBlocks < totalBlocks )
+ {
+ // Start at first byte after header.
+ int byteIndex = TarBuffer.BlockSize * ((factor * FillFactor)+ 1);
+ while ( byteIndex < tarData.Length )
+ {
+ int blockNumber = byteIndex / TarBuffer.BlockSize;
+ int offset = blockNumber % TarBuffer.BlockSize;
+ Assert.AreEqual(0, tarData[byteIndex],
+ string.Format("Trailing block data should be null iteration {0} block {1} offset {2} index {3}",
+ factor,
+ blockNumber, offset, byteIndex));
+ byteIndex += 1;
+ }
+ }
+ }
+ }
+
+
+ /// <summary>
+ /// Check that the tar trailer only contains nulls.
+ /// </summary>
+ [Test]
+ public void TrailerContainsNulls()
+ {
+ const int TestBlockFactor = 3;
+
+ for ( int iteration = 0; iteration < TestBlockFactor * 2; ++iteration)
+ {
+ MemoryStream ms = new MemoryStream();
+
+ using ( TarOutputStream tarOut = new TarOutputStream(ms, TestBlockFactor) )
+ {
+ TarEntry entry = TarEntry.CreateTarEntry("TestEntry");
+ if ( iteration > 0 )
+ {
+ entry.Size = (TarBuffer.BlockSize * (iteration - 1)) + 9;
+ }
+ tarOut.PutNextEntry(entry);
+
+ byte[] buffer = new byte[TarBuffer.BlockSize];
+
+ Random r = new Random();
+ r.NextBytes(buffer);
+
+ if ( iteration > 0 )
+ {
+ for ( int i = 0; i < iteration - 1; ++i )
+ {
+ tarOut.Write(buffer, 0, buffer.Length);
+ }
+
+ // Last block is a partial one
+ for ( int i = 1; i < 10; ++i)
+ {
+ tarOut.WriteByte((byte)i);
+ }
+ }
+ }
+
+ byte[] tarData = ms.ToArray();
+ Assert.IsNotNull(tarData, "Data written is null");
+
+ // Blocks = Header + Data Blocks + Zero block + Record trailer
+ int usedBlocks = 1 + iteration + 1;
+ int totalBlocks = usedBlocks + (TestBlockFactor - 1);
+ totalBlocks /= TestBlockFactor;
+ totalBlocks *= TestBlockFactor;
+
+ Assert.AreEqual(TarBuffer.BlockSize * totalBlocks, tarData.Length,
+ string.Format("Tar file should be {0} blocks in length", totalBlocks));
+
+ if ( usedBlocks < totalBlocks )
+ {
+ // Start at first byte after header.
+ int byteIndex = TarBuffer.BlockSize * (iteration + 1);
+ while ( byteIndex < tarData.Length )
+ {
+ int blockNumber = byteIndex / TarBuffer.BlockSize;
+ int offset = blockNumber % TarBuffer.BlockSize;
+ Assert.AreEqual(0, tarData[byteIndex],
+ string.Format("Trailing block data should be null iteration {0} block {1} offset {2} index {3}",
+ iteration,
+ blockNumber, offset, byteIndex));
+ byteIndex += 1;
+ }
+ }
+ }
+ }
+
+ void TryLongName(string name)
+ {
+ MemoryStream ms = new MemoryStream();
+ using ( TarOutputStream tarOut = new TarOutputStream(ms) )
+ {
+ DateTime modTime = DateTime.Now;
+
+ TarEntry entry = TarEntry.CreateTarEntry(name);
+ tarOut.PutNextEntry(entry);
+ }
+
+ MemoryStream ms2 = new MemoryStream();
+ ms2.Write(ms.GetBuffer(), 0, ms.GetBuffer().Length);
+ ms2.Seek(0, SeekOrigin.Begin);
+
+ using (TarInputStream tarIn = new TarInputStream(ms2))
+ {
+ TarEntry nextEntry = tarIn.GetNextEntry();
+
+ Assert.AreEqual(nextEntry.Name, name, "Name match failure");
+ }
+ }
+
+ /// <summary>
+ /// Check that long names are handled correctly for reading and writing.
+ /// </summary>
+ [Test]
+ [Category("Tar")]
+ public void LongNames()
+ {
+ TryLongName("11111111112222222222333333333344444444445555555555" +
+ "6666666666777777777788888888889999999999000000000");
+
+ TryLongName("11111111112222222222333333333344444444445555555555" +
+ "66666666667777777777888888888899999999990000000000");
+
+ TryLongName("11111111112222222222333333333344444444445555555555" +
+ "66666666667777777777888888888899999999990000000000" +
+ "1");
+
+ TryLongName("11111111112222222222333333333344444444445555555555" +
+ "66666666667777777777888888888899999999990000000000" +
+ "11111111112222222222333333333344444444445555555555" +
+ "66666666667777777777888888888899999999990000000000");
+
+ TryLongName("11111111112222222222333333333344444444445555555555" +
+ "66666666667777777777888888888899999999990000000000" +
+ "11111111112222222222333333333344444444445555555555" +
+ "66666666667777777777888888888899999999990000000000" +
+ "11111111112222222222333333333344444444445555555555" +
+ "66666666667777777777888888888899999999990000000000" +
+ "11111111112222222222333333333344444444445555555555" +
+ "66666666667777777777888888888899999999990000000000" +
+ "11111111112222222222333333333344444444445555555555" +
+ "66666666667777777777888888888899999999990000000000");
+
+ for (int n = 1; n < 1024; ++n)
+ {
+ string format = "{0," + n + "}";
+ string formatted = string.Format(format, "A");
+ TryLongName(formatted);
+ }
+ }
+
+ /// <summary>
+ /// Test equals function for tar headers.
+ /// </summary>
+ [Test]
+ [Category("Tar")]
+ public void HeaderEquality()
+ {
+ TarHeader h1 = new TarHeader();
+ TarHeader h2 = new TarHeader();
+
+ Assert.IsTrue(h1.Equals(h2));
+
+ h1.Name = "ABCDEFG";
+ Assert.IsFalse(h1.Equals(h2));
+ h2.Name = h1.Name;
+ Assert.IsTrue(h1.Equals(h2));
+
+ h1.Mode = 33188;
+ Assert.IsFalse(h1.Equals(h2));
+ h2.Mode = h1.Mode;
+ Assert.IsTrue(h1.Equals(h2));
+
+ h1.UserId = 654;
+ Assert.IsFalse(h1.Equals(h2));
+ h2.UserId = h1.UserId;
+ Assert.IsTrue(h1.Equals(h2));
+
+ h1.GroupId = 654;
+ Assert.IsFalse(h1.Equals(h2));
+ h2.GroupId = h1.GroupId;
+ Assert.IsTrue(h1.Equals(h2));
+
+ h1.Size = 654;
+ Assert.IsFalse(h1.Equals(h2));
+ h2.Size = h1.Size;
+ Assert.IsTrue(h1.Equals(h2));
+
+ h1.ModTime = DateTime.Now;
+ Assert.IsFalse(h1.Equals(h2));
+ h2.ModTime = h1.ModTime;
+ Assert.IsTrue(h1.Equals(h2));
+
+ h1.TypeFlag = 165;
+ Assert.IsFalse(h1.Equals(h2));
+ h2.TypeFlag = h1.TypeFlag;
+ Assert.IsTrue(h1.Equals(h2));
+
+ h1.LinkName = "link";
+ Assert.IsFalse(h1.Equals(h2));
+ h2.LinkName = h1.LinkName;
+ Assert.IsTrue(h1.Equals(h2));
+
+ h1.Magic = "ustar";
+ Assert.IsFalse(h1.Equals(h2));
+ h2.Magic = h1.Magic;
+ Assert.IsTrue(h1.Equals(h2));
+
+ h1.Version = "1";
+ Assert.IsFalse(h1.Equals(h2));
+ h2.Version = h1.Version;
+ Assert.IsTrue(h1.Equals(h2));
+
+ h1.UserName = "user";
+ Assert.IsFalse(h1.Equals(h2));
+ h2.UserName = h1.UserName;
+ Assert.IsTrue(h1.Equals(h2));
+
+ h1.GroupName = "group";
+ Assert.IsFalse(h1.Equals(h2));
+ h2.GroupName = h1.GroupName;
+ Assert.IsTrue(h1.Equals(h2));
+
+
+ h1.DevMajor = 165;
+ Assert.IsFalse(h1.Equals(h2));
+ h2.DevMajor = h1.DevMajor;
+ Assert.IsTrue(h1.Equals(h2));
+
+ h1.DevMinor = 164;
+ Assert.IsFalse(h1.Equals(h2));
+ h2.DevMinor = h1.DevMinor;
+ Assert.IsTrue(h1.Equals(h2));
+
+ }
+
+ [Test]
+ [Category("Tar")]
+ public void Checksum()
+ {
+ MemoryStream ms = new MemoryStream();
+ using ( TarOutputStream tarOut = new TarOutputStream(ms) )
+ {
+ DateTime modTime = DateTime.Now;
+
+ TarEntry entry = TarEntry.CreateTarEntry("TestEntry");
+ entry.TarHeader.Mode = 12345;
+
+ tarOut.PutNextEntry(entry);
+ }
+
+ MemoryStream ms2 = new MemoryStream();
+ ms2.Write(ms.GetBuffer(), 0, ms.GetBuffer().Length);
+ ms2.Seek(0, SeekOrigin.Begin);
+ TarEntry nextEntry;
+
+ using (TarInputStream tarIn = new TarInputStream(ms2))
+ {
+ nextEntry = tarIn.GetNextEntry();
+ Assert.IsTrue(nextEntry.TarHeader.IsChecksumValid, "Checksum should be valid");
+ }
+
+ MemoryStream ms3 = new MemoryStream();
+ ms3.Write(ms.GetBuffer(), 0, ms.GetBuffer().Length);
+ ms3.Seek(0, SeekOrigin.Begin);
+ ms3.Write(new byte[1] { 34 }, 0, 1);
+ ms3.Seek(0, SeekOrigin.Begin);
+
+ using (TarInputStream tarIn = new TarInputStream(ms3))
+ {
+ bool trapped = false;
+
+ try
+ {
+ nextEntry = tarIn.GetNextEntry();
+ }
+ catch (TarException)
+ {
+ trapped = true;
+ }
+
+ Assert.IsTrue(trapped, "Checksum should be invalid");
+ }
+ }
+
+ /// <summary>
+ /// Check that values set are preserved when writing and reading archives.
+ /// </summary>
+ [Test]
+ [Category("Tar")]
+ public void ValuesPreserved()
+ {
+ MemoryStream ms = new MemoryStream();
+ TarEntry entry;
+ DateTime modTime = DateTime.Now;
+
+ using (TarOutputStream tarOut = new TarOutputStream(ms))
+ {
+ entry = TarEntry.CreateTarEntry("TestEntry");
+ entry.GroupId = 12;
+ entry.UserId = 14;
+ entry.ModTime = modTime;
+ entry.UserName = "UserName";
+ entry.GroupName = "GroupName";
+ entry.TarHeader.Mode = 12345;
+
+ tarOut.PutNextEntry(entry);
+ }
+
+ MemoryStream ms2 = new MemoryStream();
+ ms2.Write(ms.GetBuffer(), 0, ms.GetBuffer().Length);
+ ms2.Seek(0, SeekOrigin.Begin);
+
+ using (TarInputStream tarIn = new TarInputStream(ms2))
+ {
+ TarEntry nextEntry = tarIn.GetNextEntry();
+ Assert.AreEqual(entry.TarHeader.Checksum, nextEntry.TarHeader.Checksum, "Checksum");
+
+ Assert.IsTrue(nextEntry.Equals(entry), "Entries should be equal");
+ Assert.IsTrue(nextEntry.TarHeader.Equals(entry.TarHeader), "Headers should match");
+
+ // Tar only stores seconds
+ DateTime truncatedTime = new DateTime(modTime.Year, modTime.Month, modTime.Day,
+ modTime.Hour, modTime.Minute, modTime.Second);
+ Assert.AreEqual(truncatedTime, nextEntry.ModTime, "Modtimes should match");
+
+ int entryCount = 0;
+ while ( nextEntry != null )
+ {
+ ++entryCount;
+ nextEntry = tarIn.GetNextEntry();
+ }
+
+ Assert.AreEqual(1, entryCount, "Expected 1 entry");
+ }
+ }
+
+ /// <summary>
+ /// Check invalid mod times are detected
+ /// </summary>
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void InvalidModTime()
+ {
+ TarEntry e = TarEntry.CreateTarEntry("test");
+ e.ModTime = DateTime.MinValue;
+ }
+
+
+ /// <summary>
+ /// Check invalid sizes are detected
+ /// </summary>
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void InvalidSize()
+ {
+ TarEntry e = TarEntry.CreateTarEntry("test");
+ e.Size = -6;
+ }
+
+ /// <summary>
+ /// Check invalid names are detected
+ /// </summary>
+ [Test]
+ [ExpectedException(typeof(ArgumentNullException))]
+ public void InvalidName()
+ {
+ TarEntry e = TarEntry.CreateTarEntry("test");
+ e.Name = null;
+ }
+
+ /// <summary>
+ /// Check setting user and group names.
+ /// </summary>
+ [Test]
+ public void UserAndGroupNames()
+ {
+ TarEntry e = TarEntry.CreateTarEntry("test");
+ e.UserName = null;
+ Assert.IsNotNull(e.UserName, "Name set to OS default");
+ e.UserName = "";
+ Assert.AreEqual(0, e.UserName.Length, "Empty name allowed");
+ e.GroupName = null;
+ Assert.AreEqual("None", e.GroupName, "default group name is None");
+ }
+
+ /// <summary>
+ /// Check invalid magic values are detected
+ /// </summary>
+ [Test]
+ [ExpectedException(typeof(ArgumentNullException))]
+ public void InvalidMagic()
+ {
+ TarEntry e = TarEntry.CreateTarEntry("test");
+ e.TarHeader.Magic = null;
+ }
+
+ /// <summary>
+ /// Check invalid link names are detected
+ /// </summary>
+ [Test]
+ [ExpectedException(typeof(ArgumentNullException))]
+ public void InvalidLinkName()
+ {
+ TarEntry e = TarEntry.CreateTarEntry("test");
+ e.TarHeader.LinkName = null;
+ }
+
+ /// <summary>
+ /// Check invalid version names are detected
+ /// </summary>
+ [Test]
+ [ExpectedException(typeof(ArgumentNullException))]
+ public void InvalidVersionName()
+ {
+ TarEntry e = TarEntry.CreateTarEntry("test");
+ e.TarHeader.Version = null;
+ }
+
+ [Test]
+ public void CloningAndUniqueness()
+ {
+ // Partial test of cloning for TarHeader and TarEntry
+ TarEntry e = TarEntry.CreateTarEntry("ohsogood");
+ e.GroupId = 47;
+ e.GroupName = "GroupName";
+ e.ModTime = DateTime.Now;
+ e.Size = 123234;
+
+ TarHeader headerE = e.TarHeader;
+
+ headerE.DevMajor = 99;
+ headerE.DevMinor = 98;
+ headerE.LinkName = "LanceLink";
+
+ TarEntry d = (TarEntry)e.Clone();
+
+ Assert.AreEqual(d.File, e.File);
+ Assert.AreEqual(d.GroupId, e.GroupId);
+ Assert.AreEqual(d.GroupName, e.GroupName);
+ Assert.AreEqual(d.IsDirectory, e.IsDirectory);
+ Assert.AreEqual(d.ModTime, e.ModTime);
+ Assert.AreEqual(d.Size, e.Size);
+
+ TarHeader headerD = d.TarHeader;
+
+ Assert.AreEqual(headerE.Checksum, headerD.Checksum);
+ Assert.AreEqual(headerE.LinkName, headerD.LinkName);
+
+ Assert.AreEqual(99, headerD.DevMajor);
+ Assert.AreEqual(98, headerD.DevMinor);
+
+ Assert.AreEqual("LanceLink", headerD.LinkName);
+
+ TarEntry entryf = new TarEntry(headerD);
+
+ headerD.LinkName = "Something different";
+
+ Assert.AreNotEqual(headerD.LinkName, entryf.TarHeader.LinkName, "Entry headers should be unique");
+ }
+ }
+}
--- /dev/null
+// Define this to use simple synchronisation rather than events.
+// They are about the same in terms of speed.
+#define SimpleSynch
+
+using System;
+using System.IO;
+using System.Threading;
+
+using NUnit.Framework;
+
+
+namespace ICSharpCode.SharpZipLib.Tests.TestSupport
+{
+ /// <summary>
+ /// A fixed size buffer of bytes. Both reading and writing are supported.
+ /// Reading from an empty buffer will wait until data is written. Writing to a full buffer
+ /// will wait until data is read.
+ /// </summary>
+ public class ReadWriteRingBuffer
+ {
+ #region Constructors
+ /// <summary>
+ /// Create a new RingBuffer with a specified size.
+ /// </summary>
+ /// <param name="size">The size of the ring buffer to create.</param>
+ public ReadWriteRingBuffer( int size )
+ {
+ if ( size <= 0 ) {
+ throw new ArgumentOutOfRangeException( "size" );
+ }
+
+ array_ = new byte[size];
+ lockObject_ = new object();
+
+#if SimpleSynch
+ waitSpan_ = TimeSpan.FromMilliseconds(1);
+#else
+ notEmptyEvent_ = new ManualResetEvent(false);
+ notFullEvent_ = new ManualResetEvent(true);
+#endif
+ }
+ #endregion
+
+ /// <summary>
+ /// Clear the buffer contents.
+ /// </summary>
+ public void Clear()
+ {
+ tail_ = 0;
+ head_ = 0;
+ count_ = 0;
+
+ Array.Clear( array_, 0, array_.Length );
+
+#if !SimpleSynch
+ notFullEvent_.Set();
+ notEmptyEvent_.Reset();
+#endif
+ }
+
+ /// <summary>
+ /// Close the buffer for writing.
+ /// </summary>
+ /// <remarks>A Read when the buffer is closed and there is no data will return -1.</remarks>
+ public void Close()
+ {
+ isClosed_ = true;
+#if !SimpleSynch
+ notEmptyEvent_.Set();
+#endif
+ }
+
+ /// <summary>
+ /// Write adds a byte to the head of the RingBuffer.
+ /// </summary>
+ /// <param name="value">The value to add.</param>
+ public void WriteByte( byte value )
+ {
+ if (isClosed_) {
+ throw new Exception("Buffer is closed");
+ }
+
+#if SimpleSynch
+ while (IsFull) {
+ Thread.Sleep(waitSpan_);
+ }
+#else
+ notFullEvent_.WaitOne();
+#endif
+
+ lock (lockObject_) {
+ array_[head_] = value;
+ head_ = (head_ + 1) % array_.Length;
+
+#if !SimpleSynch
+ bool setEmpty = (count_ == 0);
+#endif
+
+ count_ += 1;
+
+#if !SimpleSynch
+ if (IsFull)
+ {
+ notFullEvent_.Reset();
+ }
+
+ if (setEmpty)
+ {
+ notEmptyEvent_.Set();
+ }
+#endif
+ }
+
+ bytesWritten_++;
+ }
+
+ public void Write(byte[] buffer, int index, int count)
+ {
+ if (isClosed_)
+ {
+ throw new Exception("Buffer is closed");
+ }
+
+ while ( count > 0 )
+ {
+#if SimpleSynch
+ while (IsFull) {
+ Thread.Sleep(waitSpan_);
+ }
+#else
+ notFullEvent_.WaitOne();
+#endif
+
+ // Gauranteed to not be full at this point, however readers may sill read
+ // from the buffer first.
+ lock (lockObject_)
+ {
+ int bytesToWrite = Length - Count;
+
+ if (count < bytesToWrite)
+ {
+ bytesToWrite = count;
+ }
+#if !SimpleSynch
+ bool setEmpty = (count_ == 0);
+#endif
+
+ while (bytesToWrite > 0)
+ {
+ array_[head_] = buffer[index];
+ index++;
+
+ head_ = (head_ + 1) % array_.Length;
+
+ bytesToWrite--;
+ bytesWritten_++;
+ count--;
+ count_++;
+ }
+
+#if !SimpleSynch
+ if (IsFull)
+ {
+ notFullEvent_.Reset();
+ }
+
+ if (setEmpty)
+ {
+ notEmptyEvent_.Set();
+ }
+#endif
+ }
+ }
+ }
+
+ /// <summary>
+ /// Read a byte from the buffer.
+ /// </summary>
+ /// <returns></returns>
+ public int ReadByte()
+ {
+ int result = -1;
+
+#if SimpleSynch
+ while (!isClosed_ && IsEmpty) {
+ Thread.Sleep(waitSpan_);
+ }
+#else
+ notEmptyEvent_.WaitOne();
+#endif
+
+ if ( !IsEmpty ) {
+ lock (lockObject_) {
+ result = array_[tail_];
+ tail_ = (tail_ + 1) % array_.Length;
+#if !SimpleSynch
+ bool setFull = IsFull;
+#endif
+ count_ -= 1;
+#if !SimpleSynch
+ if (!isClosed_ && (count_ == 0))
+ {
+ notEmptyEvent_.Reset();
+ }
+
+ if (setFull)
+ {
+ notFullEvent_.Set();
+ }
+#endif
+ }
+ }
+
+ bytesRead_++;
+
+ return result;
+ }
+
+ public int Read(byte[] buffer, int index, int count)
+ {
+ int result = 0;
+
+ while (count > 0)
+ {
+#if SimpleSynch
+ while (!isClosed_ && IsEmpty)
+ {
+ Thread.Sleep(waitSpan_);
+ }
+#else
+ notEmptyEvent_.WaitOne();
+#endif
+
+ if (IsEmpty)
+ {
+ count = 0;
+ }
+ else
+ {
+ lock (lockObject_)
+ {
+ int toRead = Count;
+
+ if (toRead > count)
+ {
+ toRead = count;
+ }
+
+ result += toRead;
+
+#if !SimpleSynch
+ bool setFull = IsFull;
+#endif
+
+ while (toRead > 0)
+ {
+ buffer[index] = array_[tail_];
+ index++;
+
+ tail_ = (tail_ + 1) % array_.Length;
+ count--;
+ count_--;
+ toRead--;
+ bytesRead_++;
+ }
+#if !SimpleSynch
+ if (!isClosed_ && (count_ == 0))
+ {
+ notEmptyEvent_.Reset();
+ }
+
+ if (setFull)
+ {
+ notFullEvent_.Set();
+ }
+#endif
+ }
+ }
+ }
+
+ return result;
+ }
+
+ #region Properties
+
+ /// <summary>
+ /// Gets a value indicating wether the buffer is empty or not.
+ /// </summary>
+ public bool IsEmpty
+ {
+ get { return count_ == 0; }
+ }
+
+ public bool IsFull
+ {
+ get {
+ return (count_ == array_.Length);
+ }
+ }
+
+ public bool IsClosed
+ {
+ get { return isClosed_; }
+ }
+
+ /// <summary>
+ /// Gets the number of elements in the buffer.
+ /// </summary>
+ public int Count
+ {
+ get {
+ return count_;
+ }
+ }
+
+
+ public int Length
+ {
+ get { return array_.Length; }
+ }
+
+ public long BytesWritten
+ {
+ get { return bytesWritten_; }
+ }
+
+ public long BytesRead
+ {
+ get { return bytesRead_; }
+ }
+
+ /// <summary>
+ /// Indexer - Get an element from the tail of the RingBuffer.
+ /// </summary>
+ public byte this[ int index ]
+ {
+ get {
+ if ( ( index < 0 ) || ( index >= array_.Length ) ) {
+ throw new ArgumentOutOfRangeException( "index" );
+ }
+
+ return array_[ ( tail_ + index ) % array_.Length ];
+ }
+ }
+
+ #endregion
+
+ #region Instance Variables
+ /// <summary>
+ /// Flag indicating the buffer is closed.
+ /// </summary>
+ bool isClosed_;
+
+ /// <summary>
+ /// Index for the head of the buffer.
+ /// </summary>
+ /// <remarks>Its the index of the next byte to be <see cref="Write">written</see>.</remarks>
+ int head_;
+
+ /// <summary>
+ /// Index for the tail of the buffer.
+ /// </summary>
+ /// <remarks>Its the index of the next byte to be <see cref="Read">written</see>.</remarks>
+ int tail_;
+
+ /// <summary>
+ /// The total number of elements added to the buffer.
+ /// </summary>
+ int count_;
+
+ /// <summary>
+ /// Storage for the ring buffer contents.
+ /// </summary>
+ byte[] array_;
+
+ long bytesWritten_;
+ long bytesRead_;
+
+ object lockObject_;
+
+ TimeSpan waitSpan_;
+
+#if !SimpleSynch
+ ManualResetEvent notEmptyEvent_;
+ ManualResetEvent notFullEvent_;
+#endif
+ #endregion
+ }
+
+ [TestFixture]
+ public class ExerciseBuffer
+ {
+ [Test]
+ public void Basic()
+ {
+ const int Size = 64;
+
+ buffer_ = new ReadWriteRingBuffer(Size);
+
+ Assert.IsFalse(buffer_.IsFull);
+ Assert.IsTrue(buffer_.IsEmpty);
+
+ buffer_.WriteByte(1);
+
+ Assert.IsFalse(buffer_.IsFull);
+ Assert.IsFalse(buffer_.IsEmpty);
+ Assert.AreEqual(1, buffer_.Count);
+
+ Assert.AreEqual(1, buffer_.ReadByte());
+
+ Assert.IsFalse(buffer_.IsFull);
+ Assert.IsTrue(buffer_.IsEmpty);
+
+ for (int i = 0; i < buffer_.Length; ++i)
+ {
+ buffer_.WriteByte(unchecked((byte)(i & 0xff)));
+ }
+
+ Assert.IsTrue(buffer_.IsFull);
+ Assert.IsFalse(buffer_.IsEmpty);
+
+ buffer_.Close();
+
+ Assert.IsTrue(buffer_.IsClosed);
+
+ bool caught = false;
+ try
+ {
+ buffer_.WriteByte(1);
+ }
+ catch
+ {
+ caught = true;
+ }
+
+ Assert.IsTrue(caught);
+
+ int count = Size;
+ int expected = 0;
+
+ while (count != 0)
+ {
+ Assert.AreEqual(count, buffer_.Count);
+ Assert.AreEqual(expected, buffer_.ReadByte());
+ count--;
+ expected = (expected + 1) & 0xff;
+ }
+
+ Assert.IsTrue(buffer_.IsEmpty);
+ Assert.AreEqual(-1, buffer_.ReadByte());
+ }
+
+ [Test]
+ public void Buffered()
+ {
+
+ const int Size = 64;
+
+ buffer_ = new ReadWriteRingBuffer(Size);
+
+ byte[] writeBuffer = new byte[16];
+ for (int i = 0; i < 16; ++i)
+ {
+ writeBuffer[i] = (byte)i;
+ }
+
+ buffer_.Write(writeBuffer, 0, 3);
+ Assert.AreEqual(3, buffer_.Count);
+
+ byte[] readBuffer = new byte[16];
+ Assert.AreEqual(3, buffer_.Read(readBuffer, 0, 3));
+ for (int i = 0; i < 3; ++i)
+ {
+ Assert.AreEqual(i, readBuffer[i]);
+ }
+
+ }
+
+ [Test]
+ public void Threaded()
+ {
+ buffer_ = new ReadWriteRingBuffer(8);
+ readTarget_ = writeTarget_ = 16384;
+
+ Thread reader = new Thread(Reader);
+ reader.Start();
+
+ Thread writer = new Thread(Writer);
+ writer.Start();
+
+ writer.Join();
+ reader.Join();
+ }
+
+ void Reader()
+ {
+ Random r = new Random();
+ byte nextValue = 0;
+
+ while (readTarget_ > 0)
+ {
+ int thisTime = r.Next(16);
+ if (thisTime > readTarget_)
+ {
+ thisTime = readTarget_;
+ }
+
+ while (thisTime > 0)
+ {
+ int readValue = buffer_.ReadByte();
+ Assert.AreEqual(nextValue, readValue);
+ nextValue = (byte)((nextValue + 1) & 0xff);
+ thisTime--;
+ readTarget_--;
+ }
+
+ Thread.Sleep(r.Next(10));
+
+ }
+
+ int last = buffer_.ReadByte();
+
+ Assert.AreEqual(-1, last);
+ Assert.IsTrue(buffer_.IsClosed);
+ }
+
+ void Writer()
+ {
+ Random r = new Random();
+
+ byte nextValue = 0;
+ while (writeTarget_ > 0)
+ {
+ int thisTime = r.Next(16);
+ if (thisTime > writeTarget_)
+ {
+ thisTime = writeTarget_;
+ }
+
+ while (thisTime > 0)
+ {
+ buffer_.WriteByte(nextValue);
+ nextValue = (byte)((nextValue + 1) & 0xff);
+ thisTime--;
+ writeTarget_--;
+ }
+ Thread.Sleep(r.Next(10));
+ }
+ buffer_.Close();
+ }
+
+ int readTarget_;
+ int writeTarget_;
+
+ ReadWriteRingBuffer buffer_;
+
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Created by SharpDevelop.
+ * User: JohnR
+ * Date: 4/08/2007
+ * Time: 7:09 a.m.
+ *
+ * To change this template use Tools | Options | Coding | Edit Standard Headers.
+ */
+
+using System;
+using System.IO;
+
+namespace ICSharpCode.SharpZipLib.Tests.TestSupport
+{
+ /// <summary>
+ /// An extended <see cref="MemoryStream">memory stream</see>
+ /// that tracks closing and diposing
+ /// </summary>
+ public class MemoryStreamEx : MemoryStream
+ {
+ public MemoryStreamEx()
+ : base()
+ {
+ }
+
+ public MemoryStreamEx(byte[] buffer)
+ : base(buffer)
+ {
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ isDisposed_=true;
+ base.Dispose(disposing);
+ }
+
+ public override void Close()
+ {
+ isClosed_=true;
+ base.Close();
+ }
+
+ public bool IsClosed
+ {
+ get { return isClosed_; }
+ }
+
+ public bool IsDisposed
+ {
+ get { return isDisposed_; }
+ set { isDisposed_=value; }
+ }
+
+ #region Instance Fields
+ bool isDisposed_;
+
+ bool isClosed_;
+ #endregion
+ }
+
+ /// <summary>
+ /// A stream that cannot seek.
+ /// </summary>
+ public class MemoryStreamWithoutSeek : MemoryStreamEx
+ {
+ public override bool CanSeek
+ {
+ get {
+ return false;
+ }
+ }
+ }
+
+ public class NullStream : Stream
+ {
+ public override bool CanRead
+ {
+ get { return false; }
+ }
+
+ public override bool CanSeek
+ {
+ get { return false; }
+ }
+
+ public override bool CanWrite
+ {
+ get { return true; }
+ }
+
+ public override void Flush()
+ {
+ }
+
+ public override long Length
+ {
+ get { throw new Exception("The method or operation is not implemented."); }
+ }
+
+ public override long Position
+ {
+ get
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+ set
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+
+ public override void SetLength(long value)
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ }
+ }
+
+ public class WindowedStream : Stream
+ {
+ public WindowedStream(int size)
+ {
+ ringBuffer_ = new ReadWriteRingBuffer(size);
+ }
+
+ public override bool CanRead
+ {
+ get { return true; }
+ }
+
+ public override bool CanSeek
+ {
+ get { return false; }
+ }
+
+ public override bool CanWrite
+ {
+ get { return true; }
+ }
+
+ public override void Flush()
+ {
+ // Do nothing
+ }
+
+ public override long Length
+ {
+ // A bit of a HAK as its not true in the stream sense.
+ get { return ringBuffer_.Count; }
+ }
+
+ public override long Position
+ {
+ get
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+ set
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ int bytesRead = 0;
+ while (count > 0)
+ {
+ int value = ringBuffer_.ReadByte();
+ if (value >= 0)
+ {
+ buffer[offset] = (byte)(value & 0xff);
+ offset++;
+ bytesRead++;
+ count--;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ return bytesRead;
+ }
+
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+
+ public override void SetLength(long value)
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ for (int i = 0; i < count; ++i)
+ {
+ ringBuffer_.WriteByte(buffer[offset + i]);
+ }
+ }
+
+ public bool IsClosed
+ {
+ get { return ringBuffer_.IsClosed; }
+ }
+
+ public override void Close()
+ {
+ ringBuffer_.Close();
+ }
+
+ public long BytesWritten
+ {
+ get { return ringBuffer_.BytesWritten; }
+ }
+
+ public long BytesRead
+ {
+ get { return ringBuffer_.BytesRead; }
+ }
+
+ #region Instance Fields
+ ReadWriteRingBuffer ringBuffer_;
+
+ #endregion
+ }
+}
--- /dev/null
+using System;
+using System.IO;
+using System.Reflection;
+using System.Security;
+using System.Text;
+using System.Threading;
+using ICSharpCode.SharpZipLib.Silverlight.Checksums;
+using ICSharpCode.SharpZipLib.Silverlight.Core;
+using ICSharpCode.SharpZipLib.Silverlight.Serialization;
+using ICSharpCode.SharpZipLib.Silverlight.Zip;
+using ICSharpCode.SharpZipLib.Tests.TestSupport;
+using ICSharpCode.SharpZipLib.Zip;
+using NUnit.Framework;
+
+namespace ICSharpCode.SharpZipLib.Tests.Zip
+{
+
+ #region Local Support Classes
+
+ internal class RuntimeInfo
+ {
+ public RuntimeInfo(CompressionMethod method, int compressionLevel, int size, string password, bool getCrc)
+ {
+ this.method = method;
+ this.compressionLevel = compressionLevel;
+ this.password = password;
+ this.size = size;
+ random = false;
+
+ original = new byte[Size];
+ if (random)
+ {
+ var rnd = new Random();
+ rnd.NextBytes(original);
+ }
+ else
+ {
+ for (var i = 0; i < size; ++i)
+ {
+ original[i] = (byte) 'A';
+ }
+ }
+
+ if (getCrc)
+ {
+ var crc32 = new Crc32();
+ crc32.Update(original, 0, size);
+ crc = crc32.Value;
+ }
+ }
+
+
+ public RuntimeInfo(string password, bool isDirectory)
+ {
+ method = CompressionMethod.Stored;
+ compressionLevel = 1;
+ this.password = password;
+ size = 0;
+ random = false;
+ isDirectory_ = isDirectory;
+ original = new byte[0];
+ }
+
+
+ public byte[] Original
+ {
+ get { return original; }
+ }
+
+ public CompressionMethod Method
+ {
+ get { return method; }
+ }
+
+ public int CompressionLevel
+ {
+ get { return compressionLevel; }
+ }
+
+ public int Size
+ {
+ get { return size; }
+ }
+
+ public string Password
+ {
+ get { return password; }
+ }
+
+ private bool Random
+ {
+ get { return random; }
+ }
+
+ public long Crc
+ {
+ get { return crc; }
+ }
+
+ public bool IsDirectory
+ {
+ get { return isDirectory_; }
+ }
+
+ #region Instance Fields
+
+ private readonly int compressionLevel;
+ private readonly long crc = -1;
+ private readonly bool isDirectory_;
+ private readonly CompressionMethod method;
+ private readonly byte[] original;
+ private readonly string password;
+ private readonly bool random;
+ private readonly int size;
+
+ #endregion
+ }
+
+ internal class MemoryDataSource : IStaticDataSource
+ {
+ #region Constructors
+
+ /// <summary>
+ /// Initialise a new instance.
+ /// </summary>
+ /// <param name="data">The data to provide.</param>
+ public MemoryDataSource(byte[] data)
+ {
+ data_ = data;
+ }
+
+ #endregion
+
+ #region IStaticDataSource Members
+
+ /// <summary>
+ /// Get a Stream for this <see cref="DataSource"/>
+ /// </summary>
+ /// <returns>Returns a <see cref="Stream"/></returns>
+ public Stream GetSource()
+ {
+ return new MemoryStream(data_);
+ }
+
+ #endregion
+
+ #region Instance Fields
+
+ private readonly byte[] data_;
+
+ #endregion
+ }
+
+ internal class StringMemoryDataSource : MemoryDataSource
+ {
+ public StringMemoryDataSource(string data)
+ : base(Encoding.UTF8.GetBytes(data))
+ {
+ }
+ }
+
+ #endregion
+
+ #region ZipBase
+
+ public class ZipBase
+ {
+ protected static string GetTempFilePath()
+ {
+ string result = null;
+ try
+ {
+ result = Path.GetTempPath();
+ }
+ catch (SecurityException)
+ {
+ }
+ return result;
+ }
+
+ protected byte[] MakeInMemoryZip(bool withSeek, params object[] createSpecs)
+ {
+ MemoryStream ms;
+
+ if (withSeek)
+ {
+ ms = new MemoryStream();
+ }
+ else
+ {
+ ms = new MemoryStreamWithoutSeek();
+ }
+
+ using (var outStream = new ZipOutputStream(ms))
+ {
+ for (var counter = 0; counter < createSpecs.Length; ++counter)
+ {
+ var info = createSpecs[counter] as RuntimeInfo;
+ outStream.Password = info.Password;
+
+ if (info.Method != CompressionMethod.Stored)
+ {
+ outStream.SetLevel(info.CompressionLevel); // 0 - store only to 9 - means best compression
+ }
+
+ string entryName;
+
+ if (info.IsDirectory)
+ {
+ entryName = "dir" + counter + "/";
+ }
+ else
+ {
+ entryName = "entry" + counter + ".tst";
+ }
+
+ var entry = new ZipEntry(entryName);
+ entry.CompressionMethod = info.Method;
+ if (info.Crc >= 0)
+ {
+ entry.Crc = info.Crc;
+ }
+
+ outStream.PutNextEntry(entry);
+
+ if (info.Size > 0)
+ {
+ outStream.Write(info.Original, 0, info.Original.Length);
+ }
+ }
+ }
+ return ms.ToArray();
+ }
+
+ protected byte[] MakeInMemoryZip(ref byte[] original, CompressionMethod method,
+ int compressionLevel, int size, string password, bool withSeek)
+ {
+ MemoryStream ms;
+
+ if (withSeek)
+ {
+ ms = new MemoryStream();
+ }
+ else
+ {
+ ms = new MemoryStreamWithoutSeek();
+ }
+
+ using (var outStream = new ZipOutputStream(ms))
+ {
+ outStream.Password = password;
+
+ if (method != CompressionMethod.Stored)
+ {
+ outStream.SetLevel(compressionLevel); // 0 - store only to 9 - means best compression
+ }
+
+ var entry = new ZipEntry("dummyfile.tst");
+ entry.CompressionMethod = method;
+
+ outStream.PutNextEntry(entry);
+
+ if (size > 0)
+ {
+ var rnd = new Random();
+ original = new byte[size];
+ rnd.NextBytes(original);
+
+ outStream.Write(original, 0, original.Length);
+ }
+ }
+ return ms.ToArray();
+ }
+
+ protected static void MakeTempFile(string name, int size)
+ {
+ using (var fs = File.Create(name))
+ {
+ var buffer = new byte[4096];
+ while (size > 0)
+ {
+ fs.Write(buffer, 0, Math.Min(size, buffer.Length));
+ size -= buffer.Length;
+ }
+ }
+ }
+
+ protected static byte ScatterValue(byte rhs)
+ {
+ return (byte) ((rhs*253 + 7) & 0xff);
+ }
+
+
+ private static void AddKnownDataToEntry(ZipOutputStream zipStream, int size)
+ {
+ if (size > 0)
+ {
+ byte nextValue = 0;
+ var bufferSize = Math.Min(size, 65536);
+ var data = new byte[bufferSize];
+ var currentIndex = 0;
+ for (var i = 0; i < size; ++i)
+ {
+ data[currentIndex] = nextValue;
+ nextValue = ScatterValue(nextValue);
+
+ currentIndex += 1;
+ if ((currentIndex >= data.Length) || (i + 1 == size))
+ {
+ zipStream.Write(data, 0, currentIndex);
+ currentIndex = 0;
+ }
+ }
+ }
+ }
+
+ public void WriteToFile(string fileName, byte[] data)
+ {
+ using (var fs = File.Open(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.Read))
+ {
+ fs.Write(data, 0, data.Length);
+ }
+ }
+
+ protected static void CheckKnownEntry(Stream inStream, int expectedCount)
+ {
+ var buffer = new byte[1024];
+
+ int bytesRead;
+ var total = 0;
+ byte nextValue = 0;
+ while ((bytesRead = inStream.Read(buffer, 0, buffer.Length)) > 0)
+ {
+ total += bytesRead;
+ for (var i = 0; i < bytesRead; ++i)
+ {
+ Assert.AreEqual(nextValue, buffer[i], "Wrong value read from entry");
+ nextValue = ScatterValue(nextValue);
+ }
+ }
+ Assert.AreEqual(expectedCount, total, "Wrong number of bytes read from entry");
+ }
+
+ protected byte ReadByteChecked(Stream stream)
+ {
+ var rawValue = stream.ReadByte();
+ Assert.IsTrue(rawValue >= 0);
+ return (byte) rawValue;
+ }
+
+ protected int ReadInt(Stream stream)
+ {
+ return ReadByteChecked(stream) |
+ (ReadByteChecked(stream) << 8) |
+ (ReadByteChecked(stream) << 16) |
+ (ReadByteChecked(stream) << 24);
+ }
+
+ protected long ReadLong(Stream stream)
+ {
+ var result = ReadInt(stream) & 0xffffffff;
+ return result | (((long) ReadInt(stream)) << 32);
+ }
+
+ #region MakeZipFile Names
+
+ protected void MakeZipFile(Stream storage, bool isOwner, string[] names, int size, string comment)
+ {
+ using (var zOut = new ZipOutputStream(storage))
+ {
+ zOut.IsStreamOwner = isOwner;
+ zOut.SetComment(comment);
+ for (var i = 0; i < names.Length; ++i)
+ {
+ zOut.PutNextEntry(new ZipEntry(names[i]));
+ AddKnownDataToEntry(zOut, size);
+ }
+ zOut.Close();
+ }
+ }
+
+ protected void MakeZipFile(string name, string[] names, int size, string comment)
+ {
+ using (var fs = File.Create(name))
+ {
+ using (var zOut = new ZipOutputStream(fs))
+ {
+ zOut.SetComment(comment);
+ for (var i = 0; i < names.Length; ++i)
+ {
+ zOut.PutNextEntry(new ZipEntry(names[i]));
+ AddKnownDataToEntry(zOut, size);
+ }
+ zOut.Close();
+ }
+ fs.Close();
+ }
+ }
+
+ #endregion
+
+ #region MakeZipFile Entries
+
+ protected void MakeZipFile(string name, string entryNamePrefix, int entries, int size, string comment)
+ {
+ using (var fs = File.Create(name))
+ {
+ using (var zOut = new ZipOutputStream(fs))
+ {
+ zOut.SetComment(comment);
+ for (var i = 0; i < entries; ++i)
+ {
+ zOut.PutNextEntry(new ZipEntry(entryNamePrefix + (i + 1)));
+ AddKnownDataToEntry(zOut, size);
+ }
+ }
+ }
+ }
+
+ protected void MakeZipFile(Stream storage, bool isOwner,
+ string entryNamePrefix, int entries, int size, string comment)
+ {
+ using (var zOut = new ZipOutputStream(storage))
+ {
+ zOut.IsStreamOwner = isOwner;
+ zOut.SetComment(comment);
+ for (var i = 0; i < entries; ++i)
+ {
+ zOut.PutNextEntry(new ZipEntry(entryNamePrefix + (i + 1)));
+ AddKnownDataToEntry(zOut, size);
+ }
+ }
+ }
+
+ #endregion
+ }
+
+ #endregion
+
+ internal class TestHelper
+ {
+ public static void SaveMemoryStream(MemoryStream ms, string fileName)
+ {
+ var data = ms.ToArray();
+ using (var fs = File.Open(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.Read))
+ {
+ fs.Write(data, 0, data.Length);
+ }
+ }
+
+ public static int CompareDosDateTimes(DateTime l, DateTime r)
+ {
+ // Compare dates to dos accuracy...
+ // Ticks can be different yet all these values are still the same!
+ var result = l.Year - r.Year;
+ if (result == 0)
+ {
+ result = l.Month - r.Month;
+ if (result == 0)
+ {
+ result = l.Day - r.Day;
+ if (result == 0)
+ {
+ result = l.Hour - r.Hour;
+ if (result == 0)
+ {
+ result = l.Minute - r.Minute;
+ if (result == 0)
+ {
+ result = (l.Second/2) - (r.Second/2);
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+ }
+
+ [TestFixture]
+ public class ZipEntryHandling : ZipBase
+ {
+ private void PiecewiseCompare(ZipEntry lhs, ZipEntry rhs)
+ {
+ var entryType = typeof (ZipEntry);
+ var binding = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+
+ var fields = entryType.GetFields(binding);
+
+ Assert.Greater(fields.Length, 8, "Failed to find fields");
+
+ foreach (var info in fields)
+ {
+ var lValue = info.GetValue(lhs);
+ var rValue = info.GetValue(rhs);
+
+ Assert.AreEqual(lValue, rValue);
+ }
+ }
+
+ /// <summary>
+ /// Check that cloned entries are correct.
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void Cloning()
+ {
+ long testCrc = 3456;
+ long testSize = 99874276;
+ long testCompressedSize = 72347;
+ var testExtraData = new byte[]{0x00, 0x01, 0x00, 0x02, 0x0EF, 0xFE};
+ var testName = "Namu";
+ var testFlags = 4567;
+ long testDosTime = 23434536;
+ var testMethod = CompressionMethod.Deflated;
+
+ var testComment = "A comment";
+
+ var source = new ZipEntry(testName);
+ source.Crc = testCrc;
+ source.Comment = testComment;
+ source.Size = testSize;
+ source.CompressedSize = testCompressedSize;
+ source.ExtraData = testExtraData;
+ source.Flags = testFlags;
+ source.DosTime = testDosTime;
+ source.CompressionMethod = testMethod;
+
+ var clone = (ZipEntry) source.Clone();
+
+ // Check values against originals
+ Assert.AreEqual(testName, clone.Name, "Cloned name mismatch");
+ Assert.AreEqual(testCrc, clone.Crc, "Cloned crc mismatch");
+ Assert.AreEqual(testComment, clone.Comment, "Cloned comment mismatch");
+ Assert.AreEqual(testExtraData, clone.ExtraData, "Cloned Extra data mismatch");
+ Assert.AreEqual(testSize, clone.Size, "Cloned size mismatch");
+ Assert.AreEqual(testCompressedSize, clone.CompressedSize, "Cloned compressed size mismatch");
+ Assert.AreEqual(testFlags, clone.Flags, "Cloned flags mismatch");
+ Assert.AreEqual(testDosTime, clone.DosTime, "Cloned DOSTime mismatch");
+ Assert.AreEqual(testMethod, clone.CompressionMethod, "Cloned Compression method mismatch");
+
+ // Check against source
+ PiecewiseCompare(source, clone);
+ }
+
+ /// <summary>
+ /// Test that obsolete copy constructor works correctly.
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void Copying()
+ {
+ long testCrc = 3456;
+ long testSize = 99874276;
+ long testCompressedSize = 72347;
+ var testExtraData = new byte[]{0x00, 0x01, 0x00, 0x02, 0x0EF, 0xFE};
+ var testName = "Namu";
+ var testFlags = 4567;
+ long testDosTime = 23434536;
+ var testMethod = CompressionMethod.Deflated;
+
+ var testComment = "A comment";
+
+ var source = new ZipEntry(testName);
+ source.Crc = testCrc;
+ source.Comment = testComment;
+ source.Size = testSize;
+ source.CompressedSize = testCompressedSize;
+ source.ExtraData = testExtraData;
+ source.Flags = testFlags;
+ source.DosTime = testDosTime;
+ source.CompressionMethod = testMethod;
+
+#pragma warning disable 0618
+ var clone = new ZipEntry(source);
+#pragma warning restore
+
+ PiecewiseCompare(source, clone);
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void DateAndTime()
+ {
+ var ze = new ZipEntry("Pok");
+
+ // -1 is not strictly a valid MS-DOS DateTime value.
+ // ZipEntry is lenient about handling invalid values.
+ ze.DosTime = -1;
+
+ Assert.AreEqual(new DateTime(2107, 12, 31, 23, 59, 59), ze.DateTime);
+
+ // 0 is a special value meaning Now.
+ ze.DosTime = 0;
+ var diff = DateTime.Now - ze.DateTime;
+
+ // Value == 2 seconds!
+ ze.DosTime = 1;
+ Assert.AreEqual(new DateTime(1980, 1, 1, 0, 0, 2), ze.DateTime);
+
+ // Over the limit are set to max.
+ ze.DateTime = new DateTime(2108, 1, 1);
+ Assert.AreEqual(new DateTime(2107, 12, 31, 23, 59, 58), ze.DateTime);
+
+ // Under the limit are set to min.
+ ze.DateTime = new DateTime(1906, 12, 4);
+ Assert.AreEqual(new DateTime(1980, 1, 1, 0, 0, 0), ze.DateTime);
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void DateTimeSetsDosTime()
+ {
+ var ze = new ZipEntry("Pok");
+
+ var original = ze.DosTime;
+
+ ze.DateTime = new DateTime(1987, 9, 12);
+ Assert.AreNotEqual(original, ze.DosTime);
+ Assert.AreEqual(0, TestHelper.CompareDosDateTimes(new DateTime(1987, 9, 12), ze.DateTime));
+ }
+
+ /// <summary>
+ /// Setting entry comments to null should be allowed
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void NullEntryComment()
+ {
+ var test = new ZipEntry("null");
+ test.Comment = null;
+ }
+
+ /// <summary>
+ /// Entries with null names arent allowed
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ [ExpectedException(typeof (ArgumentNullException))]
+ public void NullNameInConstructor()
+ {
+ string name = null;
+ var test = new ZipEntry(name);
+ }
+ }
+
+ /// <summary>
+ /// This contains newer tests for stream handling. Much of this is still in GeneralHandling
+ /// </summary>
+ [TestFixture]
+ public class StreamHandling : ZipBase
+ {
+ private void MustFailRead(Stream s, byte[] buffer, int offset, int count)
+ {
+ var exception = false;
+ try
+ {
+ s.Read(buffer, offset, count);
+ }
+ catch
+ {
+ exception = true;
+ }
+ Assert.IsTrue(exception, "Read should fail");
+ }
+
+ private void Reader()
+ {
+ const int Size = 8192;
+ var readBytes = 1;
+ var buffer = new byte[Size];
+
+ var passifierLevel = readTarget_ - 0x10000000;
+ var single = inStream_.GetNextEntry();
+
+ Assert.AreEqual(single.Name, "CantSeek");
+ Assert.IsTrue((single.Flags & (int) GeneralBitFlags.Descriptor) != 0);
+
+ while ((readTarget_ > 0) && (readBytes > 0))
+ {
+ var count = Size;
+ if (count > readTarget_)
+ {
+ count = (int) readTarget_;
+ }
+
+ readBytes = inStream_.Read(buffer, 0, count);
+ readTarget_ -= readBytes;
+
+ if (readTarget_ <= passifierLevel)
+ {
+ Console.WriteLine("Reader {0} bytes remaining", readTarget_);
+ passifierLevel = readTarget_ - 0x10000000;
+ }
+ }
+
+ Assert.IsTrue(window_.IsClosed, "Window should be closed");
+
+ // This shouldnt read any data but should read the footer
+ readBytes = inStream_.Read(buffer, 0, 1);
+ Assert.AreEqual(0, readBytes, "Stream should be empty");
+ Assert.AreEqual(0, window_.Length, "Window should be closed");
+ inStream_.Close();
+ }
+
+ private void WriteTargetBytes()
+ {
+ const int Size = 8192;
+
+ var buffer = new byte[Size];
+
+ while (writeTarget_ > 0)
+ {
+ var thisTime = Size;
+ if (thisTime > writeTarget_)
+ {
+ thisTime = (int) writeTarget_;
+ }
+
+ outStream_.Write(buffer, 0, thisTime);
+ writeTarget_ -= thisTime;
+ }
+ }
+
+ private void Writer()
+ {
+ outStream_.PutNextEntry(new ZipEntry("CantSeek"));
+ WriteTargetBytes();
+ outStream_.Close();
+ }
+
+ private WindowedStream window_;
+ private ZipOutputStream outStream_;
+ private ZipInputStream inStream_;
+ private long readTarget_;
+ private long writeTarget_;
+
+ /// <summary>
+ /// Check that base stream is not closed when IsOwner is false;
+ /// </summary>
+ [Test]
+ public void BaseClosedAfterFailure()
+ {
+ var ms = new MemoryStreamEx(new byte[32]);
+
+ Assert.IsFalse(ms.IsClosed, "Underlying stream should NOT be closed initially");
+ var blewUp = false;
+ try
+ {
+ using (var stream = new ZipOutputStream(ms))
+ {
+ Assert.IsTrue(stream.IsStreamOwner, "Should be stream owner by default");
+ try
+ {
+ stream.PutNextEntry(new ZipEntry("Tiny"));
+ stream.Write(new byte[32], 0, 32);
+ }
+ finally
+ {
+ Assert.IsFalse(ms.IsClosed, "Stream should still not be closed.");
+ stream.Close();
+ Assert.Fail("Exception not thrown");
+ }
+ }
+ }
+ catch
+ {
+ blewUp = true;
+ }
+
+ Assert.IsTrue(blewUp, "Should have failed to write to stream");
+ Assert.IsTrue(ms.IsClosed, "Underlying stream should be closed");
+ }
+
+ /// <summary>
+ /// Base stream is closed when IsOwner is true ( default);
+ /// </summary>
+ [Test]
+ public void BaseClosedWhenOwner()
+ {
+ var ms = new MemoryStreamEx();
+
+ Assert.IsFalse(ms.IsClosed, "Underlying stream should NOT be closed");
+
+ using (var stream = new ZipOutputStream(ms))
+ {
+ Assert.IsTrue(stream.IsStreamOwner, "Should be stream owner by default");
+ }
+
+ Assert.IsTrue(ms.IsClosed, "Underlying stream should be closed");
+ }
+
+ /// <summary>
+ /// Check that base stream is not closed when IsOwner is false;
+ /// </summary>
+ [Test]
+ public void BaseNotClosedWhenNotOwner()
+ {
+ var ms = new MemoryStreamEx();
+
+ Assert.IsFalse(ms.IsClosed, "Underlying stream should NOT be closed");
+
+ using (var stream = new ZipOutputStream(ms))
+ {
+ Assert.IsTrue(stream.IsStreamOwner, "Should be stream owner by default");
+ stream.IsStreamOwner = false;
+ }
+ Assert.IsFalse(ms.IsClosed, "Underlying stream should still NOT be closed");
+ }
+
+ /// <summary>
+ /// Empty zips can be created and read?
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void CreateAndReadEmptyZip()
+ {
+ var ms = new MemoryStream();
+ var outStream = new ZipOutputStream(ms);
+ outStream.Finish();
+
+ ms.Seek(0, SeekOrigin.Begin);
+
+ var inStream = new ZipInputStream(ms);
+ ZipEntry entry;
+ while ((entry = inStream.GetNextEntry()) != null)
+ {
+ Assert.Fail("No entries should be found in empty zip");
+ }
+ }
+
+ /// <summary>
+ /// Empty zip entries can be created and read?
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void EmptyZipEntries()
+ {
+ var ms = new MemoryStream();
+ var outStream = new ZipOutputStream(ms);
+ for (var i = 0; i < 10; ++i)
+ {
+ outStream.PutNextEntry(new ZipEntry(i.ToString()));
+ }
+ outStream.Finish();
+
+ ms.Seek(0, SeekOrigin.Begin);
+
+ var inStream = new ZipInputStream(ms);
+
+ var extractCount = 0;
+ ZipEntry entry;
+ var decompressedData = new byte[100];
+
+ while ((entry = inStream.GetNextEntry()) != null)
+ {
+ while (true)
+ {
+ var numRead = inStream.Read(decompressedData, extractCount, decompressedData.Length);
+ if (numRead <= 0)
+ {
+ break;
+ }
+ extractCount += numRead;
+ }
+ }
+ inStream.Close();
+ Assert.AreEqual(extractCount, 0, "No data should be read from empty entries");
+ }
+
+ /// <summary>
+ /// Check that adding an entry with no data and Zip64 works OK
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void EntryWithNoDataAndZip64()
+ {
+ MemoryStream msw = new MemoryStreamWithoutSeek();
+ var outStream = new ZipOutputStream(msw);
+
+ outStream.IsStreamOwner = false;
+ var ze = new ZipEntry("Striped Marlin");
+ ze.ForceZip64();
+ ze.Size = 0;
+ outStream.PutNextEntry(ze);
+ outStream.CloseEntry();
+ outStream.Finish();
+ outStream.Close();
+
+ var ms = new MemoryStream(msw.ToArray());
+ using (var zf = new ZipFile(ms))
+ {
+ Assert.IsTrue(zf.TestArchive(true));
+ }
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void ParameterHandling()
+ {
+ var buffer = new byte[10];
+ var emptyBuffer = new byte[0];
+
+ var ms = new MemoryStream();
+ var outStream = new ZipOutputStream(ms);
+ outStream.IsStreamOwner = false;
+ outStream.PutNextEntry(new ZipEntry("Floyd"));
+ outStream.Write(buffer, 0, 10);
+ outStream.Finish();
+
+ ms.Seek(0, SeekOrigin.Begin);
+
+ var inStream = new ZipInputStream(ms);
+ var e = inStream.GetNextEntry();
+
+ MustFailRead(inStream, null, 0, 0);
+ MustFailRead(inStream, buffer, -1, 1);
+ MustFailRead(inStream, buffer, 0, 11);
+ MustFailRead(inStream, buffer, 7, 5);
+ MustFailRead(inStream, buffer, 0, -1);
+
+ MustFailRead(inStream, emptyBuffer, 0, 1);
+
+ var bytesRead = inStream.Read(buffer, 10, 0);
+ Assert.AreEqual(0, bytesRead, "Should be able to read zero bytes");
+
+ bytesRead = inStream.Read(emptyBuffer, 0, 0);
+ Assert.AreEqual(0, bytesRead, "Should be able to read zero bytes");
+ }
+
+ [Test]
+ [Category("Zip")]
+ [Category("Long Running")]
+ public void SingleLargeEntry()
+ {
+ window_ = new WindowedStream(0x10000);
+ outStream_ = new ZipOutputStream(window_);
+ inStream_ = new ZipInputStream(window_);
+
+ long target = 0x10000000;
+ readTarget_ = writeTarget_ = target;
+
+ var reader = new Thread(Reader);
+ reader.Name = "Reader";
+
+ var writer = new Thread(Writer);
+ writer.Name = "Writer";
+
+ var startTime = DateTime.Now;
+ reader.Start();
+ writer.Start();
+
+ writer.Join();
+ reader.Join();
+
+ var endTime = DateTime.Now;
+ var span = endTime - startTime;
+ Console.WriteLine("Time {0} throughput {1} KB/Sec", span, (target/1024)/span.TotalSeconds);
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void WriteThroughput()
+ {
+ outStream_ = new ZipOutputStream(new NullStream());
+
+ var startTime = DateTime.Now;
+
+ long target = 0x10000000;
+
+ writeTarget_ = target;
+ outStream_.PutNextEntry(new ZipEntry("0"));
+ WriteTargetBytes();
+
+ outStream_.Close();
+
+ var endTime = DateTime.Now;
+ var span = endTime - startTime;
+ Console.WriteLine("Time {0} throughput {1} KB/Sec", span, (target/1024)/span.TotalSeconds);
+ }
+
+ /// <summary>
+ /// Check that Zip64 descriptor is added to an entry OK.
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void Zip64Descriptor()
+ {
+ MemoryStream msw = new MemoryStreamWithoutSeek();
+ var outStream = new ZipOutputStream(msw);
+ outStream.UseZip64 = UseZip64.Off;
+
+ outStream.IsStreamOwner = false;
+ outStream.PutNextEntry(new ZipEntry("StripedMarlin"));
+ outStream.WriteByte(89);
+ outStream.Close();
+
+ var ms = new MemoryStream(msw.ToArray());
+ using (var zf = new ZipFile(ms))
+ {
+ Assert.IsTrue(zf.TestArchive(true));
+ }
+
+
+ msw = new MemoryStreamWithoutSeek();
+ outStream = new ZipOutputStream(msw);
+ outStream.UseZip64 = UseZip64.On;
+
+ outStream.IsStreamOwner = false;
+ outStream.PutNextEntry(new ZipEntry("StripedMarlin"));
+ outStream.WriteByte(89);
+ outStream.Close();
+
+ ms = new MemoryStream(msw.ToArray());
+ using (var zf = new ZipFile(ms))
+ {
+ Assert.IsTrue(zf.TestArchive(true));
+ }
+ }
+ }
+
+ [TestFixture]
+ public class NameHandling : ZipBase
+ {
+ private void TestFile(ZipNameTransform t, string original, string expected)
+ {
+ var transformed = t.TransformFile(original);
+ Assert.AreEqual(expected, transformed, "Should be equal");
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void Basic()
+ {
+ var t = new ZipNameTransform();
+
+ TestFile(t, "abcdef", "abcdef");
+ TestFile(t, @"\\uncpath\d1\file1", "file1");
+ TestFile(t, @"C:\absolute\file2", "absolute/file2");
+
+ // This is ignored but could be converted to 'file3'
+ TestFile(t, @"./file3", "./file3");
+
+ // The following relative paths cant be handled and are ignored
+ TestFile(t, @"../file3", "../file3");
+ TestFile(t, @".../file3", ".../file3");
+
+ // Trick filenames.
+ TestFile(t, @".....file3", ".....file3");
+ }
+
+ /// <summary>
+ /// Test ZipEntry static file name cleaning methods
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void FilenameCleaning()
+ {
+ Assert.AreEqual(0, string.Compare(ZipEntry.CleanName("hello"), "hello"));
+ Assert.AreEqual(0, string.Compare(ZipEntry.CleanName(@"z:\eccles"), "eccles"));
+ Assert.AreEqual(0, string.Compare(ZipEntry.CleanName(@"\\server\share\eccles"), "eccles"));
+ Assert.AreEqual(0, string.Compare(ZipEntry.CleanName(@"\\server\share\dir\eccles"), "dir/eccles"));
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void NameTransforms()
+ {
+ INameTransform t = new ZipNameTransform(@"C:\Slippery");
+ Assert.AreEqual("Pongo/Directory/", t.TransformDirectory(@"C:\Slippery\Pongo\Directory"),
+ "Value should be trimmed and converted");
+ Assert.AreEqual("PoNgo/Directory/", t.TransformDirectory(@"c:\slipperY\PoNgo\Directory"),
+ "Trimming should be case insensitive");
+ Assert.AreEqual("slippery/Pongo/Directory/", t.TransformDirectory(@"d:\slippery\Pongo\Directory"),
+ "Trimming should be case insensitive");
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void PathalogicalNames()
+ {
+ var badName = ".*:\\zy3$";
+
+ Assert.IsFalse(ZipNameTransform.IsValidName(badName));
+
+ var t = new ZipNameTransform();
+ var result = t.TransformFile(badName);
+
+ Assert.IsTrue(ZipNameTransform.IsValidName(result));
+ }
+ }
+
+ /// <summary>
+ /// This class contains test cases for Zip compression and decompression
+ /// </summary>
+ [TestFixture]
+ public class GeneralHandling : ZipBase
+ {
+ private void AddRandomDataToEntry(ZipOutputStream zipStream, int size)
+ {
+ if (size > 0)
+ {
+ var data = new byte[size];
+ var rnd = new Random();
+ rnd.NextBytes(data);
+
+ zipStream.Write(data, 0, data.Length);
+ }
+ }
+
+ private void ExerciseZip(CompressionMethod method, int compressionLevel,
+ int size, string password, bool canSeek)
+ {
+ byte[] originalData = null;
+ var compressedData = MakeInMemoryZip(ref originalData, method, compressionLevel, size, password, canSeek);
+
+ var ms = new MemoryStream(compressedData);
+ ms.Seek(0, SeekOrigin.Begin);
+
+ using (var inStream = new ZipInputStream(ms))
+ {
+ var decompressedData = new byte[size];
+ if (password != null)
+ {
+ inStream.Password = password;
+ }
+
+ var entry2 = inStream.GetNextEntry();
+
+ if ((entry2.Flags & 8) == 0)
+ {
+ Assert.AreEqual(size, entry2.Size, "Entry size invalid");
+ }
+
+ var currentIndex = 0;
+
+ if (size > 0)
+ {
+ var count = decompressedData.Length;
+
+ while (true)
+ {
+ var numRead = inStream.Read(decompressedData, currentIndex, count);
+ if (numRead <= 0)
+ {
+ break;
+ }
+ currentIndex += numRead;
+ count -= numRead;
+ }
+ }
+
+ Assert.AreEqual(currentIndex, size, "Original and decompressed data different sizes");
+
+ if (originalData != null)
+ {
+ for (var i = 0; i < originalData.Length; ++i)
+ {
+ Assert.AreEqual(decompressedData[i], originalData[i],
+ "Decompressed data doesnt match original, compression level: " +
+ compressionLevel);
+ }
+ }
+ }
+ }
+
+ private string DescribeAttributes(FieldAttributes attributes)
+ {
+ var att = string.Empty;
+ if ((FieldAttributes.Public & attributes) != 0)
+ {
+ att = att + "Public,";
+ }
+
+ if ((FieldAttributes.Static & attributes) != 0)
+ {
+ att = att + "Static,";
+ }
+
+ if ((FieldAttributes.Literal & attributes) != 0)
+ {
+ att = att + "Literal,";
+ }
+
+ if ((FieldAttributes.HasDefault & attributes) != 0)
+ {
+ att = att + "HasDefault,";
+ }
+
+ if ((FieldAttributes.InitOnly & attributes) != 0)
+ {
+ att = att + "InitOnly,";
+ }
+
+ if ((FieldAttributes.Assembly & attributes) != 0)
+ {
+ att = att + "Assembly,";
+ }
+
+ if ((FieldAttributes.FamANDAssem & attributes) != 0)
+ {
+ att = att + "FamANDAssembly,";
+ }
+
+ if ((FieldAttributes.FamORAssem & attributes) != 0)
+ {
+ att = att + "FamORAssembly,";
+ }
+
+ if ((FieldAttributes.HasFieldMarshal & attributes) != 0)
+ {
+ att = att + "HasFieldMarshal,";
+ }
+
+ return att;
+ }
+
+ private void TestLargeZip(string tempFile, int targetFiles)
+ {
+ const int BlockSize = 4096;
+
+ var data = new byte[BlockSize];
+ byte nextValue = 0;
+ for (var i = 0; i < BlockSize; ++i)
+ {
+ nextValue = ScatterValue(nextValue);
+ data[i] = nextValue;
+ }
+
+ using (var zFile = new ZipFile(tempFile))
+ {
+ Assert.AreEqual(targetFiles, zFile.Count);
+ var readData = new byte[BlockSize];
+ int readIndex;
+ foreach (ZipEntry ze in zFile)
+ {
+ var s = zFile.GetInputStream(ze);
+ readIndex = 0;
+ while (readIndex < readData.Length)
+ {
+ readIndex += s.Read(readData, readIndex, data.Length - readIndex);
+ }
+
+ for (var ii = 0; ii < BlockSize; ++ii)
+ {
+ Assert.AreEqual(data[ii], readData[ii]);
+ }
+ }
+ zFile.Close();
+ }
+ }
+
+ // [Test]
+ // [Category("Zip")]
+ // [Category("CreatesTempFile")]
+ public void TestLargeZipFile()
+ {
+ var tempFile = @"g:\\tmp";
+ tempFile = Path.Combine(tempFile, "SharpZipTest.Zip");
+ TestLargeZip(tempFile, 8100);
+ }
+
+ // [Test]
+ // [Category("Zip")]
+ // [Category("CreatesTempFile")]
+ public void MakeLargeZipFile()
+ {
+ string tempFile = null;
+ try
+ {
+ // tempFile = Path.GetTempPath();
+ tempFile = @"g:\\tmp";
+ }
+ catch (SecurityException)
+ {
+ }
+
+ Assert.IsNotNull(tempFile, "No permission to execute this test?");
+
+ if (tempFile != null)
+ {
+ const int blockSize = 4096;
+
+ var data = new byte[blockSize];
+ byte nextValue = 0;
+ for (var i = 0; i < blockSize; ++i)
+ {
+ nextValue = ScatterValue(nextValue);
+ data[i] = nextValue;
+ }
+
+ tempFile = Path.Combine(tempFile, "SharpZipTest.Zip");
+ Console.WriteLine("Starting at {0}", DateTime.Now);
+ try
+ {
+ // MakeZipFile(tempFile, new String[] {"1", "2" }, int.MaxValue, "C1");
+ using (var fs = File.Create(tempFile))
+ {
+ var zOut = new ZipOutputStream(fs);
+ zOut.SetLevel(4);
+ const int TargetFiles = 8100;
+ for (var i = 0; i < TargetFiles; ++i)
+ {
+ var e = new ZipEntry(i.ToString());
+ e.CompressionMethod = CompressionMethod.Stored;
+
+ zOut.PutNextEntry(e);
+ for (var block = 0; block < 128; ++block)
+ {
+ zOut.Write(data, 0, blockSize);
+ }
+ }
+ zOut.Close();
+ fs.Close();
+
+ TestLargeZip(tempFile, TargetFiles);
+ }
+ }
+ finally
+ {
+ Console.WriteLine("Starting at {0}", DateTime.Now);
+ // File.Delete(tempFile);
+ }
+ }
+ }
+
+ private byte[] ZipZeroLength(ISerializable data)
+ {
+ var formatter = new XmlFormatter();
+ var memStream = new MemoryStream();
+
+ using (var zipStream = new ZipOutputStream(memStream))
+ {
+ zipStream.PutNextEntry(new ZipEntry("data"));
+ formatter.Serialize(zipStream, data);
+ zipStream.CloseEntry();
+ zipStream.Close();
+ }
+
+ var result = memStream.ToArray();
+ memStream.Close();
+
+ return result;
+ }
+
+ private ISerializable UnZipZeroLength(byte[] zipped)
+ {
+ if (zipped == null)
+ {
+ return null;
+ }
+
+ object result = null;
+ var formatter = new XmlFormatter();
+ var memStream = new MemoryStream(zipped);
+ using (var zipStream = new ZipInputStream(memStream))
+ {
+ var zipEntry = zipStream.GetNextEntry();
+ if (zipEntry != null)
+ {
+ result = formatter.Deserialize(zipStream);
+ }
+ zipStream.Close();
+ }
+ memStream.Close();
+
+ return (ISerializable)result;
+ }
+
+ private void CheckNameConversion(string toCheck)
+ {
+ var intermediate = ZipConstants.ConvertToArray(toCheck);
+ var final = ZipConstants.ConvertToString(intermediate);
+
+ Assert.AreEqual(toCheck, final, "Expected identical result");
+ }
+
+ /// <summary>
+ /// Adding an entry after the stream has Finished should fail
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ [ExpectedException(typeof (InvalidOperationException))]
+ public void AddEntryAfterFinish()
+ {
+ var ms = new MemoryStream();
+ var s = new ZipOutputStream(ms);
+ s.Finish();
+ s.PutNextEntry(new ZipEntry("dummyfile.tst"));
+ }
+
+ /// <summary>
+ /// Basic compress/decompress test, no encryption, size is important here as its big enough
+ /// to force multiple write to output which was a problem...
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void BasicDeflated()
+ {
+ for (var i = 0; i <= 9; ++i)
+ {
+ ExerciseZip(CompressionMethod.Deflated, i, 50000, null, true);
+ }
+ }
+
+ /// <summary>
+ /// Basic compress/decompress test, with encryption, size is important here as its big enough
+ /// to force multiple write to output which was a problem...
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void BasicDeflatedEncrypted()
+ {
+ for (var i = 0; i <= 9; ++i)
+ {
+ ExerciseZip(CompressionMethod.Deflated, i, 50000, "Rosebud", true);
+ }
+ }
+
+ /// <summary>
+ /// Basic compress/decompress test, with encryption, size is important here as its big enough
+ /// to force multiple write to output which was a problem...
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void BasicDeflatedEncryptedNonSeekable()
+ {
+ for (var i = 0; i <= 9; ++i)
+ {
+ ExerciseZip(CompressionMethod.Deflated, i, 50000, "Rosebud", false);
+ }
+ }
+
+ /// <summary>
+ /// Basic compress/decompress test, no encryption, size is important here as its big enough
+ /// to force multiple write to output which was a problem...
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void BasicDeflatedNonSeekable()
+ {
+ for (var i = 0; i <= 9; ++i)
+ {
+ ExerciseZip(CompressionMethod.Deflated, i, 50000, null, false);
+ }
+ }
+
+ /// <summary>
+ /// Basic stored file test, no encryption.
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void BasicStored()
+ {
+ ExerciseZip(CompressionMethod.Stored, 0, 50000, null, true);
+ }
+
+ /// <summary>
+ /// Basic stored file test, with encryption.
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void BasicStoredEncrypted()
+ {
+ ExerciseZip(CompressionMethod.Stored, 0, 50000, "Rosebud", true);
+ }
+
+ /// <summary>
+ /// Basic stored file test, with encryption, non seekable output.
+ /// NOTE this gets converted deflate level 0
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void BasicStoredEncryptedNonSeekable()
+ {
+ ExerciseZip(CompressionMethod.Stored, 0, 50000, "Rosebud", false);
+ }
+
+ /// <summary>
+ /// Basic stored file test, no encryption, non seekable output
+ /// NOTE this gets converted to deflate level 0
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void BasicStoredNonSeekable()
+ {
+ ExerciseZip(CompressionMethod.Stored, 0, 50000, null, false);
+ }
+
+ /// <summary>
+ /// Check that simply closing ZipOutputStream finishes the zip correctly
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void CloseOnlyHandled()
+ {
+ var ms = new MemoryStream();
+ var s = new ZipOutputStream(ms);
+ s.PutNextEntry(new ZipEntry("dummyfile.tst"));
+ s.Close();
+
+ Assert.IsTrue(s.IsFinished, "Output stream should be finished");
+ }
+
+ /// <summary>
+ /// Check that GetNextEntry can handle the situation where part of the entry data has been read
+ /// before the call is made. ZipInputStream.CloseEntry wasnt handling this at all.
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void ExerciseGetNextEntry()
+ {
+ var compressedData = MakeInMemoryZip(
+ true,
+ new RuntimeInfo(CompressionMethod.Deflated, 9, 50, null, true),
+ new RuntimeInfo(CompressionMethod.Deflated, 2, 50, null, true),
+ new RuntimeInfo(CompressionMethod.Deflated, 9, 50, null, true),
+ new RuntimeInfo(CompressionMethod.Deflated, 2, 50, null, true),
+ new RuntimeInfo(null, true),
+ new RuntimeInfo(CompressionMethod.Stored, 2, 50, null, true),
+ new RuntimeInfo(CompressionMethod.Deflated, 9, 50, null, true)
+ );
+
+ var ms = new MemoryStream(compressedData);
+ ms.Seek(0, SeekOrigin.Begin);
+
+ using (var inStream = new ZipInputStream(ms))
+ {
+ var buffer = new byte[10];
+
+ ZipEntry entry;
+ while ((entry = inStream.GetNextEntry()) != null)
+ {
+ // Read a portion of the data, so GetNextEntry has some work to do.
+ inStream.Read(buffer, 0, 10);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Invalid passwords should be detected early if possible, non seekable stream
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ [ExpectedException(typeof (ZipException))]
+ public void InvalidPasswordNonSeekable()
+ {
+ byte[] originalData = null;
+ var compressedData = MakeInMemoryZip(ref originalData, CompressionMethod.Deflated, 3, 500, "Hola", false);
+
+ var ms = new MemoryStream(compressedData);
+ ms.Seek(0, SeekOrigin.Begin);
+
+ var buf2 = new byte[originalData.Length];
+ var pos = 0;
+
+ var inStream = new ZipInputStream(ms);
+ inStream.Password = "redhead";
+
+ var entry2 = inStream.GetNextEntry();
+
+ while (true)
+ {
+ var numRead = inStream.Read(buf2, pos, buf2.Length);
+ if (numRead <= 0)
+ {
+ break;
+ }
+ pos += numRead;
+ }
+ }
+
+ /// <summary>
+ /// Invalid passwords should be detected early if possible, seekable stream
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ [ExpectedException(typeof (ZipException))]
+ public void InvalidPasswordSeekable()
+ {
+ byte[] originalData = null;
+ var compressedData = MakeInMemoryZip(ref originalData, CompressionMethod.Deflated, 3, 500, "Hola", true);
+
+ var ms = new MemoryStream(compressedData);
+ ms.Seek(0, SeekOrigin.Begin);
+
+ var buf2 = new byte[originalData.Length];
+ var pos = 0;
+
+ var inStream = new ZipInputStream(ms);
+ inStream.Password = "redhead";
+
+ var entry2 = inStream.GetNextEntry();
+
+ while (true)
+ {
+ var numRead = inStream.Read(buf2, pos, buf2.Length);
+ if (numRead <= 0)
+ {
+ break;
+ }
+ pos += numRead;
+ }
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void MixedEncryptedAndPlain()
+ {
+ var compressedData = MakeInMemoryZip(true,
+ new RuntimeInfo(CompressionMethod.Deflated, 2, 1, null, true),
+ new RuntimeInfo(CompressionMethod.Deflated, 9, 1, "1234", false),
+ new RuntimeInfo(CompressionMethod.Deflated, 2, 1, null, false),
+ new RuntimeInfo(CompressionMethod.Deflated, 9, 1, "1234", true)
+ );
+
+ var ms = new MemoryStream(compressedData);
+ using (var inStream = new ZipInputStream(ms))
+ {
+ inStream.Password = "1234";
+
+ var extractCount = 0;
+ var extractIndex = 0;
+ ZipEntry entry;
+ var decompressedData = new byte[100];
+
+ while ((entry = inStream.GetNextEntry()) != null)
+ {
+ extractCount = decompressedData.Length;
+ extractIndex = 0;
+ while (true)
+ {
+ var numRead = inStream.Read(decompressedData, extractIndex, extractCount);
+ if (numRead <= 0)
+ {
+ break;
+ }
+ extractIndex += numRead;
+ extractCount -= numRead;
+ }
+ }
+ inStream.Close();
+ }
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void NameConversion()
+ {
+ CheckNameConversion("Hello");
+ CheckNameConversion("a/b/c/d/e/f/g/h/SomethingLikeAnArchiveName.txt");
+ }
+
+ [Test]
+ [Category("Zip")]
+ [Category("CreatesTempFile")]
+ public void PartialStreamClosing()
+ {
+ var tempFile = GetTempFilePath();
+ Assert.IsNotNull(tempFile, "No permission to execute this test?");
+
+ if (tempFile != null)
+ {
+ tempFile = Path.Combine(tempFile, "SharpZipTest.Zip");
+ MakeZipFile(tempFile, new[]{"Farriera", "Champagne", "Urban myth"}, 10, "Aha");
+
+ using (var zipFile = new ZipFile(tempFile))
+ {
+ var stream = zipFile.GetInputStream(0);
+ stream.Close();
+
+ stream = zipFile.GetInputStream(1);
+ zipFile.Close();
+ }
+ File.Delete(tempFile);
+ }
+ }
+
+ /// <summary>
+ /// Regression test for problem where the password check would fail for an archive whose
+ /// date was updated from the extra data.
+ /// This applies to archives where the crc wasnt know at the time of encryption.
+ /// The date of the entry is used in its place.
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void PasswordCheckingWithDateInExtraData()
+ {
+ var ms = new MemoryStream();
+ var checkTime = new DateTime(2010, 10, 16, 0, 3, 28);
+
+ using (var zos = new ZipOutputStream(ms))
+ {
+ zos.IsStreamOwner = false;
+ zos.Password = "secret";
+ var ze = new ZipEntry("uno");
+ ze.DateTime = new DateTime(1998, 6, 5, 4, 3, 2);
+
+ var zed = new ZipExtraData();
+
+ zed.StartNewEntry();
+
+ zed.AddData(1);
+
+ var delta = checkTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();
+ var seconds = (int) delta.TotalSeconds;
+ zed.AddLeInt(seconds);
+ zed.AddNewEntry(0x5455);
+
+ ze.ExtraData = zed.GetEntryData();
+ zos.PutNextEntry(ze);
+ zos.WriteByte(54);
+ }
+
+ ms.Position = 0;
+ using (var zis = new ZipInputStream(ms))
+ {
+ zis.Password = "secret";
+ var uno = zis.GetNextEntry();
+ var theByte = (byte) zis.ReadByte();
+ Assert.AreEqual(54, theByte);
+ Assert.AreEqual(-1, zis.ReadByte());
+ Assert.AreEqual(checkTime, uno.DateTime);
+ }
+ }
+
+ /// <summary>
+ /// Test for handling of serialized reference and value objects.
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void SerializedObject()
+ {
+ var sampleDateTime = new SerializableDateTime(1853, 8, 26);
+ ISerializable data = sampleDateTime;
+
+ var zipped = ZipZeroLength(data);
+ var rawObject = UnZipZeroLength(zipped);
+
+ var returnedDateTime = (SerializableDateTime) rawObject;
+
+ Assert.AreEqual(sampleDateTime, returnedDateTime);
+
+ var sampleString = new SerializableString("Mary had a giant cat its ears were green and smelly");
+ zipped = ZipZeroLength(sampleString);
+
+ rawObject = UnZipZeroLength(zipped);
+
+ var returnedString = rawObject as SerializableString;
+
+ Assert.AreEqual(sampleString, returnedString);
+ }
+
+ /// <summary>
+ /// Test for handling of zero lengths in compression using a formatter which
+ /// will request reads of zero length...
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void SerializedObjectZeroLength()
+ {
+// object data = new SerializableByteArray[0];
+// // This wont be zero length here due to serialisation.
+// var zipped = ZipZeroLength(data);
+// var o = UnZipZeroLength(zipped);
+//
+// var returned = o as byte[];
+//
+// Assert.IsNotNull(returned, "Expected a byte[]");
+// Assert.AreEqual(0, returned.Length);
+ }
+
+ /// <summary>
+ /// Test setting file commment to a value that is too long
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ [ExpectedException(typeof (ArgumentOutOfRangeException))]
+ public void SetCommentOversize()
+ {
+ var ms = new MemoryStream();
+ var s = new ZipOutputStream(ms);
+ s.SetComment(new String('A', 65536));
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void SkipEncryptedEntriesWithoutSettingPassword()
+ {
+ var compressedData = MakeInMemoryZip(true,
+ new RuntimeInfo("1234", true),
+ new RuntimeInfo(CompressionMethod.Deflated, 2, 1, null, true),
+ new RuntimeInfo(CompressionMethod.Deflated, 9, 1, "1234", true),
+ new RuntimeInfo(CompressionMethod.Deflated, 2, 1, null, true),
+ new RuntimeInfo(null, true),
+ new RuntimeInfo(CompressionMethod.Stored, 2, 1, "4321", true),
+ new RuntimeInfo(CompressionMethod.Deflated, 9, 1, "1234", true)
+ );
+
+ var ms = new MemoryStream(compressedData);
+ var inStream = new ZipInputStream(ms);
+
+ ZipEntry entry;
+ while ((entry = inStream.GetNextEntry()) != null)
+ {
+ }
+
+ inStream.Close();
+ }
+
+ /// <summary>
+ /// Check that when the output stream cannot seek that requests for stored
+ /// are in fact converted to defalted level 0
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void StoredNonSeekableConvertToDeflate()
+ {
+ var ms = new MemoryStreamWithoutSeek();
+
+ var outStream = new ZipOutputStream(ms);
+ outStream.SetLevel(8);
+ Assert.AreEqual(8, outStream.GetLevel(), "Compression level invalid");
+
+ var entry = new ZipEntry("1.tst");
+ entry.CompressionMethod = CompressionMethod.Stored;
+ outStream.PutNextEntry(entry);
+ Assert.AreEqual(0, outStream.GetLevel(), "Compression level invalid");
+
+ AddRandomDataToEntry(outStream, 100);
+ entry = new ZipEntry("2.tst");
+ entry.CompressionMethod = CompressionMethod.Deflated;
+ outStream.PutNextEntry(entry);
+ Assert.AreEqual(8, outStream.GetLevel(), "Compression level invalid");
+ AddRandomDataToEntry(outStream, 100);
+
+ outStream.Close();
+ }
+
+ /// <summary>
+ /// Check that adding more than the 2.0 limit for entry numbers is detected and handled
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ [Category("Long Running")]
+ public void Stream_64KPlusOneEntries()
+ {
+ const int target = 65537;
+ var ms = new MemoryStream();
+ using (var s = new ZipOutputStream(ms))
+ {
+ for (var i = 0; i < target; ++i)
+ {
+ s.PutNextEntry(new ZipEntry("dummyfile.tst"));
+ }
+
+ s.Finish();
+ ms.Seek(0, SeekOrigin.Begin);
+ using (var zipFile = new ZipFile(ms))
+ {
+ Assert.AreEqual(target, zipFile.Count, "Incorrect number of entries stored");
+ }
+ }
+ }
+
+ /// <summary>
+ /// Check that Unicode filename support works.
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void Stream_UnicodeEntries()
+ {
+ var ms = new MemoryStream();
+ using (var s = new ZipOutputStream(ms))
+ {
+ s.IsStreamOwner = false;
+
+ var sampleName = "\u03A5\u03d5\u03a3";
+ var sample = new ZipEntry(sampleName);
+ sample.IsUnicodeText = true;
+ s.PutNextEntry(sample);
+
+ s.Finish();
+ ms.Seek(0, SeekOrigin.Begin);
+
+ using (var zis = new ZipInputStream(ms))
+ {
+ var ze = zis.GetNextEntry();
+ Assert.AreEqual(sampleName, ze.Name, "Expected name to match original");
+ Assert.IsTrue(ze.IsUnicodeText, "Expected IsUnicodeText flag to be set");
+ }
+ }
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void UnicodeNameConversion()
+ {
+ var sample = "Hello world";
+
+ byte[] rawData = Encoding.UTF8.GetBytes(sample);
+
+ var converted = ZipConstants.ConvertToStringExt(0, rawData);
+ Assert.AreEqual(sample, converted);
+
+ converted = ZipConstants.ConvertToStringExt((int) GeneralBitFlags.UnicodeText, rawData);
+ Assert.AreEqual(sample, converted);
+
+ // This time use some greek characters
+ sample = "\u03A5\u03d5\u03a3";
+ rawData = Encoding.UTF8.GetBytes(sample);
+
+ converted = ZipConstants.ConvertToStringExt((int) GeneralBitFlags.UnicodeText, rawData);
+ Assert.AreEqual(sample, converted);
+ }
+
+ [Test]
+ [Category("Zip")]
+ [ExpectedException(typeof (NotSupportedException))]
+ public void UnsupportedCompressionMethod()
+ {
+ var ze = new ZipEntry("HumblePie");
+ var type = typeof (CompressionMethod);
+ // System.Reflection.FieldInfo[] info = type.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
+ var info = type.GetFields();
+
+ var aValue = CompressionMethod.Deflated;
+ for (var i = 0; i < info.Length; i++)
+ {
+ var attributes = info[i].Attributes;
+ DescribeAttributes(attributes);
+ if ((FieldAttributes.Static & attributes) != 0)
+ {
+ var obj = info[i].GetValue(null);
+ var bb = obj.ToString();
+ if (bb == null)
+ {
+ throw new Exception();
+ }
+ }
+ var x = string.Format("The value of {0} is: {1}",
+ info[i].Name, info[i].GetValue(aValue));
+ }
+
+ ze.CompressionMethod = CompressionMethod.BZip2;
+ }
+ }
+
+ [TestFixture]
+ public class ZipExtraDataHandling : ZipBase
+ {
+ [Test]
+ [Category("Zip")]
+ public void BasicOperations()
+ {
+ var zed = new ZipExtraData(null);
+ Assert.AreEqual(0, zed.Length);
+
+ zed = new ZipExtraData(new byte[]{1, 0, 0, 0});
+ Assert.AreEqual(4, zed.Length, "A length should be 4");
+
+ var zed2 = new ZipExtraData();
+ Assert.AreEqual(0, zed2.Length);
+
+ zed2.AddEntry(1, new byte[]{});
+
+ var data = zed.GetEntryData();
+ for (var i = 0; i < data.Length; ++i)
+ {
+ Assert.AreEqual(zed2.GetEntryData()[i], data[i]);
+ }
+
+ Assert.AreEqual(4, zed2.Length, "A1 length should be 4");
+
+ var findResult = zed.Find(2);
+ Assert.IsFalse(findResult, "A - Shouldnt find tag 2");
+
+ findResult = zed.Find(1);
+ Assert.IsTrue(findResult, "A - Should find tag 1");
+ Assert.AreEqual(0, zed.ValueLength, "A- Length of entry should be 0");
+ Assert.AreEqual(-1, zed.ReadByte());
+ Assert.AreEqual(0, zed.GetStreamForTag(1).Length, "A - Length of stream should be 0");
+
+ zed = new ZipExtraData(new byte[]{1, 0, 3, 0, 1, 2, 3});
+ Assert.AreEqual(7, zed.Length, "Expected a length of 7");
+
+ findResult = zed.Find(1);
+ Assert.IsTrue(findResult, "B - Should find tag 1");
+ Assert.AreEqual(3, zed.ValueLength, "B - Length of entry should be 3");
+ for (var i = 1; i <= 3; ++i)
+ {
+ Assert.AreEqual(i, zed.ReadByte());
+ }
+ Assert.AreEqual(-1, zed.ReadByte());
+
+ var s = zed.GetStreamForTag(1);
+ Assert.AreEqual(3, s.Length, "B.1 Stream length should be 3");
+ for (var i = 1; i <= 3; ++i)
+ {
+ Assert.AreEqual(i, s.ReadByte());
+ }
+ Assert.AreEqual(-1, s.ReadByte());
+
+ zed = new ZipExtraData(new byte[]{1, 0, 3, 0, 1, 2, 3, 2, 0, 1, 0, 56});
+ Assert.AreEqual(12, zed.Length, "Expected a length of 12");
+
+ findResult = zed.Find(1);
+ Assert.IsTrue(findResult, "C.1 - Should find tag 1");
+ Assert.AreEqual(3, zed.ValueLength, "C.1 - Length of entry should be 3");
+ for (var i = 1; i <= 3; ++i)
+ {
+ Assert.AreEqual(i, zed.ReadByte());
+ }
+ Assert.AreEqual(-1, zed.ReadByte());
+
+ findResult = zed.Find(2);
+ Assert.IsTrue(findResult, "C.2 - Should find tag 2");
+ Assert.AreEqual(1, zed.ValueLength, "C.2 - Length of entry should be 1");
+ Assert.AreEqual(56, zed.ReadByte());
+ Assert.AreEqual(-1, zed.ReadByte());
+
+ s = zed.GetStreamForTag(2);
+ Assert.AreEqual(1, s.Length);
+ Assert.AreEqual(56, s.ReadByte());
+ Assert.AreEqual(-1, s.ReadByte());
+
+ zed = new ZipExtraData();
+ zed.AddEntry(7, new byte[]{33, 44, 55});
+ findResult = zed.Find(7);
+ Assert.IsTrue(findResult, "Add.1 should find new tag");
+ Assert.AreEqual(3, zed.ValueLength, "Add.1 length should be 3");
+ Assert.AreEqual(33, zed.ReadByte());
+ Assert.AreEqual(44, zed.ReadByte());
+ Assert.AreEqual(55, zed.ReadByte());
+ Assert.AreEqual(-1, zed.ReadByte());
+
+ zed.AddEntry(7, null);
+ findResult = zed.Find(7);
+ Assert.IsTrue(findResult, "Add.2 should find new tag");
+ Assert.AreEqual(0, zed.ValueLength, "Add.2 length should be 0");
+
+ zed.StartNewEntry();
+ zed.AddData(0xae);
+ zed.AddNewEntry(55);
+
+ findResult = zed.Find(55);
+ Assert.IsTrue(findResult, "Add.3 should find new tag");
+ Assert.AreEqual(1, zed.ValueLength, "Add.3 length should be 1");
+ Assert.AreEqual(0xae, zed.ReadByte());
+ Assert.AreEqual(-1, zed.ReadByte());
+
+ zed = new ZipExtraData();
+ zed.StartNewEntry();
+ zed.AddLeLong(0);
+ zed.AddLeLong(-4);
+ zed.AddLeLong(-1);
+ zed.AddLeLong(long.MaxValue);
+ zed.AddLeLong(long.MinValue);
+ zed.AddLeLong(0x123456789ABCDEF0);
+ zed.AddLeLong(unchecked((long) 0xFEDCBA9876543210));
+ zed.AddNewEntry(567);
+
+ s = zed.GetStreamForTag(567);
+ var longValue = ReadLong(s);
+ Assert.AreEqual(longValue, zed.ReadLong(), "Read/stream mismatch");
+ Assert.AreEqual(0, longValue, "Expected long value of zero");
+
+ longValue = ReadLong(s);
+ Assert.AreEqual(longValue, zed.ReadLong(), "Read/stream mismatch");
+ Assert.AreEqual(-4, longValue, "Expected long value of -4");
+
+ longValue = ReadLong(s);
+ Assert.AreEqual(longValue, zed.ReadLong(), "Read/stream mismatch");
+ Assert.AreEqual(-1, longValue, "Expected long value of -1");
+
+ longValue = ReadLong(s);
+ Assert.AreEqual(longValue, zed.ReadLong(), "Read/stream mismatch");
+ Assert.AreEqual(long.MaxValue, longValue, "Expected long value of MaxValue");
+
+ longValue = ReadLong(s);
+ Assert.AreEqual(longValue, zed.ReadLong(), "Read/stream mismatch");
+ Assert.AreEqual(long.MinValue, longValue, "Expected long value of MinValue");
+
+ longValue = ReadLong(s);
+ Assert.AreEqual(longValue, zed.ReadLong(), "Read/stream mismatch");
+ Assert.AreEqual(0x123456789abcdef0, longValue, "Expected long value of MinValue");
+
+ longValue = ReadLong(s);
+ Assert.AreEqual(longValue, zed.ReadLong(), "Read/stream mismatch");
+ Assert.AreEqual(unchecked((long) 0xFEDCBA9876543210), longValue, "Expected long value of MinValue");
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void Deleting()
+ {
+ var zed = new ZipExtraData();
+ Assert.AreEqual(0, zed.Length);
+
+ // Tag 1 Totoal length 10
+ zed.AddEntry(1, new byte[]{10, 11, 12, 13, 14, 15});
+ Assert.AreEqual(10, zed.Length, "Length should be 10");
+ Assert.AreEqual(10, zed.GetEntryData().Length, "Data length should be 10");
+
+ // Tag 2 total length 9
+ zed.AddEntry(2, new byte[]{20, 21, 22, 23, 24});
+ Assert.AreEqual(19, zed.Length, "Length should be 19");
+ Assert.AreEqual(19, zed.GetEntryData().Length, "Data length should be 19");
+
+ // Tag 3 Total Length 6
+ zed.AddEntry(3, new byte[]{30, 31});
+ Assert.AreEqual(25, zed.Length, "Length should be 25");
+ Assert.AreEqual(25, zed.GetEntryData().Length, "Data length should be 25");
+
+ zed.Delete(2);
+ Assert.AreEqual(16, zed.Length, "Length should be 16");
+ Assert.AreEqual(16, zed.GetEntryData().Length, "Data length should be 16");
+
+ // Tag 2 total length 9
+ zed.AddEntry(2, new byte[]{20, 21, 22, 23, 24});
+ Assert.AreEqual(25, zed.Length, "Length should be 25");
+ Assert.AreEqual(25, zed.GetEntryData().Length, "Data length should be 25");
+
+ zed.AddEntry(3, null);
+ Assert.AreEqual(23, zed.Length, "Length should be 23");
+ Assert.AreEqual(23, zed.GetEntryData().Length, "Data length should be 23");
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void ExceedSize()
+ {
+ var zed = new ZipExtraData();
+ var buffer = new byte[65506];
+ zed.AddEntry(1, buffer);
+ Assert.AreEqual(65510, zed.Length);
+ zed.AddEntry(2, new byte[21]);
+ Assert.AreEqual(65535, zed.Length);
+
+ var caught = false;
+ try
+ {
+ zed.AddEntry(3, null);
+ }
+ catch
+ {
+ caught = true;
+ }
+ Assert.IsTrue(caught, "Expected an exception when max size exceeded");
+ Assert.AreEqual(65535, zed.Length);
+
+ zed.Delete(2);
+ Assert.AreEqual(65510, zed.Length);
+
+ caught = false;
+ try
+ {
+ zed.AddEntry(2, new byte[22]);
+ }
+ catch
+ {
+ caught = true;
+ }
+ Assert.IsTrue(caught, "Expected an exception when max size exceeded");
+ Assert.AreEqual(65510, zed.Length);
+ }
+
+ /// <summary>
+ /// Extra data for separate entries should be unique to that entry
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void IsDataUnique()
+ {
+ var a = new ZipEntry("Basil");
+ var extra = new byte[4];
+ extra[0] = 27;
+ a.ExtraData = extra;
+
+ var b = (ZipEntry) a.Clone();
+ b.ExtraData[0] = 89;
+ Assert.IsTrue(b.ExtraData[0] != a.ExtraData[0],
+ "Extra data not unique " + b.ExtraData[0] + " " + a.ExtraData[0]);
+
+ var c = (ZipEntry) a.Clone();
+ c.ExtraData[0] = 45;
+ Assert.IsTrue(a.ExtraData[0] != c.ExtraData[0],
+ "Extra data not unique " + a.ExtraData[0] + " " + c.ExtraData[0]);
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void ReadOverrunInt()
+ {
+ var zed = new ZipExtraData(new byte[]{1, 0, 0, 0});
+ Assert.AreEqual(4, zed.Length, "Length should be 4");
+ Assert.IsTrue(zed.Find(1), "Should find tag 1");
+
+ // Empty Tag
+ var exceptionCaught = false;
+ try
+ {
+ zed.ReadInt();
+ }
+ catch (ZipException)
+ {
+ exceptionCaught = true;
+ }
+ Assert.IsTrue(exceptionCaught, "Expected EOS exception");
+
+ // three bytes
+ zed = new ZipExtraData(new byte[]{1, 0, 3, 0, 1, 2, 3});
+ Assert.IsTrue(zed.Find(1), "Should find tag 1");
+
+ exceptionCaught = false;
+ try
+ {
+ zed.ReadInt();
+ }
+ catch (ZipException)
+ {
+ exceptionCaught = true;
+ }
+ Assert.IsTrue(exceptionCaught, "Expected EOS exception");
+
+ zed = new ZipExtraData(new byte[]{1, 0, 7, 0, 1, 2, 3, 4, 5, 6, 7});
+ Assert.IsTrue(zed.Find(1), "Should find tag 1");
+
+ zed.ReadInt();
+
+ exceptionCaught = false;
+ try
+ {
+ zed.ReadInt();
+ }
+ catch (ZipException)
+ {
+ exceptionCaught = true;
+ }
+ Assert.IsTrue(exceptionCaught, "Expected EOS exception");
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void ReadOverrunLong()
+ {
+ var zed = new ZipExtraData(new byte[]{1, 0, 0, 0});
+ Assert.AreEqual(4, zed.Length, "Length should be 4");
+ Assert.IsTrue(zed.Find(1), "Should find tag 1");
+
+ // Empty Tag
+ var exceptionCaught = false;
+ try
+ {
+ zed.ReadLong();
+ }
+ catch (ZipException)
+ {
+ exceptionCaught = true;
+ }
+ Assert.IsTrue(exceptionCaught, "Expected EOS exception");
+
+ // seven bytes
+ zed = new ZipExtraData(new byte[]{1, 0, 7, 0, 1, 2, 3, 4, 5, 6, 7});
+ Assert.IsTrue(zed.Find(1), "Should find tag 1");
+
+ exceptionCaught = false;
+ try
+ {
+ zed.ReadLong();
+ }
+ catch (ZipException)
+ {
+ exceptionCaught = true;
+ }
+ Assert.IsTrue(exceptionCaught, "Expected EOS exception");
+
+ zed = new ZipExtraData(new byte[]{1, 0, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15});
+ Assert.IsTrue(zed.Find(1), "Should find tag 1");
+
+ zed.ReadLong();
+
+ exceptionCaught = false;
+ try
+ {
+ zed.ReadLong();
+ }
+ catch (ZipException)
+ {
+ exceptionCaught = true;
+ }
+ Assert.IsTrue(exceptionCaught, "Expected EOS exception");
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void ReadOverrunShort()
+ {
+ var zed = new ZipExtraData(new byte[]{1, 0, 0, 0});
+ Assert.AreEqual(4, zed.Length, "Length should be 4");
+ Assert.IsTrue(zed.Find(1), "Should find tag 1");
+
+ // Empty Tag
+ var exceptionCaught = false;
+ try
+ {
+ zed.ReadShort();
+ }
+ catch (ZipException)
+ {
+ exceptionCaught = true;
+ }
+ Assert.IsTrue(exceptionCaught, "Expected EOS exception");
+
+ // Single byte
+ zed = new ZipExtraData(new byte[]{1, 0, 1, 0, 1});
+ Assert.IsTrue(zed.Find(1), "Should find tag 1");
+
+ exceptionCaught = false;
+ try
+ {
+ zed.ReadShort();
+ }
+ catch (ZipException)
+ {
+ exceptionCaught = true;
+ }
+ Assert.IsTrue(exceptionCaught, "Expected EOS exception");
+
+ zed = new ZipExtraData(new byte[]{1, 0, 2, 0, 1, 2});
+ Assert.IsTrue(zed.Find(1), "Should find tag 1");
+
+ zed.ReadShort();
+
+ exceptionCaught = false;
+ try
+ {
+ zed.ReadShort();
+ }
+ catch (ZipException)
+ {
+ exceptionCaught = true;
+ }
+ Assert.IsTrue(exceptionCaught, "Expected EOS exception");
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void Skipping()
+ {
+ var zed = new ZipExtraData(new byte[]{1, 0, 7, 0, 1, 2, 3, 4, 5, 6, 7});
+ Assert.AreEqual(11, zed.Length, "Length should be 11");
+ Assert.IsTrue(zed.Find(1), "Should find tag 1");
+
+ Assert.AreEqual(7, zed.UnreadCount);
+ Assert.AreEqual(4, zed.CurrentReadIndex);
+
+ zed.ReadByte();
+ Assert.AreEqual(6, zed.UnreadCount);
+ Assert.AreEqual(5, zed.CurrentReadIndex);
+
+ zed.Skip(1);
+ Assert.AreEqual(5, zed.UnreadCount);
+ Assert.AreEqual(6, zed.CurrentReadIndex);
+
+ zed.Skip(-1);
+ Assert.AreEqual(6, zed.UnreadCount);
+ Assert.AreEqual(5, zed.CurrentReadIndex);
+
+ zed.Skip(6);
+ Assert.AreEqual(0, zed.UnreadCount);
+ Assert.AreEqual(11, zed.CurrentReadIndex);
+
+ var exceptionCaught = false;
+
+ try
+ {
+ zed.Skip(1);
+ }
+ catch (ZipException)
+ {
+ exceptionCaught = true;
+ }
+ Assert.IsTrue(exceptionCaught, "Should fail to skip past end");
+
+ Assert.AreEqual(0, zed.UnreadCount);
+ Assert.AreEqual(11, zed.CurrentReadIndex);
+
+ zed.Skip(-7);
+ Assert.AreEqual(7, zed.UnreadCount);
+ Assert.AreEqual(4, zed.CurrentReadIndex);
+
+ try
+ {
+ zed.Skip(-1);
+ }
+ catch (ZipException)
+ {
+ exceptionCaught = true;
+ }
+ Assert.IsTrue(exceptionCaught, "Should fail to skip before beginning");
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void TaggedDataHandling()
+ {
+ var tagData = new NTTaggedData();
+ var modTime = tagData.LastModificationTime;
+ var rawData = tagData.GetData();
+ tagData.LastModificationTime = tagData.LastModificationTime + TimeSpan.FromSeconds(40);
+ tagData.SetData(rawData, 0, rawData.Length);
+ Assert.AreEqual(10, tagData.TagID, "TagID mismatch");
+ Assert.AreEqual(modTime, tagData.LastModificationTime, "NT Mod time incorrect");
+
+ tagData.CreateTime = DateTime.FromFileTimeUtc(0);
+ tagData.LastAccessTime = new DateTime(9999, 12, 31, 23, 59, 59);
+ rawData = tagData.GetData();
+
+ var unixData = new ExtendedUnixData();
+ modTime = unixData.ModificationTime;
+ unixData.ModificationTime = modTime; // Ensure flag is set.
+
+ rawData = unixData.GetData();
+ unixData.ModificationTime += TimeSpan.FromSeconds(100);
+ unixData.SetData(rawData, 0, rawData.Length);
+ Assert.AreEqual(0x5455, unixData.TagID, "TagID mismatch");
+ Assert.AreEqual(modTime, unixData.ModificationTime, "Unix mod time incorrect");
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void UnreadCountValid()
+ {
+ var zed = new ZipExtraData(new byte[]{1, 0, 0, 0});
+ Assert.AreEqual(4, zed.Length, "Length should be 4");
+ Assert.IsTrue(zed.Find(1), "Should find tag 1");
+ Assert.AreEqual(0, zed.UnreadCount);
+
+ // seven bytes
+ zed = new ZipExtraData(new byte[]{1, 0, 7, 0, 1, 2, 3, 4, 5, 6, 7});
+ Assert.IsTrue(zed.Find(1), "Should find tag 1");
+
+ for (var i = 0; i < 7; ++i)
+ {
+ Assert.AreEqual(7 - i, zed.UnreadCount);
+ zed.ReadByte();
+ }
+
+ zed.ReadByte();
+ Assert.AreEqual(0, zed.UnreadCount);
+ }
+ }
+
+ [TestFixture]
+ public class FastZipHandling : ZipBase
+ {
+ private const string ZipTempDir = "SharpZipLibTest";
+
+ private void EnsureTestDirectoryIsEmpty(string baseDir)
+ {
+ var name = Path.Combine(baseDir, ZipTempDir);
+
+ if (Directory.Exists(name))
+ {
+ Directory.Delete(name, true);
+ }
+
+ Directory.CreateDirectory(name);
+ }
+
+ [Test]
+ [Category("Zip")]
+ [Category("CreatesTempFile")]
+ public void Basics()
+ {
+ const string tempName1 = "a.dat";
+
+ var target = new MemoryStream();
+
+ var tempFilePath = GetTempFilePath();
+ Assert.IsNotNull(tempFilePath, "No permission to execute this test?");
+
+ var addFile = Path.Combine(tempFilePath, tempName1);
+ MakeTempFile(addFile, 1);
+
+ try
+ {
+ var fastZip = new FastZip();
+ fastZip.CreateZip(target, tempFilePath, false, @"a\.dat", null);
+
+ var archive = new MemoryStream(target.ToArray());
+ using (var zf = new ZipFile(archive))
+ {
+ Assert.AreEqual(1, zf.Count);
+ var entry = zf[0];
+ Assert.AreEqual(tempName1, entry.Name);
+ Assert.AreEqual(1, entry.Size);
+ Assert.IsTrue(zf.TestArchive(true));
+
+ zf.Close();
+ }
+ }
+ finally
+ {
+ File.Delete(tempName1);
+ }
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void Encryption()
+ {
+ const string tempName1 = "a.dat";
+
+ var target = new MemoryStream();
+
+ var tempFilePath = GetTempFilePath();
+ Assert.IsNotNull(tempFilePath, "No permission to execute this test?");
+
+ var addFile = Path.Combine(tempFilePath, tempName1);
+ MakeTempFile(addFile, 1);
+
+ try
+ {
+ var fastZip = new FastZip();
+ fastZip.Password = "Ahoy";
+
+ fastZip.CreateZip(target, tempFilePath, false, @"a\.dat", null);
+
+ var archive = new MemoryStream(target.ToArray());
+ using (var zf = new ZipFile(archive))
+ {
+ zf.Password = "Ahoy";
+ Assert.AreEqual(1, zf.Count);
+ var entry = zf[0];
+ Assert.AreEqual(tempName1, entry.Name);
+ Assert.AreEqual(1, entry.Size);
+ Assert.IsTrue(zf.TestArchive(true));
+ Assert.IsTrue(entry.IsCrypted);
+ }
+ }
+ finally
+ {
+ File.Delete(tempName1);
+ }
+ }
+
+ [Test]
+ [Category("Zip")]
+ [Category("CreatesTempFile")]
+ public void ExtractEmptyDirectories()
+ {
+ var tempFilePath = GetTempFilePath();
+ Assert.IsNotNull(tempFilePath, "No permission to execute this test?");
+
+ var name = Path.Combine(tempFilePath, "x.zip");
+
+ EnsureTestDirectoryIsEmpty(tempFilePath);
+
+ var targetDir = Path.Combine(tempFilePath, ZipTempDir + @"\floyd");
+ using (var fs = File.Create(name))
+ {
+ using (var zOut = new ZipOutputStream(fs))
+ {
+ zOut.PutNextEntry(new ZipEntry("floyd/"));
+ }
+ }
+
+ var fastZip = new FastZip();
+ fastZip.CreateEmptyDirectories = true;
+ fastZip.ExtractZip(name, targetDir, "zz");
+
+ File.Delete(name);
+ Assert.IsTrue(Directory.Exists(targetDir), "Empty directory should be created");
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void NonAsciiPasswords()
+ {
+ const string tempName1 = "a.dat";
+
+ var target = new MemoryStream();
+
+ var tempFilePath = GetTempFilePath();
+ Assert.IsNotNull(tempFilePath, "No permission to execute this test?");
+
+ var addFile = Path.Combine(tempFilePath, tempName1);
+ MakeTempFile(addFile, 1);
+
+ var password = "abc\u0066\u0393";
+ try
+ {
+ var fastZip = new FastZip();
+ fastZip.Password = password;
+
+ fastZip.CreateZip(target, tempFilePath, false, @"a\.dat", null);
+
+ var archive = new MemoryStream(target.ToArray());
+ using (var zf = new ZipFile(archive))
+ {
+ zf.Password = password;
+ Assert.AreEqual(1, zf.Count);
+ var entry = zf[0];
+ Assert.AreEqual(tempName1, entry.Name);
+ Assert.AreEqual(1, entry.Size);
+ Assert.IsTrue(zf.TestArchive(true));
+ Assert.IsTrue(entry.IsCrypted);
+ }
+ }
+ finally
+ {
+ File.Delete(tempName1);
+ }
+ }
+ }
+
+ [TestFixture]
+ public class ZipFileHandling : ZipBase
+ {
+ private void Compare(byte[] a, byte[] b)
+ {
+ Assert.AreEqual(a.Length, b.Length);
+ for (var i = 0; i < a.Length; ++i)
+ {
+ Assert.AreEqual(a[i], b[i]);
+ }
+ }
+
+ private void TryDeleting(byte[] master, int totalEntries, int additions, params string[] toDelete)
+ {
+ var ms = new MemoryStream();
+ ms.Write(master, 0, master.Length);
+
+ using (var f = new ZipFile(ms))
+ {
+ f.IsStreamOwner = false;
+ Assert.AreEqual(totalEntries, f.Count);
+ Assert.IsTrue(f.TestArchive(true));
+ f.BeginUpdate(new MemoryArchiveStorage());
+
+ for (var i = 0; i < additions; ++i)
+ {
+ f.Add(new StringMemoryDataSource("Another great file"),
+ string.Format("Add{0}.dat", i + 1));
+ }
+
+ foreach (var name in toDelete)
+ {
+ f.Delete(name);
+ }
+ f.CommitUpdate();
+
+ // write stream to file to assist debugging.
+ // WriteToFile(@"c:\aha.zip", ms.ToArray());
+
+ var newTotal = totalEntries + additions - toDelete.Length;
+ Assert.AreEqual(newTotal, f.Count,
+ string.Format("Expected {0} entries after update found {1}", newTotal, f.Count));
+ Assert.IsTrue(f.TestArchive(true), "Archive test should pass");
+ }
+ }
+
+ private void TryDeleting(byte[] master, int totalEntries, int additions, params int[] toDelete)
+ {
+ var ms = new MemoryStream();
+ ms.Write(master, 0, master.Length);
+
+ using (var f = new ZipFile(ms))
+ {
+ f.IsStreamOwner = false;
+ Assert.AreEqual(totalEntries, f.Count);
+ Assert.IsTrue(f.TestArchive(true));
+ f.BeginUpdate(new MemoryArchiveStorage());
+
+ for (var i = 0; i < additions; ++i)
+ {
+ f.Add(new StringMemoryDataSource("Another great file"),
+ string.Format("Add{0}.dat", i + 1));
+ }
+
+ foreach (var i in toDelete)
+ {
+ f.Delete(f[i]);
+ }
+ f.CommitUpdate();
+
+ /* write stream to file to assist debugging.
+ byte[] data = ms.ToArray();
+ using ( FileStream fs = File.Open(@"c:\aha.zip", FileMode.Create, FileAccess.ReadWrite, FileShare.Read) ) {
+ fs.Write(data, 0, data.Length);
+ }
+ */
+ var newTotal = totalEntries + additions - toDelete.Length;
+ Assert.AreEqual(newTotal, f.Count,
+ string.Format("Expected {0} entries after update found {1}", newTotal, f.Count));
+ Assert.IsTrue(f.TestArchive(true), "Archive test should pass");
+ }
+ }
+
+ [Test]
+ [Category("Zip")]
+ [Category("CreatesTempFile")]
+ public void AddAndDeleteEntries()
+ {
+ var tempFile = GetTempFilePath();
+ Assert.IsNotNull(tempFile, "No permission to execute this test?");
+
+ var addFile = Path.Combine(tempFile, "a.dat");
+ MakeTempFile(addFile, 1);
+
+ var addFile2 = Path.Combine(tempFile, "b.dat");
+ MakeTempFile(addFile2, 259);
+
+ tempFile = Path.Combine(tempFile, "SharpZipTest.Zip");
+
+ using (var f = ZipFile.Create(tempFile))
+ {
+ f.BeginUpdate();
+ f.Add(addFile);
+ f.Add(addFile2);
+ f.CommitUpdate();
+ Assert.IsTrue(f.TestArchive(true));
+ }
+
+ using (var f = new ZipFile(tempFile))
+ {
+ Assert.AreEqual(2, f.Count);
+ Assert.IsTrue(f.TestArchive(true));
+ f.BeginUpdate();
+ f.Delete(f[0]);
+ f.CommitUpdate();
+ Assert.AreEqual(1, f.Count);
+ Assert.IsTrue(f.TestArchive(true));
+ }
+
+ File.Delete(addFile);
+ File.Delete(addFile2);
+ File.Delete(tempFile);
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void AddAndDeleteEntriesMemory()
+ {
+ var memStream = new MemoryStream();
+
+ using (var f = new ZipFile(memStream))
+ {
+ f.IsStreamOwner = false;
+
+ f.BeginUpdate(new MemoryArchiveStorage());
+ f.Add(new StringMemoryDataSource("Hello world"), @"z:\a\a.dat");
+ f.Add(new StringMemoryDataSource("Another"), @"\b\b.dat");
+ f.Add(new StringMemoryDataSource("Mr C"), @"c\c.dat");
+ f.Add(new StringMemoryDataSource("Mrs D was a star"), @"d\d.dat");
+ f.CommitUpdate();
+ Assert.IsTrue(f.TestArchive(true));
+ }
+
+ var master = memStream.ToArray();
+
+ TryDeleting(master, 4, 1, @"z:\a\a.dat");
+ TryDeleting(master, 4, 1, @"\a\a.dat");
+ TryDeleting(master, 4, 1, @"a/a.dat");
+
+ TryDeleting(master, 4, 0, 0);
+ TryDeleting(master, 4, 0, 1);
+ TryDeleting(master, 4, 0, 2);
+ TryDeleting(master, 4, 0, 3);
+ TryDeleting(master, 4, 0, 0, 1);
+ TryDeleting(master, 4, 0, 0, 2);
+ TryDeleting(master, 4, 0, 0, 3);
+ TryDeleting(master, 4, 0, 1, 2);
+ TryDeleting(master, 4, 0, 1, 3);
+ TryDeleting(master, 4, 0, 2);
+
+ TryDeleting(master, 4, 1, 0);
+ TryDeleting(master, 4, 1, 1);
+ TryDeleting(master, 4, 3, 2);
+ TryDeleting(master, 4, 4, 3);
+ TryDeleting(master, 4, 10, 0, 1);
+ TryDeleting(master, 4, 10, 0, 2);
+ TryDeleting(master, 4, 10, 0, 3);
+ TryDeleting(master, 4, 20, 1, 2);
+ TryDeleting(master, 4, 30, 1, 3);
+ TryDeleting(master, 4, 40, 2);
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void AddEncryptedEntriesToExistingArchive()
+ {
+ const string TestValue = "0001000";
+ var memStream = new MemoryStream();
+ using (var f = new ZipFile(memStream))
+ {
+ f.IsStreamOwner = false;
+ f.UseZip64 = UseZip64.Off;
+
+ var m = new StringMemoryDataSource(TestValue);
+ f.BeginUpdate(new MemoryArchiveStorage());
+ f.Add(m, "a.dat");
+ f.CommitUpdate();
+ Assert.IsTrue(f.TestArchive(true), "Archive test should pass");
+ }
+
+ using (var g = new ZipFile(memStream))
+ {
+ var ze = g[0];
+
+ Assert.IsFalse(ze.IsCrypted, "Entry should NOT be encrypted");
+ using (var r = new StreamReader(g.GetInputStream(0)))
+ {
+ var data = r.ReadToEnd();
+ Assert.AreEqual(TestValue, data);
+ }
+
+ var n = new StringMemoryDataSource(TestValue);
+
+ g.Password = "Axolotyl";
+ g.UseZip64 = UseZip64.Off;
+ g.IsStreamOwner = false;
+ g.BeginUpdate();
+ g.Add(n, "a1.dat");
+ g.CommitUpdate();
+ Assert.IsTrue(g.TestArchive(true), "Archive test should pass");
+ ze = g[1];
+ Assert.IsTrue(ze.IsCrypted, "New entry should be encrypted");
+ using (var r = new StreamReader(g.GetInputStream(0)))
+ {
+ var data = r.ReadToEnd();
+ Assert.AreEqual(TestValue, data);
+ }
+ }
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void AddToEmptyArchive()
+ {
+ var tempFile = GetTempFilePath();
+ Assert.IsNotNull(tempFile, "No permission to execute this test?");
+ if (tempFile != null)
+ {
+ var addFile = Path.Combine(tempFile, "a.dat");
+ MakeTempFile(addFile, 1);
+
+ tempFile = Path.Combine(tempFile, "SharpZipTest.Zip");
+
+ using (var f = ZipFile.Create(tempFile))
+ {
+ f.BeginUpdate();
+ f.Add(addFile);
+ f.CommitUpdate();
+ Assert.AreEqual(1, f.Count);
+ Assert.IsTrue(f.TestArchive(true));
+ }
+
+ using (var f = new ZipFile(tempFile))
+ {
+ Assert.AreEqual(1, f.Count);
+ f.BeginUpdate();
+ f.Delete(f[0]);
+ f.CommitUpdate();
+ Assert.AreEqual(0, f.Count);
+ Assert.IsTrue(f.TestArchive(true));
+ f.Close();
+ }
+
+ File.Delete(addFile);
+ File.Delete(tempFile);
+ }
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void ArchiveTesting()
+ {
+ byte[] originalData = null;
+ var compressedData = MakeInMemoryZip(ref originalData, CompressionMethod.Deflated,
+ 6, 1024, null, true);
+
+ var ms = new MemoryStream(compressedData);
+ ms.Seek(0, SeekOrigin.Begin);
+
+ using (var testFile = new ZipFile(ms))
+ {
+ Assert.IsTrue(testFile.TestArchive(true), "Unexpected error in archive detected");
+
+ var corrupted = new byte[compressedData.Length];
+ Array.Copy(compressedData, corrupted, compressedData.Length);
+
+ corrupted[123] = (byte) (~corrupted[123] & 0xff);
+ ms = new MemoryStream(corrupted);
+ }
+
+ using (var testFile = new ZipFile(ms))
+ {
+ Assert.IsFalse(testFile.TestArchive(true), "Error in archive not detected");
+ }
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void BasicEncryption()
+ {
+ const string TestValue = "0001000";
+ var memStream = new MemoryStream();
+ using (var f = new ZipFile(memStream))
+ {
+ f.IsStreamOwner = false;
+ f.Password = "Hello";
+
+ var m = new StringMemoryDataSource(TestValue);
+ f.BeginUpdate(new MemoryArchiveStorage());
+ f.Add(m, "a.dat");
+ f.CommitUpdate();
+ Assert.IsTrue(f.TestArchive(true), "Archive test should pass");
+ }
+
+ using (var g = new ZipFile(memStream))
+ {
+ g.Password = "Hello";
+ var ze = g[0];
+
+ Assert.IsTrue(ze.IsCrypted, "Entry should be encrypted");
+ using (var r = new StreamReader(g.GetInputStream(0)))
+ {
+ var data = r.ReadToEnd();
+ Assert.AreEqual(TestValue, data);
+ }
+ }
+ }
+
+ [Test]
+ [Category("Zip")]
+ [Category("CreatesTempFile")]
+ public void BasicEncryptionToDisk()
+ {
+ const string TestValue = "0001000";
+ var tempFile = GetTempFilePath();
+ Assert.IsNotNull(tempFile, "No permission to execute this test?");
+
+ tempFile = Path.Combine(tempFile, "SharpZipTest.Zip");
+
+ using (var f = ZipFile.Create(tempFile))
+ {
+ f.Password = "Hello";
+
+ var m = new StringMemoryDataSource(TestValue);
+ f.BeginUpdate();
+ f.Add(m, "a.dat");
+ f.CommitUpdate();
+ }
+
+ using (var f = new ZipFile(tempFile))
+ {
+ f.Password = "Hello";
+ Assert.IsTrue(f.TestArchive(true), "Archive test should pass");
+ }
+
+ using (var g = new ZipFile(tempFile))
+ {
+ g.Password = "Hello";
+ var ze = g[0];
+
+ Assert.IsTrue(ze.IsCrypted, "Entry should be encrypted");
+ using (var r = new StreamReader(g.GetInputStream(0)))
+ {
+ var data = r.ReadToEnd();
+ Assert.AreEqual(TestValue, data);
+ }
+ }
+
+ File.Delete(tempFile);
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void CreateEmptyArchive()
+ {
+ var tempFile = GetTempFilePath();
+ Assert.IsNotNull(tempFile, "No permission to execute this test?");
+
+ if (tempFile != null)
+ {
+ tempFile = Path.Combine(tempFile, "SharpZipTest.Zip");
+
+ using (var f = ZipFile.Create(tempFile))
+ {
+ f.BeginUpdate();
+ f.CommitUpdate();
+ Assert.IsTrue(f.TestArchive(true));
+ f.Close();
+ }
+
+ using (var f = new ZipFile(tempFile))
+ {
+ Assert.AreEqual(0, f.Count);
+ }
+ }
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void Crypto_AddEncryptedEntryToExistingArchiveDirect()
+ {
+ var ms = new MemoryStream();
+
+ byte[] rawData;
+
+ using (var testFile = new ZipFile(ms))
+ {
+ testFile.IsStreamOwner = false;
+ testFile.BeginUpdate();
+ testFile.Add(new StringMemoryDataSource("Aha"), "No1", CompressionMethod.Stored);
+ testFile.Add(new StringMemoryDataSource("And so it goes"), "No2", CompressionMethod.Stored);
+ testFile.Add(new StringMemoryDataSource("No3"), "No3", CompressionMethod.Stored);
+ testFile.CommitUpdate();
+
+ Assert.IsTrue(testFile.TestArchive(true));
+ rawData = ms.ToArray();
+ }
+
+ using (var testFile = new ZipFile(ms))
+ {
+ Assert.IsTrue(testFile.TestArchive(true));
+ testFile.IsStreamOwner = false;
+
+ testFile.BeginUpdate();
+ testFile.Password = "pwd";
+ testFile.Add(new StringMemoryDataSource("Zapata!"), "encrypttest.xml");
+ testFile.CommitUpdate();
+
+ Assert.IsTrue(testFile.TestArchive(true));
+
+ var entryIndex = testFile.FindEntry("encrypttest.xml", true);
+ Assert.IsNotNull(entryIndex >= 0);
+ Assert.IsTrue(testFile[entryIndex].IsCrypted);
+ }
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void Crypto_AddEncryptedEntryToExistingArchiveSafe()
+ {
+ var ms = new MemoryStream();
+
+ byte[] rawData;
+
+ using (var testFile = new ZipFile(ms))
+ {
+ testFile.IsStreamOwner = false;
+ testFile.BeginUpdate();
+ testFile.Add(new StringMemoryDataSource("Aha"), "No1", CompressionMethod.Stored);
+ testFile.Add(new StringMemoryDataSource("And so it goes"), "No2", CompressionMethod.Stored);
+ testFile.Add(new StringMemoryDataSource("No3"), "No3", CompressionMethod.Stored);
+ testFile.CommitUpdate();
+
+ Assert.IsTrue(testFile.TestArchive(true));
+ rawData = ms.ToArray();
+ }
+
+ ms = new MemoryStream(rawData);
+
+ using (var testFile = new ZipFile(ms))
+ {
+ Assert.IsTrue(testFile.TestArchive(true));
+
+ testFile.BeginUpdate(new MemoryArchiveStorage(FileUpdateMode.Safe));
+ testFile.Password = "pwd";
+ testFile.Add(new StringMemoryDataSource("Zapata!"), "encrypttest.xml");
+ testFile.CommitUpdate();
+
+ Assert.IsTrue(testFile.TestArchive(true));
+
+ var entryIndex = testFile.FindEntry("encrypttest.xml", true);
+ Assert.IsNotNull(entryIndex >= 0);
+ Assert.IsTrue(testFile[entryIndex].IsCrypted);
+ }
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void EmbeddedArchive()
+ {
+ var memStream = new MemoryStream();
+ using (var f = new ZipFile(memStream))
+ {
+ f.IsStreamOwner = false;
+
+ var m = new StringMemoryDataSource("0000000");
+ f.BeginUpdate(new MemoryArchiveStorage());
+ f.Add(m, "a.dat");
+ f.Add(m, "b.dat");
+ f.CommitUpdate();
+ Assert.IsTrue(f.TestArchive(true));
+ }
+
+ var rawArchive = memStream.ToArray();
+ var pseudoSfx = new byte[1049 + rawArchive.Length];
+ Array.Copy(rawArchive, 0, pseudoSfx, 1049, rawArchive.Length);
+
+ memStream = new MemoryStream(pseudoSfx);
+ using (var f = new ZipFile(memStream))
+ {
+ for (var index = 0; index < f.Count; ++index)
+ {
+ var entryStream = f.GetInputStream(index);
+ var data = new MemoryStream();
+ StreamUtils.Copy(entryStream, data, new byte[128]);
+
+ var bytes = data.ToArray();
+ string contents = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
+ Assert.AreEqual("0000000", contents);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Check that ZipFile doesnt find entries when there is more than 64K of data at the end.
+ /// </summary>
+ /// <remarks>
+ /// This may well be flawed but is the current behaviour.
+ /// </remarks>
+ [Test]
+ [Category("Zip")]
+ [Category("CreatesTempFile")]
+ public void FindEntriesInArchiveExtraData()
+ {
+ var tempFile = GetTempFilePath();
+ Assert.IsNotNull(tempFile, "No permission to execute this test?");
+
+ if (tempFile != null)
+ {
+ tempFile = Path.Combine(tempFile, "SharpZipTest.Zip");
+ var longComment = new String('A', 65535);
+ var tempStream = File.Create(tempFile);
+ MakeZipFile(tempStream, false, "", 1, 1, longComment);
+
+ tempStream.WriteByte(85);
+ tempStream.Close();
+
+ var fails = false;
+ try
+ {
+ using (var zipFile = new ZipFile(tempFile))
+ {
+ foreach (ZipEntry e in zipFile)
+ {
+ var instream = zipFile.GetInputStream(e);
+ CheckKnownEntry(instream, 1);
+ }
+ zipFile.Close();
+ }
+ }
+ catch
+ {
+ fails = true;
+ }
+
+ File.Delete(tempFile);
+ Assert.IsTrue(fails, "Currently zip file wont be found");
+ }
+ }
+
+ /// <summary>
+ /// Check that ZipFile finds entries when its got a long comment
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ [Category("CreatesTempFile")]
+ public void FindEntriesInArchiveWithLongComment()
+ {
+ var tempFile = GetTempFilePath();
+ Assert.IsNotNull(tempFile, "No permission to execute this test?");
+
+ if (tempFile != null)
+ {
+ tempFile = Path.Combine(tempFile, "SharpZipTest.Zip");
+ var longComment = new String('A', 65535);
+ MakeZipFile(tempFile, "", 1, 1, longComment);
+ using (var zipFile = new ZipFile(tempFile))
+ {
+ foreach (ZipEntry e in zipFile)
+ {
+ var instream = zipFile.GetInputStream(e);
+ CheckKnownEntry(instream, 1);
+ }
+ zipFile.Close();
+ }
+ File.Delete(tempFile);
+ }
+ }
+
+ /// <summary>
+ /// Test ZipFile Find method operation
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ [Category("CreatesTempFile")]
+ public void FindEntry()
+ {
+ var tempFile = GetTempFilePath();
+ Assert.IsNotNull(tempFile, "No permission to execute this test?");
+
+ if (tempFile != null)
+ {
+ tempFile = Path.Combine(tempFile, "SharpZipTest.Zip");
+ MakeZipFile(tempFile, new[]{"Farriera", "Champagne", "Urban myth"}, 10, "Aha");
+
+ using (var zipFile = new ZipFile(tempFile))
+ {
+ Assert.AreEqual(3, zipFile.Count, "Expected 1 entry");
+
+ var testIndex = zipFile.FindEntry("Farriera", false);
+ Assert.AreEqual(0, testIndex, "Case sensitive find failure");
+ Assert.IsTrue(string.Compare(zipFile[testIndex].Name, "Farriera", StringComparison.InvariantCulture) == 0);
+
+ testIndex = zipFile.FindEntry("Farriera", true);
+ Assert.AreEqual(0, testIndex, "Case insensitive find failure");
+ Assert.IsTrue(string.Compare(zipFile[testIndex].Name, "Farriera", StringComparison.InvariantCultureIgnoreCase) == 0);
+
+ testIndex = zipFile.FindEntry("urban mYTH", false);
+ Assert.AreEqual(-1, testIndex, "Case sensitive find failure");
+
+ testIndex = zipFile.FindEntry("urban mYTH", true);
+ Assert.AreEqual(2, testIndex, "Case insensitive find failure");
+ Assert.IsTrue(string.Compare(zipFile[testIndex].Name, "urban mYTH", StringComparison.InvariantCultureIgnoreCase) == 0);
+
+ testIndex = zipFile.FindEntry("Champane.", false);
+ Assert.AreEqual(-1, testIndex, "Case sensitive find failure");
+
+ testIndex = zipFile.FindEntry("Champane.", true);
+ Assert.AreEqual(-1, testIndex, "Case insensitive find failure");
+
+ zipFile.Close();
+ }
+ File.Delete(tempFile);
+ }
+ }
+
+ /// <summary>
+ /// Check that ZipFile class handles no entries in zip file
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ [Category("CreatesTempFile")]
+ public void HandlesNoEntries()
+ {
+ var tempFile = GetTempFilePath();
+ Assert.IsNotNull(tempFile, "No permission to execute this test?");
+
+ if (tempFile != null)
+ {
+ tempFile = Path.Combine(tempFile, "SharpZipTest.Zip");
+ MakeZipFile(tempFile, "", 0, 1, "Aha");
+
+ using (var zipFile = new ZipFile(tempFile))
+ {
+ Assert.AreEqual(0, zipFile.Count);
+ zipFile.Close();
+ }
+
+ File.Delete(tempFile);
+ }
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void NameFactory()
+ {
+ var memStream = new MemoryStream();
+ var fixedTime = new DateTime(1981, 4, 3);
+ using (var f = new ZipFile(memStream))
+ {
+ f.IsStreamOwner = false;
+ ((ZipEntryFactory) f.EntryFactory).IsUnicodeText = true;
+ ((ZipEntryFactory) f.EntryFactory).Setting = ZipEntryFactory.TimeSetting.Fixed;
+ ((ZipEntryFactory) f.EntryFactory).FixedDateTime = fixedTime;
+ ((ZipEntryFactory) f.EntryFactory).SetAttributes = 1;
+ f.BeginUpdate(new MemoryArchiveStorage());
+
+ var names = new[]{
+ "\u030A\u03B0", // Greek
+ "\u0680\u0685", // Arabic
+ };
+
+ foreach (var name in names)
+ {
+ f.Add(new StringMemoryDataSource("Hello world"), name,
+ CompressionMethod.Deflated, true);
+ }
+ f.CommitUpdate();
+ Assert.IsTrue(f.TestArchive(true));
+
+ foreach (var name in names)
+ {
+ var index = f.FindEntry(name, true);
+
+ Assert.IsTrue(index >= 0);
+ var found = f[index];
+ Assert.AreEqual(name, found.Name);
+ Assert.IsTrue(found.IsUnicodeText);
+ Assert.AreEqual(fixedTime, found.DateTime);
+ Assert.IsTrue(found.IsDOSEntry);
+ }
+ }
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void NullStreamDetected()
+ {
+ ZipFile bad = null;
+ FileStream nullStream = null;
+
+ var nullStreamDetected = false;
+
+ try
+ {
+ bad = new ZipFile(nullStream);
+ }
+ catch
+ {
+ nullStreamDetected = true;
+ }
+
+ Assert.IsTrue(nullStreamDetected, "Null stream should be detected in ZipFile constructor");
+ Assert.IsNull(bad, "ZipFile instance should not be created");
+ }
+
+ /// <summary>
+ /// Simple round trip test for ZipFile class
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ [Category("CreatesTempFile")]
+ public void RoundTrip()
+ {
+ var tempFile = GetTempFilePath();
+ Assert.IsNotNull(tempFile, "No permission to execute this test?");
+
+ if (tempFile != null)
+ {
+ tempFile = Path.Combine(tempFile, "SharpZipTest.Zip");
+ MakeZipFile(tempFile, "", 10, 1024, "");
+
+ using (var zipFile = new ZipFile(tempFile))
+ {
+ foreach (ZipEntry e in zipFile)
+ {
+ var instream = zipFile.GetInputStream(e);
+ CheckKnownEntry(instream, 1024);
+ }
+ zipFile.Close();
+ }
+
+ File.Delete(tempFile);
+ }
+ }
+
+ /// <summary>
+ /// Simple round trip test for ZipFile class
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ public void RoundTripInMemory()
+ {
+ var storage = new MemoryStream();
+ MakeZipFile(storage, false, "", 10, 1024, "");
+
+ using (var zipFile = new ZipFile(storage))
+ {
+ foreach (ZipEntry e in zipFile)
+ {
+ var instream = zipFile.GetInputStream(e);
+ CheckKnownEntry(instream, 1024);
+ }
+ zipFile.Close();
+ }
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void UnicodeNames()
+ {
+ var memStream = new MemoryStream();
+ using (var f = new ZipFile(memStream))
+ {
+ f.IsStreamOwner = false;
+
+ f.BeginUpdate(new MemoryArchiveStorage());
+
+ var names = new[]{
+ "\u030A\u03B0", // Greek
+ "\u0680\u0685", // Arabic
+ };
+
+ foreach (var name in names)
+ {
+ f.Add(new StringMemoryDataSource("Hello world"), name,
+ CompressionMethod.Deflated, true);
+ }
+ f.CommitUpdate();
+ Assert.IsTrue(f.TestArchive(true));
+
+ foreach (var name in names)
+ {
+ var index = f.FindEntry(name, true);
+
+ Assert.IsTrue(index >= 0);
+ var found = f[index];
+ Assert.AreEqual(name, found.Name);
+ }
+ }
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void UpdateCommentOnlyInMemory()
+ {
+ var ms = new MemoryStream();
+
+ using (var testFile = new ZipFile(ms))
+ {
+ testFile.IsStreamOwner = false;
+ testFile.BeginUpdate();
+ testFile.Add(new StringMemoryDataSource("Aha"), "No1", CompressionMethod.Stored);
+ testFile.Add(new StringMemoryDataSource("And so it goes"), "No2", CompressionMethod.Stored);
+ testFile.Add(new StringMemoryDataSource("No3"), "No3", CompressionMethod.Stored);
+ testFile.CommitUpdate();
+
+ Assert.IsTrue(testFile.TestArchive(true));
+ }
+
+ using (var testFile = new ZipFile(ms))
+ {
+ Assert.IsTrue(testFile.TestArchive(true));
+ Assert.AreEqual("", testFile.ZipFileComment);
+ testFile.IsStreamOwner = false;
+
+ testFile.BeginUpdate();
+ testFile.SetComment("Here is my comment");
+ testFile.CommitUpdate();
+
+ Assert.IsTrue(testFile.TestArchive(true));
+ }
+
+ using (var testFile = new ZipFile(ms))
+ {
+ Assert.IsTrue(testFile.TestArchive(true));
+ Assert.AreEqual("Here is my comment", testFile.ZipFileComment);
+ }
+ }
+
+ [Test]
+ [Category("Zip")]
+ [Category("CreatesTempFile")]
+ public void UpdateCommentOnlyOnDisk()
+ {
+ var tempFile = GetTempFilePath();
+ Assert.IsNotNull(tempFile, "No permission to execute this test?");
+
+ tempFile = Path.Combine(tempFile, "SharpZipTest.Zip");
+ if (File.Exists(tempFile))
+ {
+ File.Delete(tempFile);
+ }
+
+ using (var testFile = ZipFile.Create(tempFile))
+ {
+ testFile.BeginUpdate();
+ testFile.Add(new StringMemoryDataSource("Aha"), "No1", CompressionMethod.Stored);
+ testFile.Add(new StringMemoryDataSource("And so it goes"), "No2", CompressionMethod.Stored);
+ testFile.Add(new StringMemoryDataSource("No3"), "No3", CompressionMethod.Stored);
+ testFile.CommitUpdate();
+
+ Assert.IsTrue(testFile.TestArchive(true));
+ }
+
+ using (var testFile = new ZipFile(tempFile))
+ {
+ Assert.IsTrue(testFile.TestArchive(true));
+ Assert.AreEqual("", testFile.ZipFileComment);
+
+ testFile.BeginUpdate(new DiskArchiveStorage(testFile, FileUpdateMode.Direct));
+ testFile.SetComment("Here is my comment");
+ testFile.CommitUpdate();
+
+ Assert.IsTrue(testFile.TestArchive(true));
+ }
+
+ using (var testFile = new ZipFile(tempFile))
+ {
+ Assert.IsTrue(testFile.TestArchive(true));
+ Assert.AreEqual("Here is my comment", testFile.ZipFileComment);
+ }
+ File.Delete(tempFile);
+
+ // Variant using indirect updating.
+ using (var testFile = ZipFile.Create(tempFile))
+ {
+ testFile.BeginUpdate();
+ testFile.Add(new StringMemoryDataSource("Aha"), "No1", CompressionMethod.Stored);
+ testFile.Add(new StringMemoryDataSource("And so it goes"), "No2", CompressionMethod.Stored);
+ testFile.Add(new StringMemoryDataSource("No3"), "No3", CompressionMethod.Stored);
+ testFile.CommitUpdate();
+
+ Assert.IsTrue(testFile.TestArchive(true));
+ }
+
+ using (var testFile = new ZipFile(tempFile))
+ {
+ Assert.IsTrue(testFile.TestArchive(true));
+ Assert.AreEqual("", testFile.ZipFileComment);
+
+ testFile.BeginUpdate();
+ testFile.SetComment("Here is my comment");
+ testFile.CommitUpdate();
+
+ Assert.IsTrue(testFile.TestArchive(true));
+ }
+
+ using (var testFile = new ZipFile(tempFile))
+ {
+ Assert.IsTrue(testFile.TestArchive(true));
+ Assert.AreEqual("Here is my comment", testFile.ZipFileComment);
+ }
+ File.Delete(tempFile);
+ }
+
+ /// <summary>
+ /// Check that adding too many entries is detected and handled
+ /// </summary>
+ [Test]
+ [Category("Zip")]
+ [Category("CreatesTempFile")]
+ public void Zip64Entries()
+ {
+ var tempFile = GetTempFilePath();
+ Assert.IsNotNull(tempFile, "No permission to execute this test?");
+
+ const int target = 65537;
+
+ using (var zipFile = ZipFile.Create(Path.GetTempFileName()))
+ {
+ zipFile.BeginUpdate();
+
+ for (var i = 0; i < target; ++i)
+ {
+ var ze = new ZipEntry(i.ToString());
+ ze.CompressedSize = 0;
+ ze.Size = 0;
+ zipFile.Add(ze);
+ }
+ zipFile.CommitUpdate();
+
+ Assert.IsTrue(zipFile.TestArchive(true));
+ Assert.AreEqual(target, zipFile.Count, "Incorrect number of entries stored");
+ }
+ }
+
+ [Test]
+ [Category("Zip")]
+ [Explicit]
+ public void Zip64Offset()
+ {
+ // TODO: Test to check that a zip64 offset value is loaded correctly.
+ // Changes in ZipEntry to CentralHeaderRequiresZip64 and LocalHeaderRequiresZip64
+ // were not quite correct...
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void Zip64Useage()
+ {
+ var memStream = new MemoryStream();
+ using (var f = new ZipFile(memStream))
+ {
+ f.IsStreamOwner = false;
+ f.UseZip64 = UseZip64.On;
+
+ var m = new StringMemoryDataSource("0000000");
+ f.BeginUpdate(new MemoryArchiveStorage());
+ f.Add(m, "a.dat");
+ f.Add(m, "b.dat");
+ f.CommitUpdate();
+ Assert.IsTrue(f.TestArchive(true));
+ }
+
+ var rawArchive = memStream.ToArray();
+
+ var pseudoSfx = new byte[1049 + rawArchive.Length];
+ Array.Copy(rawArchive, 0, pseudoSfx, 1049, rawArchive.Length);
+
+ memStream = new MemoryStream(pseudoSfx);
+ using (var f = new ZipFile(memStream))
+ {
+ for (var index = 0; index < f.Count; ++index)
+ {
+ var entryStream = f.GetInputStream(index);
+ var data = new MemoryStream();
+ StreamUtils.Copy(entryStream, data, new byte[128]);
+
+ var bytes = data.ToArray();
+ string contents = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
+ Assert.AreEqual("0000000", contents);
+ }
+ }
+ }
+ }
+
+ [TestFixture]
+ public class ZipEntryFactoryHandling : ZipBase
+ {
+ // TODO: Complete testing for ZipEntryFactory
+
+ [Test]
+ [Category("Zip")]
+ public void CreateInMemoryValues()
+ {
+ var tempFile = "bingo:";
+
+ // Note the seconds returned will be even!
+ var epochTime = new DateTime(1980, 1, 1);
+ var createTime = new DateTime(2100, 2, 27, 11, 07, 56);
+ var lastWriteTime = new DateTime(2050, 11, 3, 7, 23, 32);
+ var lastAccessTime = new DateTime(2050, 11, 3, 0, 42, 12);
+
+ var factory = new ZipEntryFactory();
+ ZipEntry entry;
+ int combinedAttributes;
+
+ var startTime = DateTime.Now;
+
+ factory.Setting = ZipEntryFactory.TimeSetting.CreateTime;
+ factory.GetAttributes = ~((int) FileAttributes.ReadOnly);
+ factory.SetAttributes = (int) FileAttributes.ReadOnly;
+ combinedAttributes = (int) FileAttributes.ReadOnly;
+
+ entry = factory.MakeFileEntry(tempFile, false);
+ Assert.IsTrue(TestHelper.CompareDosDateTimes(startTime, entry.DateTime) <= 0, "Create time failure");
+ Assert.AreEqual(entry.ExternalFileAttributes, combinedAttributes);
+ Assert.AreEqual(-1, entry.Size);
+
+ factory.FixedDateTime = startTime;
+ factory.Setting = ZipEntryFactory.TimeSetting.Fixed;
+ entry = factory.MakeFileEntry(tempFile, false);
+ Assert.AreEqual(0, TestHelper.CompareDosDateTimes(startTime, entry.DateTime), "Access time failure");
+ Assert.AreEqual(-1, entry.Size);
+
+ factory.Setting = ZipEntryFactory.TimeSetting.LastWriteTime;
+ entry = factory.MakeFileEntry(tempFile, false);
+ Assert.IsTrue(TestHelper.CompareDosDateTimes(startTime, entry.DateTime) <= 0, "Write time failure");
+ Assert.AreEqual(-1, entry.Size);
+ }
+
+ [Test]
+ [Category("Zip")]
+ public void Defaults()
+ {
+ var testStart = DateTime.Now;
+ var f = new ZipEntryFactory();
+ Assert.IsNotNull(f.NameTransform);
+ Assert.AreEqual(-1, f.GetAttributes);
+ Assert.AreEqual(0, f.SetAttributes);
+ Assert.AreEqual(ZipEntryFactory.TimeSetting.LastWriteTime, f.Setting);
+
+ Assert.LessOrEqual(testStart, f.FixedDateTime);
+ Assert.GreaterOrEqual(DateTime.Now, f.FixedDateTime);
+
+ f = new ZipEntryFactory(ZipEntryFactory.TimeSetting.LastAccessTimeUtc);
+ Assert.IsNotNull(f.NameTransform);
+ Assert.AreEqual(-1, f.GetAttributes);
+ Assert.AreEqual(0, f.SetAttributes);
+ Assert.AreEqual(ZipEntryFactory.TimeSetting.LastAccessTimeUtc, f.Setting);
+ Assert.LessOrEqual(testStart, f.FixedDateTime);
+ Assert.GreaterOrEqual(DateTime.Now, f.FixedDateTime);
+
+ var fixedDate = new DateTime(1999, 1, 2);
+ f = new ZipEntryFactory(fixedDate);
+ Assert.IsNotNull(f.NameTransform);
+ Assert.AreEqual(-1, f.GetAttributes);
+ Assert.AreEqual(0, f.SetAttributes);
+ Assert.AreEqual(ZipEntryFactory.TimeSetting.Fixed, f.Setting);
+ Assert.AreEqual(fixedDate, f.FixedDateTime);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="NUnit" version="2.5.10.11092" />
+</packages>
\ No newline at end of file
--- /dev/null
+// BZip2.cs
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.BZip2
+{
+ /// <summary>
+ /// A helper class to simplify compressing and decompressing streams.
+ /// </summary>
+ public static class BZip2
+ {
+ /// <summary>
+ /// Decompress <paramref name="inStream">input</paramref> writing
+ /// decompressed data to the <paramref name="outStream">output stream</paramref>
+ /// </summary>
+ /// <param name="inStream">The stream containing data to decompress.</param>
+ /// <param name="outStream">The stream to write decompressed data to.</param>
+ /// <remarks>Both streams are closed on completion</remarks>
+ public static void Decompress(Stream inStream, Stream outStream)
+ {
+ if ( inStream == null ) {
+ throw new ArgumentNullException("inStream");
+ }
+
+ if ( outStream == null ) {
+ throw new ArgumentNullException("outStream");
+ }
+
+ using ( outStream ) {
+ using ( var bzis = new BZip2InputStream(inStream) ) {
+ var ch = bzis.ReadByte();
+ while (ch != -1) {
+ outStream.WriteByte((byte)ch);
+ ch = bzis.ReadByte();
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Compress <paramref name="inStream">input stream</paramref> sending
+ /// result to <paramref name="outStream">output stream</paramref>
+ /// </summary>
+ /// <param name="inStream">The stream to compress.</param>
+ /// <param name="outStream">The stream to write compressed data to.</param>
+ /// <param name="blockSize">The block size to use.</param>
+ /// <remarks>Both streams are closed on completion</remarks>
+ public static void Compress(Stream inStream, Stream outStream, int blockSize)
+ {
+ if ( inStream == null ) {
+ throw new ArgumentNullException("inStream");
+ }
+
+ if ( outStream == null ) {
+ throw new ArgumentNullException("outStream");
+ }
+
+ using ( inStream ) {
+ using (var bzos = new BZip2OutputStream(outStream, blockSize)) {
+ var ch = inStream.ReadByte();
+ while (ch != -1) {
+ bzos.WriteByte((byte)ch);
+ ch = inStream.ReadByte();
+ }
+ }
+ }
+ }
+ }
+}
+
+/* derived from a file which contained this license :
+ * Copyright (c) 1999-2001 Keiron Liddle, Aftex Software
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+*/
--- /dev/null
+// BZip2Constants.cs
+// Copyright (C) 2001 Mike Krueger
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+namespace ICSharpCode.SharpZipLib.Silverlight.BZip2
+{
+ /// <summary>
+ /// Defines internal values for both compression and decompression
+ /// </summary>
+ public static class BZip2Constants
+ {
+ /// <summary>
+ /// Random numbers used to randomise repetitive blocks
+ /// </summary>
+ public readonly static int[] rNums = {
+ 619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
+ 985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
+ 733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
+ 419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
+ 878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
+ 862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
+ 150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
+ 170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
+ 73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
+ 909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
+ 641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
+ 161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
+ 382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
+ 98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
+ 227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
+ 469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
+ 184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
+ 715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
+ 951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
+ 652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
+ 645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
+ 609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
+ 653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
+ 411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
+ 170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
+ 857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
+ 669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
+ 944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
+ 344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
+ 897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
+ 433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
+ 686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
+ 946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
+ 978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
+ 680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
+ 707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
+ 297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
+ 134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
+ 343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
+ 140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
+ 170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
+ 369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
+ 804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
+ 896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
+ 661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
+ 768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
+ 61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
+ 372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
+ 780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
+ 920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
+ 645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
+ 936, 638
+ };
+
+ /// <summary>
+ /// When multiplied by compression parameter (1-9) gives the block size for compression
+ /// 9 gives the best compresssion but uses the most memory.
+ /// </summary>
+ public const int baseBlockSize = 100000;
+
+ /// <summary>
+ /// Backend constant
+ /// </summary>
+ public const int MAX_ALPHA_SIZE = 258;
+
+ /// <summary>
+ /// Backend constant
+ /// </summary>
+ public const int MAX_CODE_LEN = 23;
+
+ /// <summary>
+ /// Backend constant
+ /// </summary>
+ public const int RUNA = 0;
+
+ /// <summary>
+ /// Backend constant
+ /// </summary>
+ public const int RUNB = 1;
+
+ /// <summary>
+ /// Backend constant
+ /// </summary>
+ public const int N_GROUPS = 6;
+
+ /// <summary>
+ /// Backend constant
+ /// </summary>
+ public const int G_SIZE = 50;
+
+ /// <summary>
+ /// Backend constant
+ /// </summary>
+ public const int N_ITERS = 4;
+
+ /// <summary>
+ /// Backend constant
+ /// </summary>
+ public const int MAX_SELECTORS = (2 + (900000 / G_SIZE));
+
+ /// <summary>
+ /// Backend constant
+ /// </summary>
+ public const int NUM_OVERSHOOT_BYTES = 20;
+ }
+}
+
+/* This file was derived from a file containing this license:
+ *
+ * This file is a part of bzip2 and/or libbzip2, a program and
+ * library for lossless, block-sorting data compression.
+ *
+ * Copyright (C) 1996-1998 Julian R Seward. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. The origin of this software must not be misrepresented; you must
+ * not claim that you wrote the original software. If you use this
+ * software in a product, an acknowledgment in the product
+ * documentation would be appreciated but is not required.
+ *
+ * 3. Altered source versions must be plainly marked as such, and must
+ * not be misrepresented as being the original software.
+ *
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Java version ported by Keiron Liddle, Aftex Software <keiron@aftexsw.com> 1999-2001
+ */
--- /dev/null
+// BZip2.cs
+//
+// Copyright 2004 John Reilly
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using ICSharpCode.SharpZipLib.Silverlight.Serialization;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.BZip2
+{
+ /// <summary>
+ /// BZip2Exception represents exceptions specific to Bzip2 algorithm
+ /// </summary>
+ [Serializable]
+ public class BZip2Exception : SharpZipBaseException
+ {
+ /// <summary>
+ /// Deserialization constructor
+ /// </summary>
+ /// <param name="info"><see cref="System.Runtime.Serialization.SerializationInfo"/> for this constructor</param>
+ protected BZip2Exception(SerializationInfo info) : base(info)
+ {
+ }
+
+ /// <summary>
+ /// Initialise a new instance of BZip2Exception
+ /// </summary>
+ public BZip2Exception()
+ {
+
+ }
+
+ /// <summary>
+ /// Initialise a new instance of BZip2Exception with its message set to message.
+ /// </summary>
+ /// <param name="message">The message describing the error.</param>
+ public BZip2Exception(string message) : base(message)
+ {
+ }
+
+ /// <summary>
+ /// Initialise an instance of BZip2Exception
+ /// </summary>
+ /// <param name="message">A message describing the error.</param>
+ /// <param name="exception">The exception that is the cause of the current exception.</param>
+ public BZip2Exception(string message, Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// BZip2InputStream.cs
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+using ICSharpCode.SharpZipLib.Silverlight.Checksums;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.BZip2
+{
+ /// <summary>
+ /// An input stream that decompresses files in the BZip2 format
+ /// </summary>
+ public class BZip2InputStream : Stream
+ {
+ #region Constants
+
+ private const int NO_RAND_PART_A_STATE = 5;
+ private const int NO_RAND_PART_B_STATE = 6;
+ private const int NO_RAND_PART_C_STATE = 7;
+ private const int RAND_PART_A_STATE = 2;
+ private const int RAND_PART_B_STATE = 3;
+ private const int RAND_PART_C_STATE = 4;
+ private const int START_BLOCK_STATE = 1;
+
+ #endregion
+
+ #region Constructors
+
+ /// <summary>
+ /// Construct instance for reading from stream
+ /// </summary>
+ /// <param name="stream">Data source</param>
+ public BZip2InputStream(Stream stream)
+ {
+ // init arrays
+ for (var i = 0; i < BZip2Constants.N_GROUPS; ++i)
+ {
+ limit[i] = new int[BZip2Constants.MAX_ALPHA_SIZE];
+ baseArray[i] = new int[BZip2Constants.MAX_ALPHA_SIZE];
+ perm[i] = new int[BZip2Constants.MAX_ALPHA_SIZE];
+ }
+
+ BsSetStream(stream);
+ Initialize();
+ InitBlock();
+ SetupBlock();
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Get/set flag indicating ownership of underlying stream.
+ /// When the flag is true <see cref="Close"></see> will close the underlying stream also.
+ /// </summary>
+ public bool IsStreamOwner
+ {
+ get { return isStreamOwner; }
+ set { isStreamOwner = value; }
+ }
+
+ #region Stream Overrides
+
+ /// <summary>
+ /// Gets a value indicating if the stream supports reading
+ /// </summary>
+ public override bool CanRead
+ {
+ get { return baseStream.CanRead; }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the current stream supports seeking.
+ /// </summary>
+ public override bool CanSeek
+ {
+ get { return baseStream.CanSeek; }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the current stream supports writing.
+ /// This property always returns false
+ /// </summary>
+ public override bool CanWrite
+ {
+ get { return false; }
+ }
+
+ /// <summary>
+ /// Gets the length in bytes of the stream.
+ /// </summary>
+ public override long Length
+ {
+ get { return baseStream.Length; }
+ }
+
+ /// <summary>
+ /// Gets or sets the streams position.
+ /// Setting the position is not supported and will throw a NotSupportException
+ /// </summary>
+ /// <exception cref="NotSupportedException">Any attempt to set the position</exception>
+ public override long Position
+ {
+ get { return baseStream.Position; }
+ set { throw new NotSupportedException("BZip2InputStream position cannot be set"); }
+ }
+
+ /// <summary>
+ /// Flushes the stream.
+ /// </summary>
+ public override void Flush()
+ {
+ if (baseStream != null)
+ {
+ baseStream.Flush();
+ }
+ }
+
+ /// <summary>
+ /// Set the streams position. This operation is not supported and will throw a NotSupportedException
+ /// </summary>
+ /// <param name="offset">A byte offset relative to the <paramref name="origin"/> parameter.</param>
+ /// <param name="origin">A value of type <see cref="SeekOrigin"/> indicating the reference point used to obtain the new position.</param>
+ /// <returns>The new position of the stream.</returns>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new NotSupportedException("BZip2InputStream Seek not supported");
+ }
+
+ /// <summary>
+ /// Sets the length of this stream to the given value.
+ /// This operation is not supported and will throw a NotSupportedExceptionortedException
+ /// </summary>
+ /// <param name="value">The new length for the stream.</param>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override void SetLength(long value)
+ {
+ throw new NotSupportedException("BZip2InputStream SetLength not supported");
+ }
+
+ /// <summary>
+ /// Writes a block of bytes to this stream using data from a buffer.
+ /// This operation is not supported and will throw a NotSupportedException
+ /// </summary>
+ /// <param name="buffer">The buffer to source data from.</param>
+ /// <param name="offset">The offset to start obtaining data from.</param>
+ /// <param name="count">The number of bytes of data to write.</param>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ throw new NotSupportedException("BZip2InputStream Write not supported");
+ }
+
+ /// <summary>
+ /// Writes a byte to the current position in the file stream.
+ /// This operation is not supported and will throw a NotSupportedException
+ /// </summary>
+ /// <param name="value">The value to write.</param>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override void WriteByte(byte value)
+ {
+ throw new NotSupportedException("BZip2InputStream WriteByte not supported");
+ }
+
+ /// <summary>
+ /// Read a sequence of bytes and advances the read position by one byte.
+ /// </summary>
+ /// <param name="buffer">Array of bytes to store values in</param>
+ /// <param name="offset">Offset in array to begin storing data</param>
+ /// <param name="count">The maximum number of bytes to read</param>
+ /// <returns>The total number of bytes read into the buffer. This might be less
+ /// than the number of bytes requested if that number of bytes are not
+ /// currently available or zero if the end of the stream is reached.
+ /// </returns>
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ if (buffer == null)
+ {
+ throw new ArgumentNullException("buffer");
+ }
+
+ for (var i = 0; i < count; ++i)
+ {
+ var rb = ReadByte();
+ if (rb == -1)
+ {
+ return i;
+ }
+ buffer[offset + i] = (byte) rb;
+ }
+ return count;
+ }
+
+ /// <summary>
+ /// Closes the stream, releasing any associated resources.
+ /// </summary>
+ public override void Close()
+ {
+ if (IsStreamOwner && (baseStream != null))
+ {
+ baseStream.Close();
+ }
+ }
+
+ /// <summary>
+ /// Read a byte from stream advancing position
+ /// </summary>
+ /// <returns>byte read or -1 on end of stream</returns>
+ public override int ReadByte()
+ {
+ if (streamEnd)
+ {
+ return -1; // ok
+ }
+
+ var retChar = currentChar;
+ switch (currentState)
+ {
+ case RAND_PART_B_STATE:
+ SetupRandPartB();
+ break;
+ case RAND_PART_C_STATE:
+ SetupRandPartC();
+ break;
+ case NO_RAND_PART_B_STATE:
+ SetupNoRandPartB();
+ break;
+ case NO_RAND_PART_C_STATE:
+ SetupNoRandPartC();
+ break;
+ case START_BLOCK_STATE:
+ case NO_RAND_PART_A_STATE:
+ case RAND_PART_A_STATE:
+ break;
+ default:
+ break;
+ }
+ return retChar;
+ }
+
+ #endregion
+
+ private void MakeMaps()
+ {
+ nInUse = 0;
+ for (var i = 0; i < 256; ++i)
+ {
+ if (inUse[i])
+ {
+ seqToUnseq[nInUse] = (byte) i;
+ unseqToSeq[i] = (byte) nInUse;
+ nInUse++;
+ }
+ }
+ }
+
+ private void Initialize()
+ {
+ var magic1 = BsGetUChar();
+ var magic2 = BsGetUChar();
+
+ var magic3 = BsGetUChar();
+ var magic4 = BsGetUChar();
+
+ if (magic1 != 'B' || magic2 != 'Z' || magic3 != 'h' || magic4 < '1' || magic4 > '9')
+ {
+ streamEnd = true;
+ return;
+ }
+
+ SetDecompressStructureSizes(magic4 - '0');
+ computedCombinedCRC = 0;
+ }
+
+ private void InitBlock()
+ {
+ var magic1 = BsGetUChar();
+ var magic2 = BsGetUChar();
+ var magic3 = BsGetUChar();
+ var magic4 = BsGetUChar();
+ var magic5 = BsGetUChar();
+ var magic6 = BsGetUChar();
+
+ if (magic1 == 0x17 && magic2 == 0x72 && magic3 == 0x45 && magic4 == 0x38 && magic5 == 0x50 && magic6 == 0x90)
+ {
+ Complete();
+ return;
+ }
+
+ if (magic1 != 0x31 || magic2 != 0x41 || magic3 != 0x59 || magic4 != 0x26 || magic5 != 0x53 || magic6 != 0x59)
+ {
+ BadBlockHeader();
+ streamEnd = true;
+ return;
+ }
+
+ storedBlockCRC = BsGetInt32();
+
+ blockRandomised = (BsR(1) == 1);
+
+ GetAndMoveToFrontDecode();
+
+ mCrc.Reset();
+ currentState = START_BLOCK_STATE;
+ }
+
+ private void EndBlock()
+ {
+ computedBlockCRC = (int) mCrc.Value;
+
+ // -- A bad CRC is considered a fatal error. --
+ if (storedBlockCRC != computedBlockCRC)
+ {
+ CrcError();
+ }
+
+ // 1528150659
+ computedCombinedCRC = ((computedCombinedCRC << 1) & 0xFFFFFFFF) | (computedCombinedCRC >> 31);
+ computedCombinedCRC = computedCombinedCRC ^ (uint) computedBlockCRC;
+ }
+
+ private void Complete()
+ {
+ storedCombinedCRC = BsGetInt32();
+ if (storedCombinedCRC != (int) computedCombinedCRC)
+ {
+ CrcError();
+ }
+
+ streamEnd = true;
+ }
+
+ private void BsSetStream(Stream stream)
+ {
+ baseStream = stream;
+ bsLive = 0;
+ bsBuff = 0;
+ }
+
+ private void FillBuffer()
+ {
+ var thech = 0;
+
+ try
+ {
+ thech = baseStream.ReadByte();
+ }
+ catch (Exception)
+ {
+ CompressedStreamEOF();
+ }
+
+ if (thech == -1)
+ {
+ CompressedStreamEOF();
+ }
+
+ bsBuff = (bsBuff << 8) | (thech & 0xFF);
+ bsLive += 8;
+ }
+
+ private int BsR(int n)
+ {
+ while (bsLive < n)
+ {
+ FillBuffer();
+ }
+
+ var v = (bsBuff >> (bsLive - n)) & ((1 << n) - 1);
+ bsLive -= n;
+ return v;
+ }
+
+ private char BsGetUChar()
+ {
+ return (char) BsR(8);
+ }
+
+ private int BsGetint()
+ {
+ var u = BsR(8);
+ u = (u << 8) | BsR(8);
+ u = (u << 8) | BsR(8);
+ u = (u << 8) | BsR(8);
+ return u;
+ }
+
+ private int BsGetIntVS(int numBits)
+ {
+ return BsR(numBits);
+ }
+
+ private int BsGetInt32()
+ {
+ return BsGetint();
+ }
+
+ private void RecvDecodingTables()
+ {
+ var len = new char[BZip2Constants.N_GROUPS][];
+ for (var i = 0; i < BZip2Constants.N_GROUPS; ++i)
+ {
+ len[i] = new char[BZip2Constants.MAX_ALPHA_SIZE];
+ }
+
+ var inUse16 = new bool[16];
+
+ //--- Receive the mapping table ---
+ for (var i = 0; i < 16; i++)
+ {
+ inUse16[i] = (BsR(1) == 1);
+ }
+
+ for (var i = 0; i < 16; i++)
+ {
+ if (inUse16[i])
+ {
+ for (var j = 0; j < 16; j++)
+ {
+ inUse[i*16 + j] = (BsR(1) == 1);
+ }
+ }
+ else
+ {
+ for (var j = 0; j < 16; j++)
+ {
+ inUse[i*16 + j] = false;
+ }
+ }
+ }
+
+ MakeMaps();
+ var alphaSize = nInUse + 2;
+
+ //--- Now the selectors ---
+ var nGroups = BsR(3);
+ var nSelectors = BsR(15);
+
+ for (var i = 0; i < nSelectors; i++)
+ {
+ var j = 0;
+ while (BsR(1) == 1)
+ {
+ j++;
+ }
+ selectorMtf[i] = (byte) j;
+ }
+
+ //--- Undo the MTF values for the selectors. ---
+ var pos = new byte[BZip2Constants.N_GROUPS];
+ for (var v = 0; v < nGroups; v++)
+ {
+ pos[v] = (byte) v;
+ }
+
+ for (var i = 0; i < nSelectors; i++)
+ {
+ int v = selectorMtf[i];
+ var tmp = pos[v];
+ while (v > 0)
+ {
+ pos[v] = pos[v - 1];
+ v--;
+ }
+ pos[0] = tmp;
+ selector[i] = tmp;
+ }
+
+ //--- Now the coding tables ---
+ for (var t = 0; t < nGroups; t++)
+ {
+ var curr = BsR(5);
+ for (var i = 0; i < alphaSize; i++)
+ {
+ while (BsR(1) == 1)
+ {
+ if (BsR(1) == 0)
+ {
+ curr++;
+ }
+ else
+ {
+ curr--;
+ }
+ }
+ len[t][i] = (char) curr;
+ }
+ }
+
+ //--- Create the Huffman decoding tables ---
+ for (var t = 0; t < nGroups; t++)
+ {
+ var minLen = 32;
+ var maxLen = 0;
+ for (var i = 0; i < alphaSize; i++)
+ {
+ maxLen = Math.Max(maxLen, len[t][i]);
+ minLen = Math.Min(minLen, len[t][i]);
+ }
+ HbCreateDecodeTables(limit[t], baseArray[t], perm[t], len[t], minLen, maxLen, alphaSize);
+ minLens[t] = minLen;
+ }
+ }
+
+ private void GetAndMoveToFrontDecode()
+ {
+ var yy = new byte[256];
+
+ var limitLast = BZip2Constants.baseBlockSize*blockSize100k;
+ origPtr = BsGetIntVS(24);
+
+ RecvDecodingTables();
+ var EOB = nInUse + 1;
+ var groupNo = -1;
+ var groupPos = 0;
+
+ /*--
+ Setting up the unzftab entries here is not strictly
+ necessary, but it does save having to do it later
+ in a separate pass, and so saves a block's worth of
+ cache misses.
+ --*/
+ for (var i = 0; i <= 255; i++)
+ {
+ unzftab[i] = 0;
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ yy[i] = (byte) i;
+ }
+
+ last = -1;
+
+ if (groupPos == 0)
+ {
+ groupNo++;
+ groupPos = BZip2Constants.G_SIZE;
+ }
+
+ groupPos--;
+ int zt = selector[groupNo];
+ var zn = minLens[zt];
+ var zvec = BsR(zn);
+ int zj;
+
+ while (zvec > limit[zt][zn])
+ {
+ if (zn > 20)
+ {
+ // the longest code
+ throw new BZip2Exception("Bzip data error");
+ }
+ zn++;
+ while (bsLive < 1)
+ {
+ FillBuffer();
+ }
+ zj = (bsBuff >> (bsLive - 1)) & 1;
+ bsLive--;
+ zvec = (zvec << 1) | zj;
+ }
+ if (zvec - baseArray[zt][zn] < 0 || zvec - baseArray[zt][zn] >= BZip2Constants.MAX_ALPHA_SIZE)
+ {
+ throw new BZip2Exception("Bzip data error");
+ }
+ int nextSym = perm[zt][zvec - baseArray[zt][zn]];
+
+ while (true)
+ {
+ if (nextSym == EOB)
+ {
+ break;
+ }
+
+ if (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB)
+ {
+ var s = -1;
+ var n = 1;
+ do
+ {
+ if (nextSym == BZip2Constants.RUNA)
+ {
+ s += (0 + 1)*n;
+ }
+ else if (nextSym == BZip2Constants.RUNB)
+ {
+ s += (1 + 1)*n;
+ }
+
+ n <<= 1;
+
+ if (groupPos == 0)
+ {
+ groupNo++;
+ groupPos = BZip2Constants.G_SIZE;
+ }
+
+ groupPos--;
+
+ zt = selector[groupNo];
+ zn = minLens[zt];
+ zvec = BsR(zn);
+
+ while (zvec > limit[zt][zn])
+ {
+ zn++;
+ while (bsLive < 1)
+ {
+ FillBuffer();
+ }
+ zj = (bsBuff >> (bsLive - 1)) & 1;
+ bsLive--;
+ zvec = (zvec << 1) | zj;
+ }
+ nextSym = perm[zt][zvec - baseArray[zt][zn]];
+ } while (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB);
+
+ s++;
+ var ch = seqToUnseq[yy[0]];
+ unzftab[ch] += s;
+
+ while (s > 0)
+ {
+ last++;
+ ll8[last] = ch;
+ s--;
+ }
+
+ if (last >= limitLast)
+ {
+ BlockOverrun();
+ }
+ continue;
+ }
+ last++;
+ if (last >= limitLast)
+ {
+ BlockOverrun();
+ }
+
+ var tmp = yy[nextSym - 1];
+ unzftab[seqToUnseq[tmp]]++;
+ ll8[last] = seqToUnseq[tmp];
+
+ for (var j = nextSym - 1; j > 0; --j)
+ {
+ yy[j] = yy[j - 1];
+ }
+ yy[0] = tmp;
+
+ if (groupPos == 0)
+ {
+ groupNo++;
+ groupPos = BZip2Constants.G_SIZE;
+ }
+
+ groupPos--;
+ zt = selector[groupNo];
+ zn = minLens[zt];
+ zvec = BsR(zn);
+ while (zvec > limit[zt][zn])
+ {
+ zn++;
+ while (bsLive < 1)
+ {
+ FillBuffer();
+ }
+ zj = (bsBuff >> (bsLive - 1)) & 1;
+ bsLive--;
+ zvec = (zvec << 1) | zj;
+ }
+ nextSym = perm[zt][zvec - baseArray[zt][zn]];
+ continue;
+ }
+ }
+
+ private void SetupBlock()
+ {
+ var cftab = new int[257];
+
+ cftab[0] = 0;
+ Array.Copy(unzftab, 0, cftab, 1, 256);
+
+ for (var i = 1; i <= 256; i++)
+ {
+ cftab[i] += cftab[i - 1];
+ }
+
+ for (var i = 0; i <= last; i++)
+ {
+ var ch = ll8[i];
+ tt[cftab[ch]] = i;
+ cftab[ch]++;
+ }
+
+ tPos = tt[origPtr];
+
+ count = 0;
+ i2 = 0;
+ ch2 = 256; /*-- not a char and not EOF --*/
+
+ if (blockRandomised)
+ {
+ rNToGo = 0;
+ rTPos = 0;
+ SetupRandPartA();
+ }
+ else
+ {
+ SetupNoRandPartA();
+ }
+ }
+
+ private void SetupRandPartA()
+ {
+ if (i2 <= last)
+ {
+ chPrev = ch2;
+ ch2 = ll8[tPos];
+ tPos = tt[tPos];
+ if (rNToGo == 0)
+ {
+ rNToGo = BZip2Constants.rNums[rTPos];
+ rTPos++;
+ if (rTPos == 512)
+ {
+ rTPos = 0;
+ }
+ }
+ rNToGo--;
+ ch2 ^= ((rNToGo == 1) ? 1 : 0);
+ i2++;
+
+ currentChar = ch2;
+ currentState = RAND_PART_B_STATE;
+ mCrc.Update(ch2);
+ }
+ else
+ {
+ EndBlock();
+ InitBlock();
+ SetupBlock();
+ }
+ }
+
+ private void SetupNoRandPartA()
+ {
+ if (i2 <= last)
+ {
+ chPrev = ch2;
+ ch2 = ll8[tPos];
+ tPos = tt[tPos];
+ i2++;
+
+ currentChar = ch2;
+ currentState = NO_RAND_PART_B_STATE;
+ mCrc.Update(ch2);
+ }
+ else
+ {
+ EndBlock();
+ InitBlock();
+ SetupBlock();
+ }
+ }
+
+ private void SetupRandPartB()
+ {
+ if (ch2 != chPrev)
+ {
+ currentState = RAND_PART_A_STATE;
+ count = 1;
+ SetupRandPartA();
+ }
+ else
+ {
+ count++;
+ if (count >= 4)
+ {
+ z = ll8[tPos];
+ tPos = tt[tPos];
+ if (rNToGo == 0)
+ {
+ rNToGo = BZip2Constants.rNums[rTPos];
+ rTPos++;
+ if (rTPos == 512)
+ {
+ rTPos = 0;
+ }
+ }
+ rNToGo--;
+ z ^= (byte) ((rNToGo == 1) ? 1 : 0);
+ j2 = 0;
+ currentState = RAND_PART_C_STATE;
+ SetupRandPartC();
+ }
+ else
+ {
+ currentState = RAND_PART_A_STATE;
+ SetupRandPartA();
+ }
+ }
+ }
+
+ private void SetupRandPartC()
+ {
+ if (j2 < z)
+ {
+ currentChar = ch2;
+ mCrc.Update(ch2);
+ j2++;
+ }
+ else
+ {
+ currentState = RAND_PART_A_STATE;
+ i2++;
+ count = 0;
+ SetupRandPartA();
+ }
+ }
+
+ private void SetupNoRandPartB()
+ {
+ if (ch2 != chPrev)
+ {
+ currentState = NO_RAND_PART_A_STATE;
+ count = 1;
+ SetupNoRandPartA();
+ }
+ else
+ {
+ count++;
+ if (count >= 4)
+ {
+ z = ll8[tPos];
+ tPos = tt[tPos];
+ currentState = NO_RAND_PART_C_STATE;
+ j2 = 0;
+ SetupNoRandPartC();
+ }
+ else
+ {
+ currentState = NO_RAND_PART_A_STATE;
+ SetupNoRandPartA();
+ }
+ }
+ }
+
+ private void SetupNoRandPartC()
+ {
+ if (j2 < z)
+ {
+ currentChar = ch2;
+ mCrc.Update(ch2);
+ j2++;
+ }
+ else
+ {
+ currentState = NO_RAND_PART_A_STATE;
+ i2++;
+ count = 0;
+ SetupNoRandPartA();
+ }
+ }
+
+ private void SetDecompressStructureSizes(int newSize100k)
+ {
+ if (!(0 <= newSize100k && newSize100k <= 9 && 0 <= blockSize100k && blockSize100k <= 9))
+ {
+ throw new BZip2Exception("Invalid block size");
+ }
+
+ blockSize100k = newSize100k;
+
+ if (newSize100k == 0)
+ {
+ return;
+ }
+
+ var n = BZip2Constants.baseBlockSize*newSize100k;
+ ll8 = new byte[n];
+ tt = new int[n];
+ }
+
+ private static void CompressedStreamEOF()
+ {
+ throw new EndOfStreamException("BZip2 input stream end of compressed stream");
+ }
+
+ private static void BlockOverrun()
+ {
+ throw new BZip2Exception("BZip2 input stream block overrun");
+ }
+
+ private static void BadBlockHeader()
+ {
+ throw new BZip2Exception("BZip2 input stream bad block header");
+ }
+
+ private static void CrcError()
+ {
+ throw new BZip2Exception("BZip2 input stream crc error");
+ }
+
+ private static void HbCreateDecodeTables(int[] limit, int[] baseArray, int[] perm, char[] length, int minLen,
+ int maxLen, int alphaSize)
+ {
+ var pp = 0;
+
+ for (var i = minLen; i <= maxLen; ++i)
+ {
+ for (var j = 0; j < alphaSize; ++j)
+ {
+ if (length[j] == i)
+ {
+ perm[pp] = j;
+ ++pp;
+ }
+ }
+ }
+
+ for (var i = 0; i < BZip2Constants.MAX_CODE_LEN; i++)
+ {
+ baseArray[i] = 0;
+ }
+
+ for (var i = 0; i < alphaSize; i++)
+ {
+ ++baseArray[length[i] + 1];
+ }
+
+ for (var i = 1; i < BZip2Constants.MAX_CODE_LEN; i++)
+ {
+ baseArray[i] += baseArray[i - 1];
+ }
+
+ for (var i = 0; i < BZip2Constants.MAX_CODE_LEN; i++)
+ {
+ limit[i] = 0;
+ }
+
+ var vec = 0;
+
+ for (var i = minLen; i <= maxLen; i++)
+ {
+ vec += (baseArray[i + 1] - baseArray[i]);
+ limit[i] = vec - 1;
+ vec <<= 1;
+ }
+
+ for (var i = minLen + 1; i <= maxLen; i++)
+ {
+ baseArray[i] = ((limit[i - 1] + 1) << 1) - baseArray[i];
+ }
+ }
+
+ #region Instance Fields
+
+ /*--
+ index of the last char in the block, so
+ the block size == last + 1.
+ --*/
+
+ private readonly int[][] baseArray = new int[BZip2Constants.N_GROUPS][];
+ private readonly bool[] inUse = new bool[256];
+ private readonly int[][] limit = new int[BZip2Constants.N_GROUPS][];
+ private readonly IChecksum mCrc = new StrangeCRC();
+ private readonly int[] minLens = new int[BZip2Constants.N_GROUPS];
+ private readonly int[][] perm = new int[BZip2Constants.N_GROUPS][];
+
+ private readonly byte[] selector = new byte[BZip2Constants.MAX_SELECTORS];
+ private readonly byte[] selectorMtf = new byte[BZip2Constants.MAX_SELECTORS];
+ private readonly byte[] seqToUnseq = new byte[256];
+ private readonly byte[] unseqToSeq = new byte[256];
+
+ /*--
+ freq table collected to save a pass over the data
+ during decompression.
+ --*/
+ private readonly int[] unzftab = new int[256];
+
+ private Stream baseStream;
+ private bool blockRandomised;
+ private int blockSize100k;
+ private int bsBuff;
+ private int bsLive;
+ private int ch2;
+ private int chPrev;
+ private int computedBlockCRC;
+ private uint computedCombinedCRC;
+
+ private int count;
+ private int currentChar = -1;
+
+ private int currentState = START_BLOCK_STATE;
+ private int i2;
+ private bool isStreamOwner = true;
+ private int j2;
+ private int last;
+ private byte[] ll8;
+ private int nInUse;
+ private int origPtr;
+ private int rNToGo;
+ private int rTPos;
+ private int storedBlockCRC, storedCombinedCRC;
+ private bool streamEnd;
+ private int tPos;
+ private int[] tt;
+ private byte z;
+
+ #endregion
+ }
+}
+
+/* This file was derived from a file containing this license:
+ *
+ * This file is a part of bzip2 and/or libbzip2, a program and
+ * library for lossless, block-sorting data compression.
+ *
+ * Copyright (C) 1996-1998 Julian R Seward. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. The origin of this software must not be misrepresented; you must
+ * not claim that you wrote the original software. If you use this
+ * software in a product, an acknowledgment in the product
+ * documentation would be appreciated but is not required.
+ *
+ * 3. Altered source versions must be plainly marked as such, and must
+ * not be misrepresented as being the original software.
+ *
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Java version ported by Keiron Liddle, Aftex Software <keiron@aftexsw.com> 1999-2001
+ */
\ No newline at end of file
--- /dev/null
+// BZip2OutputStream.cs
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+using ICSharpCode.SharpZipLib.Silverlight.BZip2;
+using ICSharpCode.SharpZipLib.Silverlight.Checksums;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.BZip2
+{
+ /// <summary>
+ /// An output stream that compresses into the BZip2 format
+ /// including file header chars into another stream.
+ /// </summary>
+ public class BZip2OutputStream : Stream
+ {
+ #region Constants
+ const int SETMASK = (1 << 21);
+ const int CLEARMASK = (~SETMASK);
+ const int GREATER_ICOST = 15;
+ const int LESSER_ICOST = 0;
+ const int SMALL_THRESH = 20;
+ const int DEPTH_THRESH = 10;
+
+ /*--
+ If you are ever unlucky/improbable enough
+ to get a stack overflow whilst sorting,
+ increase the following constant and try
+ again. In practice I have never seen the
+ stack go above 27 elems, so the following
+ limit seems very generous.
+ --*/
+ const int QSORT_STACK_SIZE = 1000;
+
+ /*--
+ Knuth's increments seem to work better
+ than Incerpi-Sedgewick here. Possibly
+ because the number of elems to sort is
+ usually small, typically <= 20.
+ --*/
+ readonly int[] increments = new int[] {
+ 1, 4, 13, 40, 121, 364, 1093, 3280,
+ 9841, 29524, 88573, 265720,
+ 797161, 2391484
+ };
+ #endregion
+
+ #region Constructors
+ /// <summary>
+ /// Construct a default output stream with maximum block size
+ /// </summary>
+ /// <param name="stream">The stream to write BZip data onto.</param>
+ public BZip2OutputStream(Stream stream) : this(stream, 9)
+ {
+ }
+
+ /// <summary>
+ /// Initialise a new instance of the <see cref="BZip2OutputStream"></see>
+ /// for the specified stream, using the given blocksize.
+ /// </summary>
+ /// <param name="stream">The stream to write compressed data to.</param>
+ /// <param name="blockSize">The block size to use.</param>
+ /// <remarks>
+ /// Valid block sizes are in the range 1..9, with 1 giving
+ /// the lowest compression and 9 the highest.
+ /// </remarks>
+ public BZip2OutputStream(Stream stream, int blockSize)
+ {
+ BsSetStream(stream);
+
+ workFactor = 50;
+ if (blockSize > 9) {
+ blockSize = 9;
+ }
+
+ if (blockSize < 1) {
+ blockSize = 1;
+ }
+ blockSize100k = blockSize;
+ AllocateCompressStructures();
+ Initialize();
+ InitBlock();
+ }
+ #endregion
+
+ #region Destructor
+ /// <summary>
+ /// Ensures that resources are freed and other cleanup operations
+ /// are performed when the garbage collector reclaims the BZip2OutputStream.
+ /// </summary>
+ ~BZip2OutputStream()
+ {
+ Dispose(false);
+ }
+ #endregion
+
+ /// <summary>
+ /// Get/set flag indicating ownership of underlying stream.
+ /// When the flag is true <see cref="Close"></see> will close the underlying stream also.
+ /// </summary>
+ public bool IsStreamOwner
+ {
+ get { return isStreamOwner; }
+ set { isStreamOwner = value; }
+ }
+
+
+ #region Stream overrides
+ /// <summary>
+ /// Gets a value indicating whether the current stream supports reading
+ /// </summary>
+ public override bool CanRead
+ {
+ get {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the current stream supports seeking
+ /// </summary>
+ public override bool CanSeek {
+ get {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the current stream supports writing
+ /// </summary>
+ public override bool CanWrite {
+ get {
+ return baseStream.CanWrite;
+ }
+ }
+
+ /// <summary>
+ /// Gets the length in bytes of the stream
+ /// </summary>
+ public override long Length {
+ get {
+ return baseStream.Length;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the current position of this stream.
+ /// </summary>
+ public override long Position {
+ get {
+ return baseStream.Position;
+ }
+ set {
+ throw new NotSupportedException("BZip2OutputStream position cannot be set");
+ }
+ }
+
+ /// <summary>
+ /// Sets the current position of this stream to the given value.
+ /// </summary>
+ /// <param name="offset">The point relative to the offset from which to being seeking.</param>
+ /// <param name="origin">The reference point from which to begin seeking.</param>
+ /// <returns>The new position in the stream.</returns>
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new NotSupportedException("BZip2OutputStream Seek not supported");
+ }
+
+ /// <summary>
+ /// Sets the length of this stream to the given value.
+ /// </summary>
+ /// <param name="value">The new stream length.</param>
+ public override void SetLength(long value)
+ {
+ throw new NotSupportedException("BZip2OutputStream SetLength not supported");
+ }
+
+ /// <summary>
+ /// Read a byte from the stream advancing the position.
+ /// </summary>
+ /// <returns>The byte read cast to an int; -1 if end of stream.</returns>
+ public override int ReadByte()
+ {
+ throw new NotSupportedException("BZip2OutputStream ReadByte not supported");
+ }
+
+ /// <summary>
+ /// Read a block of bytes
+ /// </summary>
+ /// <param name="buffer">The buffer to read into.</param>
+ /// <param name="offset">The offset in the buffer to start storing data at.</param>
+ /// <param name="count">The maximum number of bytes to read.</param>
+ /// <returns>The total number of bytes read. This might be less than the number of bytes
+ /// requested if that number of bytes are not currently available, or zero
+ /// if the end of the stream is reached.</returns>
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ throw new NotSupportedException("BZip2OutputStream Read not supported");
+ }
+
+ /// <summary>
+ /// Write a block of bytes to the stream
+ /// </summary>
+ /// <param name="buffer">The buffer containing data to write.</param>
+ /// <param name="offset">The offset of the first byte to write.</param>
+ /// <param name="count">The number of bytes to write.</param>
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ if ( buffer == null ) {
+ throw new ArgumentNullException("buffer");
+ }
+
+ if ( offset < 0 )
+ {
+ throw new ArgumentOutOfRangeException("offset");
+ }
+
+ if ( count < 0 )
+ {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ if ( buffer.Length - offset < count )
+ {
+ throw new ArgumentException("Offset/count out of range");
+ }
+
+ for (int i = 0; i < count; ++i) {
+ WriteByte(buffer[offset + i]);
+ }
+ }
+
+ /// <summary>
+ /// Write a byte to the stream.
+ /// </summary>
+ /// <param name="value">The byte to write to the stream.</param>
+ public override void WriteByte(byte value)
+ {
+ int b = (256 + value) % 256;
+ if (currentChar != -1) {
+ if (currentChar == b) {
+ runLength++;
+ if (runLength > 254) {
+ WriteRun();
+ currentChar = -1;
+ runLength = 0;
+ }
+ } else {
+ WriteRun();
+ runLength = 1;
+ currentChar = b;
+ }
+ } else {
+ currentChar = b;
+ runLength++;
+ }
+ }
+
+ /// <summary>
+ /// End the current block and end compression.
+ /// Close the stream and free any resources
+ /// </summary>
+ public override void Close()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ void MakeMaps()
+ {
+ nInUse = 0;
+ for (int i = 0; i < 256; i++) {
+ if (inUse[i]) {
+ seqToUnseq[nInUse] = (char)i;
+ unseqToSeq[i] = (char)nInUse;
+ nInUse++;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Get the number of bytes written to output.
+ /// </summary>
+ void WriteRun()
+ {
+ if (last < allowableBlockSize) {
+ inUse[currentChar] = true;
+ for (int i = 0; i < runLength; i++) {
+ mCrc.Update(currentChar);
+ }
+
+ switch (runLength) {
+ case 1:
+ last++;
+ block[last + 1] = (byte)currentChar;
+ break;
+ case 2:
+ last++;
+ block[last + 1] = (byte)currentChar;
+ last++;
+ block[last + 1] = (byte)currentChar;
+ break;
+ case 3:
+ last++;
+ block[last + 1] = (byte)currentChar;
+ last++;
+ block[last + 1] = (byte)currentChar;
+ last++;
+ block[last + 1] = (byte)currentChar;
+ break;
+ default:
+ inUse[runLength - 4] = true;
+ last++;
+ block[last + 1] = (byte)currentChar;
+ last++;
+ block[last + 1] = (byte)currentChar;
+ last++;
+ block[last + 1] = (byte)currentChar;
+ last++;
+ block[last + 1] = (byte)currentChar;
+ last++;
+ block[last + 1] = (byte)(runLength - 4);
+ break;
+ }
+ } else {
+ EndBlock();
+ InitBlock();
+ WriteRun();
+ }
+ }
+
+ /// <summary>
+ /// Get the number of bytes written to the output.
+ /// </summary>
+ public int BytesWritten
+ {
+ get { return bytesOut; }
+ }
+
+ /// <summary>
+ /// Releases the unmanaged resources used by the <see cref="BZip2OutputStream"/> and optionally releases the managed resources.
+ /// </summary>
+ /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
+ override protected void Dispose(bool disposing)
+ {
+ try {
+ base.Dispose(disposing);
+ if( !disposed_ ) {
+ disposed_=true;
+
+ if( runLength>0 ) {
+ WriteRun();
+ }
+
+ currentChar=-1;
+ EndBlock();
+ EndCompression();
+ Flush();
+ }
+ }
+ finally {
+ if ( disposing ) {
+ if ( IsStreamOwner ) {
+ baseStream.Close();
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Flush output buffers
+ /// </summary>
+ public override void Flush()
+ {
+ baseStream.Flush();
+ }
+
+ void Initialize()
+ {
+ bytesOut = 0;
+ nBlocksRandomised = 0;
+
+ /*--- Write header `magic' bytes indicating file-format == huffmanised,
+ followed by a digit indicating blockSize100k.
+ ---*/
+
+ BsPutUChar('B');
+ BsPutUChar('Z');
+
+ BsPutUChar('h');
+ BsPutUChar('0' + blockSize100k);
+
+ combinedCRC = 0;
+ }
+
+ void InitBlock()
+ {
+ mCrc.Reset();
+ last = -1;
+
+ for (int i = 0; i < 256; i++) {
+ inUse[i] = false;
+ }
+
+ /*--- 20 is just a paranoia constant ---*/
+ allowableBlockSize = BZip2Constants.baseBlockSize * blockSize100k - 20;
+ }
+
+ void EndBlock()
+ {
+ if (last < 0) { // dont do anything for empty files, (makes empty files compatible with original Bzip)
+ return;
+ }
+
+ blockCRC = unchecked((uint)mCrc.Value);
+ combinedCRC = (combinedCRC << 1) | (combinedCRC >> 31);
+ combinedCRC ^= blockCRC;
+
+ /*-- sort the block and establish position of original string --*/
+ DoReversibleTransformation();
+
+ /*--
+ A 6-byte block header, the value chosen arbitrarily
+ as 0x314159265359 :-). A 32 bit value does not really
+ give a strong enough guarantee that the value will not
+ appear by chance in the compressed datastream. Worst-case
+ probability of this event, for a 900k block, is about
+ 2.0e-3 for 32 bits, 1.0e-5 for 40 bits and 4.0e-8 for 48 bits.
+ For a compressed file of size 100Gb -- about 100000 blocks --
+ only a 48-bit marker will do. NB: normal compression/
+ decompression do *not* rely on these statistical properties.
+ They are only important when trying to recover blocks from
+ damaged files.
+ --*/
+ BsPutUChar(0x31);
+ BsPutUChar(0x41);
+ BsPutUChar(0x59);
+ BsPutUChar(0x26);
+ BsPutUChar(0x53);
+ BsPutUChar(0x59);
+
+ /*-- Now the block's CRC, so it is in a known place. --*/
+ unchecked {
+ BsPutint((int)blockCRC);
+ }
+
+ /*-- Now a single bit indicating randomisation. --*/
+ if (blockRandomised) {
+ BsW(1,1);
+ nBlocksRandomised++;
+ } else {
+ BsW(1,0);
+ }
+
+ /*-- Finally, block's contents proper. --*/
+ MoveToFrontCodeAndSend();
+ }
+
+ void EndCompression()
+ {
+ /*--
+ Now another magic 48-bit number, 0x177245385090, to
+ indicate the end of the last block. (sqrt(pi), if
+ you want to know. I did want to use e, but it contains
+ too much repetition -- 27 18 28 18 28 46 -- for me
+ to feel statistically comfortable. Call me paranoid.)
+ --*/
+ BsPutUChar(0x17);
+ BsPutUChar(0x72);
+ BsPutUChar(0x45);
+ BsPutUChar(0x38);
+ BsPutUChar(0x50);
+ BsPutUChar(0x90);
+
+ unchecked {
+ BsPutint((int)combinedCRC);
+ }
+
+ BsFinishedWithStream();
+ }
+
+ void BsSetStream(Stream stream)
+ {
+ baseStream = stream;
+ bsLive = 0;
+ bsBuff = 0;
+ bytesOut = 0;
+ }
+
+ void BsFinishedWithStream()
+ {
+ while (bsLive > 0)
+ {
+ int ch = (bsBuff >> 24);
+ baseStream.WriteByte((byte)ch); // write 8-bit
+ bsBuff <<= 8;
+ bsLive -= 8;
+ bytesOut++;
+ }
+ }
+
+ void BsW(int n, int v)
+ {
+ while (bsLive >= 8) {
+ int ch = (bsBuff >> 24);
+ unchecked{baseStream.WriteByte((byte)ch);} // write 8-bit
+ bsBuff <<= 8;
+ bsLive -= 8;
+ ++bytesOut;
+ }
+ bsBuff |= (v << (32 - bsLive - n));
+ bsLive += n;
+ }
+
+ void BsPutUChar(int c)
+ {
+ BsW(8, c);
+ }
+
+ void BsPutint(int u)
+ {
+ BsW(8, (u >> 24) & 0xFF);
+ BsW(8, (u >> 16) & 0xFF);
+ BsW(8, (u >> 8) & 0xFF);
+ BsW(8, u & 0xFF);
+ }
+
+ void BsPutIntVS(int numBits, int c)
+ {
+ BsW(numBits, c);
+ }
+
+ void SendMTFValues()
+ {
+ char[][] len = new char[BZip2Constants.N_GROUPS][];
+ for (int i = 0; i < BZip2Constants.N_GROUPS; ++i) {
+ len[i] = new char[BZip2Constants.MAX_ALPHA_SIZE];
+ }
+
+ int gs, ge, totc, bt, bc, iter;
+ int nSelectors = 0, alphaSize, minLen, maxLen, selCtr;
+ int nGroups;
+
+ alphaSize = nInUse + 2;
+ for (int t = 0; t < BZip2Constants.N_GROUPS; t++) {
+ for (int v = 0; v < alphaSize; v++) {
+ len[t][v] = (char)GREATER_ICOST;
+ }
+ }
+
+ /*--- Decide how many coding tables to use ---*/
+ if (nMTF <= 0) {
+ Panic();
+ }
+
+ if (nMTF < 200) {
+ nGroups = 2;
+ } else if (nMTF < 600) {
+ nGroups = 3;
+ } else if (nMTF < 1200) {
+ nGroups = 4;
+ } else if (nMTF < 2400) {
+ nGroups = 5;
+ } else {
+ nGroups = 6;
+ }
+
+ /*--- Generate an initial set of coding tables ---*/
+ int nPart = nGroups;
+ int remF = nMTF;
+ gs = 0;
+ while (nPart > 0) {
+ int tFreq = remF / nPart;
+ int aFreq = 0;
+ ge = gs - 1;
+ while (aFreq < tFreq && ge < alphaSize - 1) {
+ ge++;
+ aFreq += mtfFreq[ge];
+ }
+
+ if (ge > gs && nPart != nGroups && nPart != 1 && ((nGroups - nPart) % 2 == 1)) {
+ aFreq -= mtfFreq[ge];
+ ge--;
+ }
+
+ for (int v = 0; v < alphaSize; v++) {
+ if (v >= gs && v <= ge) {
+ len[nPart - 1][v] = (char)LESSER_ICOST;
+ } else {
+ len[nPart - 1][v] = (char)GREATER_ICOST;
+ }
+ }
+
+ nPart--;
+ gs = ge + 1;
+ remF -= aFreq;
+ }
+
+ int[][] rfreq = new int[BZip2Constants.N_GROUPS][];
+ for (int i = 0; i < BZip2Constants.N_GROUPS; ++i) {
+ rfreq[i] = new int[BZip2Constants.MAX_ALPHA_SIZE];
+ }
+
+ int[] fave = new int[BZip2Constants.N_GROUPS];
+ short[] cost = new short[BZip2Constants.N_GROUPS];
+ /*---
+ Iterate up to N_ITERS times to improve the tables.
+ ---*/
+ for (iter = 0; iter < BZip2Constants.N_ITERS; ++iter) {
+ for (int t = 0; t < nGroups; ++t) {
+ fave[t] = 0;
+ }
+
+ for (int t = 0; t < nGroups; ++t) {
+ for (int v = 0; v < alphaSize; ++v) {
+ rfreq[t][v] = 0;
+ }
+ }
+
+ nSelectors = 0;
+ totc = 0;
+ gs = 0;
+ while (true) {
+ /*--- Set group start & end marks. --*/
+ if (gs >= nMTF) {
+ break;
+ }
+ ge = gs + BZip2Constants.G_SIZE - 1;
+ if (ge >= nMTF) {
+ ge = nMTF - 1;
+ }
+
+ /*--
+ Calculate the cost of this group as coded
+ by each of the coding tables.
+ --*/
+ for (int t = 0; t < nGroups; t++) {
+ cost[t] = 0;
+ }
+
+ if (nGroups == 6) {
+ short cost0, cost1, cost2, cost3, cost4, cost5;
+ cost0 = cost1 = cost2 = cost3 = cost4 = cost5 = 0;
+ for (int i = gs; i <= ge; ++i) {
+ short icv = szptr[i];
+ cost0 += (short)len[0][icv];
+ cost1 += (short)len[1][icv];
+ cost2 += (short)len[2][icv];
+ cost3 += (short)len[3][icv];
+ cost4 += (short)len[4][icv];
+ cost5 += (short)len[5][icv];
+ }
+ cost[0] = cost0;
+ cost[1] = cost1;
+ cost[2] = cost2;
+ cost[3] = cost3;
+ cost[4] = cost4;
+ cost[5] = cost5;
+ } else {
+ for (int i = gs; i <= ge; ++i) {
+ short icv = szptr[i];
+ for (int t = 0; t < nGroups; t++) {
+ cost[t] += (short)len[t][icv];
+ }
+ }
+ }
+
+ /*--
+ Find the coding table which is best for this group,
+ and record its identity in the selector table.
+ --*/
+ bc = 999999999;
+ bt = -1;
+ for (int t = 0; t < nGroups; ++t) {
+ if (cost[t] < bc) {
+ bc = cost[t];
+ bt = t;
+ }
+ }
+ totc += bc;
+ fave[bt]++;
+ selector[nSelectors] = (char)bt;
+ nSelectors++;
+
+ /*--
+ Increment the symbol frequencies for the selected table.
+ --*/
+ for (int i = gs; i <= ge; ++i) {
+ ++rfreq[bt][szptr[i]];
+ }
+
+ gs = ge+1;
+ }
+
+ /*--
+ Recompute the tables based on the accumulated frequencies.
+ --*/
+ for (int t = 0; t < nGroups; ++t) {
+ HbMakeCodeLengths(len[t], rfreq[t], alphaSize, 20);
+ }
+ }
+
+ rfreq = null;
+ fave = null;
+ cost = null;
+
+ if (!(nGroups < 8)) {
+ Panic();
+ }
+
+ if (!(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZip2Constants.G_SIZE)))) {
+ Panic();
+ }
+
+ /*--- Compute MTF values for the selectors. ---*/
+ char[] pos = new char[BZip2Constants.N_GROUPS];
+ char ll_i, tmp2, tmp;
+
+ for (int i = 0; i < nGroups; i++) {
+ pos[i] = (char)i;
+ }
+
+ for (int i = 0; i < nSelectors; i++) {
+ ll_i = selector[i];
+ int j = 0;
+ tmp = pos[j];
+ while (ll_i != tmp) {
+ j++;
+ tmp2 = tmp;
+ tmp = pos[j];
+ pos[j] = tmp2;
+ }
+ pos[0] = tmp;
+ selectorMtf[i] = (char)j;
+ }
+
+ int[][] code = new int[BZip2Constants.N_GROUPS][];
+
+ for (int i = 0; i < BZip2Constants.N_GROUPS; ++i) {
+ code[i] = new int[BZip2Constants.MAX_ALPHA_SIZE];
+ }
+
+ /*--- Assign actual codes for the tables. --*/
+ for (int t = 0; t < nGroups; t++) {
+ minLen = 32;
+ maxLen = 0;
+ for (int i = 0; i < alphaSize; i++) {
+ if (len[t][i] > maxLen) {
+ maxLen = len[t][i];
+ }
+ if (len[t][i] < minLen) {
+ minLen = len[t][i];
+ }
+ }
+ if (maxLen > 20) {
+ Panic();
+ }
+ if (minLen < 1) {
+ Panic();
+ }
+ HbAssignCodes(code[t], len[t], minLen, maxLen, alphaSize);
+ }
+
+ /*--- Transmit the mapping table. ---*/
+ bool[] inUse16 = new bool[16];
+ for (int i = 0; i < 16; ++i) {
+ inUse16[i] = false;
+ for (int j = 0; j < 16; ++j) {
+ if (inUse[i * 16 + j]) {
+ inUse16[i] = true;
+ }
+ }
+ }
+
+ for (int i = 0; i < 16; ++i) {
+ if (inUse16[i]) {
+ BsW(1,1);
+ } else {
+ BsW(1,0);
+ }
+ }
+
+ for (int i = 0; i < 16; ++i) {
+ if (inUse16[i]) {
+ for (int j = 0; j < 16; ++j) {
+ if (inUse[i * 16 + j]) {
+ BsW(1,1);
+ } else {
+ BsW(1,0);
+ }
+ }
+ }
+ }
+
+ /*--- Now the selectors. ---*/
+ BsW(3, nGroups);
+ BsW(15, nSelectors);
+ for (int i = 0; i < nSelectors; ++i) {
+ for (int j = 0; j < selectorMtf[i]; ++j) {
+ BsW(1,1);
+ }
+ BsW(1,0);
+ }
+
+ /*--- Now the coding tables. ---*/
+ for (int t = 0; t < nGroups; ++t) {
+ int curr = len[t][0];
+ BsW(5, curr);
+ for (int i = 0; i < alphaSize; ++i) {
+ while (curr < len[t][i]) {
+ BsW(2, 2);
+ curr++; /* 10 */
+ }
+ while (curr > len[t][i]) {
+ BsW(2, 3);
+ curr--; /* 11 */
+ }
+ BsW (1, 0);
+ }
+ }
+
+ /*--- And finally, the block data proper ---*/
+ selCtr = 0;
+ gs = 0;
+ while (true) {
+ if (gs >= nMTF) {
+ break;
+ }
+ ge = gs + BZip2Constants.G_SIZE - 1;
+ if (ge >= nMTF) {
+ ge = nMTF - 1;
+ }
+
+ for (int i = gs; i <= ge; i++) {
+ BsW(len[selector[selCtr]][szptr[i]], code[selector[selCtr]][szptr[i]]);
+ }
+
+ gs = ge + 1;
+ ++selCtr;
+ }
+ if (!(selCtr == nSelectors)) {
+ Panic();
+ }
+ }
+
+ void MoveToFrontCodeAndSend ()
+ {
+ BsPutIntVS(24, origPtr);
+ GenerateMTFValues();
+ SendMTFValues();
+ }
+
+ void SimpleSort(int lo, int hi, int d)
+ {
+ int i, j, h, bigN, hp;
+ int v;
+
+ bigN = hi - lo + 1;
+ if (bigN < 2) {
+ return;
+ }
+
+ hp = 0;
+ while (increments[hp] < bigN) {
+ hp++;
+ }
+ hp--;
+
+ for (; hp >= 0; hp--) {
+ h = increments[hp];
+
+ i = lo + h;
+ while (true) {
+ /*-- copy 1 --*/
+ if (i > hi)
+ break;
+ v = zptr[i];
+ j = i;
+ while (FullGtU(zptr[j-h]+d, v+d)) {
+ zptr[j] = zptr[j-h];
+ j = j - h;
+ if (j <= (lo + h - 1))
+ break;
+ }
+ zptr[j] = v;
+ i++;
+
+ /*-- copy 2 --*/
+ if (i > hi) {
+ break;
+ }
+ v = zptr[i];
+ j = i;
+ while (FullGtU ( zptr[j-h]+d, v+d )) {
+ zptr[j] = zptr[j-h];
+ j = j - h;
+ if (j <= (lo + h - 1)) {
+ break;
+ }
+ }
+ zptr[j] = v;
+ i++;
+
+ /*-- copy 3 --*/
+ if (i > hi) {
+ break;
+ }
+ v = zptr[i];
+ j = i;
+ while (FullGtU ( zptr[j-h]+d, v+d)) {
+ zptr[j] = zptr[j-h];
+ j = j - h;
+ if (j <= (lo + h - 1)) {
+ break;
+ }
+ }
+ zptr[j] = v;
+ i++;
+
+ if (workDone > workLimit && firstAttempt) {
+ return;
+ }
+ }
+ }
+ }
+
+ void Vswap(int p1, int p2, int n )
+ {
+ int temp = 0;
+ while (n > 0) {
+ temp = zptr[p1];
+ zptr[p1] = zptr[p2];
+ zptr[p2] = temp;
+ p1++;
+ p2++;
+ n--;
+ }
+ }
+
+ void QSort3(int loSt, int hiSt, int dSt)
+ {
+ int unLo, unHi, ltLo, gtHi, med, n, m;
+ int lo, hi, d;
+ StackElement[] stack = new StackElement[QSORT_STACK_SIZE];
+ for (int count = 0; count < QSORT_STACK_SIZE; count++) {
+ stack[count] = new StackElement();
+ }
+
+ int sp = 0;
+
+ stack[sp].ll = loSt;
+ stack[sp].hh = hiSt;
+ stack[sp].dd = dSt;
+ sp++;
+
+ while (sp > 0) {
+ if (sp >= QSORT_STACK_SIZE) {
+ Panic();
+ }
+
+ sp--;
+ lo = stack[sp].ll;
+ hi = stack[sp].hh;
+ d = stack[sp].dd;
+
+ if (hi - lo < SMALL_THRESH || d > DEPTH_THRESH) {
+ SimpleSort(lo, hi, d);
+ if (workDone > workLimit && firstAttempt) {
+ return;
+ }
+ continue;
+ }
+
+ med = Med3(block[zptr[lo] + d + 1],
+ block[zptr[hi ] + d + 1],
+ block[zptr[(lo + hi) >> 1] + d + 1]);
+
+ unLo = ltLo = lo;
+ unHi = gtHi = hi;
+
+ while (true) {
+ while (true) {
+ if (unLo > unHi) {
+ break;
+ }
+ n = ((int)block[zptr[unLo]+d + 1]) - med;
+ if (n == 0) {
+ int temp = 0;
+ temp = zptr[unLo];
+ zptr[unLo] = zptr[ltLo];
+ zptr[ltLo] = temp;
+ ltLo++;
+ unLo++;
+ continue;
+ }
+ if (n > 0) {
+ break;
+ }
+ unLo++;
+ }
+
+ while (true) {
+ if (unLo > unHi) {
+ break;
+ }
+ n = ((int)block[zptr[unHi]+d + 1]) - med;
+ if (n == 0) {
+ int temp = 0;
+ temp = zptr[unHi];
+ zptr[unHi] = zptr[gtHi];
+ zptr[gtHi] = temp;
+ gtHi--;
+ unHi--;
+ continue;
+ }
+ if (n < 0) {
+ break;
+ }
+ unHi--;
+ }
+
+ if (unLo > unHi) {
+ break;
+ }
+
+ {
+ int temp = zptr[unLo];
+ zptr[unLo] = zptr[unHi];
+ zptr[unHi] = temp;
+ unLo++;
+ unHi--;
+ }
+ }
+
+ if (gtHi < ltLo) {
+ stack[sp].ll = lo;
+ stack[sp].hh = hi;
+ stack[sp].dd = d+1;
+ sp++;
+ continue;
+ }
+
+ n = ((ltLo-lo) < (unLo-ltLo)) ? (ltLo-lo) : (unLo-ltLo);
+ Vswap(lo, unLo-n, n);
+ m = ((hi-gtHi) < (gtHi-unHi)) ? (hi-gtHi) : (gtHi-unHi);
+ Vswap(unLo, hi-m+1, m);
+
+ n = lo + unLo - ltLo - 1;
+ m = hi - (gtHi - unHi) + 1;
+
+ stack[sp].ll = lo;
+ stack[sp].hh = n;
+ stack[sp].dd = d;
+ sp++;
+
+ stack[sp].ll = n + 1;
+ stack[sp].hh = m - 1;
+ stack[sp].dd = d+1;
+ sp++;
+
+ stack[sp].ll = m;
+ stack[sp].hh = hi;
+ stack[sp].dd = d;
+ sp++;
+ }
+ }
+
+ void MainSort()
+ {
+ int i, j, ss, sb;
+ int[] runningOrder = new int[256];
+ int[] copy = new int[256];
+ bool[] bigDone = new bool[256];
+ int c1, c2;
+ int numQSorted;
+
+ /*--
+ In the various block-sized structures, live data runs
+ from 0 to last+NUM_OVERSHOOT_BYTES inclusive. First,
+ set up the overshoot area for block.
+ --*/
+
+ // if (verbosity >= 4) fprintf ( stderr, " sort initialise ...\n" );
+ for (i = 0; i < BZip2Constants.NUM_OVERSHOOT_BYTES; i++) {
+ block[last + i + 2] = block[(i % (last + 1)) + 1];
+ }
+ for (i = 0; i <= last + BZip2Constants.NUM_OVERSHOOT_BYTES; i++) {
+ quadrant[i] = 0;
+ }
+
+ block[0] = (byte)(block[last + 1]);
+
+ if (last < 4000) {
+ /*--
+ Use simpleSort(), since the full sorting mechanism
+ has quite a large constant overhead.
+ --*/
+ for (i = 0; i <= last; i++) {
+ zptr[i] = i;
+ }
+ firstAttempt = false;
+ workDone = workLimit = 0;
+ SimpleSort(0, last, 0);
+ } else {
+ numQSorted = 0;
+ for (i = 0; i <= 255; i++) {
+ bigDone[i] = false;
+ }
+ for (i = 0; i <= 65536; i++) {
+ ftab[i] = 0;
+ }
+
+ c1 = block[0];
+ for (i = 0; i <= last; i++) {
+ c2 = block[i + 1];
+ ftab[(c1 << 8) + c2]++;
+ c1 = c2;
+ }
+
+ for (i = 1; i <= 65536; i++) {
+ ftab[i] += ftab[i - 1];
+ }
+
+ c1 = block[1];
+ for (i = 0; i < last; i++) {
+ c2 = block[i + 2];
+ j = (c1 << 8) + c2;
+ c1 = c2;
+ ftab[j]--;
+ zptr[ftab[j]] = i;
+ }
+
+ j = ((block[last + 1]) << 8) + (block[1]);
+ ftab[j]--;
+ zptr[ftab[j]] = last;
+
+ /*--
+ Now ftab contains the first loc of every small bucket.
+ Calculate the running order, from smallest to largest
+ big bucket.
+ --*/
+
+ for (i = 0; i <= 255; i++) {
+ runningOrder[i] = i;
+ }
+
+ int vv;
+ int h = 1;
+ do {
+ h = 3 * h + 1;
+ } while (h <= 256);
+ do {
+ h = h / 3;
+ for (i = h; i <= 255; i++) {
+ vv = runningOrder[i];
+ j = i;
+ while ((ftab[((runningOrder[j-h])+1) << 8] - ftab[(runningOrder[j-h]) << 8]) > (ftab[((vv)+1) << 8] - ftab[(vv) << 8])) {
+ runningOrder[j] = runningOrder[j-h];
+ j = j - h;
+ if (j <= (h - 1)) {
+ break;
+ }
+ }
+ runningOrder[j] = vv;
+ }
+ } while (h != 1);
+
+ /*--
+ The main sorting loop.
+ --*/
+ for (i = 0; i <= 255; i++) {
+
+ /*--
+ Process big buckets, starting with the least full.
+ --*/
+ ss = runningOrder[i];
+
+ /*--
+ Complete the big bucket [ss] by quicksorting
+ any unsorted small buckets [ss, j]. Hopefully
+ previous pointer-scanning phases have already
+ completed many of the small buckets [ss, j], so
+ we don't have to sort them at all.
+ --*/
+ for (j = 0; j <= 255; j++) {
+ sb = (ss << 8) + j;
+ if(!((ftab[sb] & SETMASK) == SETMASK)) {
+ int lo = ftab[sb] & CLEARMASK;
+ int hi = (ftab[sb+1] & CLEARMASK) - 1;
+ if (hi > lo) {
+ QSort3(lo, hi, 2);
+ numQSorted += (hi - lo + 1);
+ if (workDone > workLimit && firstAttempt) {
+ return;
+ }
+ }
+ ftab[sb] |= SETMASK;
+ }
+ }
+
+ /*--
+ The ss big bucket is now done. Record this fact,
+ and update the quadrant descriptors. Remember to
+ update quadrants in the overshoot area too, if
+ necessary. The "if (i < 255)" test merely skips
+ this updating for the last bucket processed, since
+ updating for the last bucket is pointless.
+ --*/
+ bigDone[ss] = true;
+
+ if (i < 255) {
+ int bbStart = ftab[ss << 8] & CLEARMASK;
+ int bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart;
+ int shifts = 0;
+
+ while ((bbSize >> shifts) > 65534) {
+ shifts++;
+ }
+
+ for (j = 0; j < bbSize; j++) {
+ int a2update = zptr[bbStart + j];
+ int qVal = (j >> shifts);
+ quadrant[a2update] = qVal;
+ if (a2update < BZip2Constants.NUM_OVERSHOOT_BYTES) {
+ quadrant[a2update + last + 1] = qVal;
+ }
+ }
+
+ if (!(((bbSize-1) >> shifts) <= 65535)) {
+ Panic();
+ }
+ }
+
+ /*--
+ Now scan this big bucket so as to synthesise the
+ sorted order for small buckets [t, ss] for all t != ss.
+ --*/
+ for (j = 0; j <= 255; j++) {
+ copy[j] = ftab[(j << 8) + ss] & CLEARMASK;
+ }
+
+ for (j = ftab[ss << 8] & CLEARMASK; j < (ftab[(ss+1) << 8] & CLEARMASK); j++) {
+ c1 = block[zptr[j]];
+ if (!bigDone[c1]) {
+ zptr[copy[c1]] = zptr[j] == 0 ? last : zptr[j] - 1;
+ copy[c1] ++;
+ }
+ }
+
+ for (j = 0; j <= 255; j++) {
+ ftab[(j << 8) + ss] |= SETMASK;
+ }
+ }
+ }
+ }
+
+ void RandomiseBlock()
+ {
+ int i;
+ int rNToGo = 0;
+ int rTPos = 0;
+ for (i = 0; i < 256; i++) {
+ inUse[i] = false;
+ }
+
+ for (i = 0; i <= last; i++) {
+ if (rNToGo == 0) {
+ rNToGo = (int)BZip2Constants.rNums[rTPos];
+ rTPos++;
+ if (rTPos == 512) {
+ rTPos = 0;
+ }
+ }
+ rNToGo--;
+ block[i + 1] ^= (byte)((rNToGo == 1) ? 1 : 0);
+ // handle 16 bit signed numbers
+ block[i + 1] &= 0xFF;
+
+ inUse[block[i + 1]] = true;
+ }
+ }
+
+ void DoReversibleTransformation()
+ {
+ workLimit = workFactor * last;
+ workDone = 0;
+ blockRandomised = false;
+ firstAttempt = true;
+
+ MainSort();
+
+ if (workDone > workLimit && firstAttempt) {
+ RandomiseBlock();
+ workLimit = workDone = 0;
+ blockRandomised = true;
+ firstAttempt = false;
+ MainSort();
+ }
+
+ origPtr = -1;
+ for (int i = 0; i <= last; i++) {
+ if (zptr[i] == 0) {
+ origPtr = i;
+ break;
+ }
+ }
+
+ if (origPtr == -1) {
+ Panic();
+ }
+ }
+
+ bool FullGtU(int i1, int i2)
+ {
+ int k;
+ byte c1, c2;
+ int s1, s2;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return c1 > c2;
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return c1 > c2;
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return c1 > c2;
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return c1 > c2;
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return c1 > c2;
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return c1 > c2;
+ }
+ i1++;
+ i2++;
+
+ k = last + 1;
+
+ do {
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return c1 > c2;
+ }
+ s1 = quadrant[i1];
+ s2 = quadrant[i2];
+ if (s1 != s2) {
+ return s1 > s2;
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return c1 > c2;
+ }
+ s1 = quadrant[i1];
+ s2 = quadrant[i2];
+ if (s1 != s2) {
+ return s1 > s2;
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return c1 > c2;
+ }
+ s1 = quadrant[i1];
+ s2 = quadrant[i2];
+ if (s1 != s2) {
+ return s1 > s2;
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return c1 > c2;
+ }
+ s1 = quadrant[i1];
+ s2 = quadrant[i2];
+ if (s1 != s2) {
+ return s1 > s2;
+ }
+ i1++;
+ i2++;
+
+ if (i1 > last) {
+ i1 -= last;
+ i1--;
+ }
+ if (i2 > last) {
+ i2 -= last;
+ i2--;
+ }
+
+ k -= 4;
+ ++workDone;
+ } while (k >= 0);
+
+ return false;
+ }
+
+ void AllocateCompressStructures()
+ {
+ int n = BZip2Constants.baseBlockSize * blockSize100k;
+ block = new byte[(n + 1 + BZip2Constants.NUM_OVERSHOOT_BYTES)];
+ quadrant = new int[(n + BZip2Constants.NUM_OVERSHOOT_BYTES)];
+ zptr = new int[n];
+ ftab = new int[65537];
+
+ if (block == null || quadrant == null || zptr == null || ftab == null) {
+ // int totalDraw = (n + 1 + NUM_OVERSHOOT_BYTES) + (n + NUM_OVERSHOOT_BYTES) + n + 65537;
+ // compressOutOfMemory ( totalDraw, n );
+ }
+
+ /*
+ The back end needs a place to store the MTF values
+ whilst it calculates the coding tables. We could
+ put them in the zptr array. However, these values
+ will fit in a short, so we overlay szptr at the
+ start of zptr, in the hope of reducing the number
+ of cache misses induced by the multiple traversals
+ of the MTF values when calculating coding tables.
+ Seems to improve compression speed by about 1%.
+ */
+ // szptr = zptr;
+
+
+ szptr = new short[2 * n];
+ }
+
+ void GenerateMTFValues()
+ {
+ char[] yy = new char[256];
+ int i, j;
+ char tmp;
+ char tmp2;
+ int zPend;
+ int wr;
+ int EOB;
+
+ MakeMaps();
+ EOB = nInUse+1;
+
+ for (i = 0; i <= EOB; i++) {
+ mtfFreq[i] = 0;
+ }
+
+ wr = 0;
+ zPend = 0;
+ for (i = 0; i < nInUse; i++) {
+ yy[i] = (char) i;
+ }
+
+
+ for (i = 0; i <= last; i++) {
+ char ll_i;
+
+ ll_i = unseqToSeq[block[zptr[i]]];
+
+ j = 0;
+ tmp = yy[j];
+ while (ll_i != tmp) {
+ j++;
+ tmp2 = tmp;
+ tmp = yy[j];
+ yy[j] = tmp2;
+ }
+ yy[0] = tmp;
+
+ if (j == 0) {
+ zPend++;
+ } else {
+ if (zPend > 0) {
+ zPend--;
+ while (true) {
+ switch (zPend % 2) {
+ case 0:
+ szptr[wr] = (short)BZip2Constants.RUNA;
+ wr++;
+ mtfFreq[BZip2Constants.RUNA]++;
+ break;
+ case 1:
+ szptr[wr] = (short)BZip2Constants.RUNB;
+ wr++;
+ mtfFreq[BZip2Constants.RUNB]++;
+ break;
+ }
+ if (zPend < 2) {
+ break;
+ }
+ zPend = (zPend - 2) / 2;
+ }
+ zPend = 0;
+ }
+ szptr[wr] = (short)(j + 1);
+ wr++;
+ mtfFreq[j + 1]++;
+ }
+ }
+
+ if (zPend > 0) {
+ zPend--;
+ while (true) {
+ switch (zPend % 2) {
+ case 0:
+ szptr[wr] = (short)BZip2Constants.RUNA;
+ wr++;
+ mtfFreq[BZip2Constants.RUNA]++;
+ break;
+ case 1:
+ szptr[wr] = (short)BZip2Constants.RUNB;
+ wr++;
+ mtfFreq[BZip2Constants.RUNB]++;
+ break;
+ }
+ if (zPend < 2) {
+ break;
+ }
+ zPend = (zPend - 2) / 2;
+ }
+ }
+
+ szptr[wr] = (short)EOB;
+ wr++;
+ mtfFreq[EOB]++;
+
+ nMTF = wr;
+ }
+
+ static void Panic()
+ {
+ throw new BZip2Exception("BZip2 output stream panic");
+ }
+
+ static void HbMakeCodeLengths(char[] len, int[] freq, int alphaSize, int maxLen)
+ {
+ /*--
+ Nodes and heap entries run from 1. Entry 0
+ for both the heap and nodes is a sentinel.
+ --*/
+ int nNodes, nHeap, n1, n2, j, k;
+ bool tooLong;
+
+ int[] heap = new int[BZip2Constants.MAX_ALPHA_SIZE + 2];
+ int[] weight = new int[BZip2Constants.MAX_ALPHA_SIZE * 2];
+ int[] parent = new int[BZip2Constants.MAX_ALPHA_SIZE * 2];
+
+ for (int i = 0; i < alphaSize; ++i)
+ {
+ weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
+ }
+
+ while (true)
+ {
+ nNodes = alphaSize;
+ nHeap = 0;
+
+ heap[0] = 0;
+ weight[0] = 0;
+ parent[0] = -2;
+
+ for (int i = 1; i <= alphaSize; ++i)
+ {
+ parent[i] = -1;
+ nHeap++;
+ heap[nHeap] = i;
+ int zz = nHeap;
+ int tmp = heap[zz];
+ while (weight[tmp] < weight[heap[zz >> 1]])
+ {
+ heap[zz] = heap[zz >> 1];
+ zz >>= 1;
+ }
+ heap[zz] = tmp;
+ }
+ if (!(nHeap < (BZip2Constants.MAX_ALPHA_SIZE+2)))
+ {
+ Panic();
+ }
+
+ while (nHeap > 1)
+ {
+ n1 = heap[1];
+ heap[1] = heap[nHeap];
+ nHeap--;
+ int zz = 1;
+ int yy = 0;
+ int tmp = heap[zz];
+ while (true)
+ {
+ yy = zz << 1;
+ if (yy > nHeap)
+ {
+ break;
+ }
+ if (yy < nHeap && weight[heap[yy+1]] < weight[heap[yy]])
+ {
+ yy++;
+ }
+ if (weight[tmp] < weight[heap[yy]])
+ {
+ break;
+ }
+
+ heap[zz] = heap[yy];
+ zz = yy;
+ }
+ heap[zz] = tmp;
+ n2 = heap[1];
+ heap[1] = heap[nHeap];
+ nHeap--;
+
+ zz = 1;
+ yy = 0;
+ tmp = heap[zz];
+ while (true)
+ {
+ yy = zz << 1;
+ if (yy > nHeap)
+ {
+ break;
+ }
+ if (yy < nHeap && weight[heap[yy+1]] < weight[heap[yy]])
+ {
+ yy++;
+ }
+ if (weight[tmp] < weight[heap[yy]])
+ {
+ break;
+ }
+ heap[zz] = heap[yy];
+ zz = yy;
+ }
+ heap[zz] = tmp;
+ nNodes++;
+ parent[n1] = parent[n2] = nNodes;
+
+ weight[nNodes] = (int)((weight[n1] & 0xffffff00) + (weight[n2] & 0xffffff00)) |
+ (int)(1 + (((weight[n1] & 0x000000ff) > (weight[n2] & 0x000000ff)) ? (weight[n1] & 0x000000ff) : (weight[n2] & 0x000000ff)));
+
+ parent[nNodes] = -1;
+ nHeap++;
+ heap[nHeap] = nNodes;
+
+ zz = nHeap;
+ tmp = heap[zz];
+ while (weight[tmp] < weight[heap[zz >> 1]])
+ {
+ heap[zz] = heap[zz >> 1];
+ zz >>= 1;
+ }
+ heap[zz] = tmp;
+ }
+ if (!(nNodes < (BZip2Constants.MAX_ALPHA_SIZE * 2)))
+ {
+ Panic();
+ }
+
+ tooLong = false;
+ for (int i = 1; i <= alphaSize; ++i)
+ {
+ j = 0;
+ k = i;
+ while (parent[k] >= 0)
+ {
+ k = parent[k];
+ j++;
+ }
+ len[i - 1] = (char)j;
+ if (j > maxLen)
+ {
+ tooLong = true;
+ }
+ }
+
+ if (!tooLong)
+ {
+ break;
+ }
+
+ for (int i = 1; i < alphaSize; ++i)
+ {
+ j = weight[i] >> 8;
+ j = 1 + (j / 2);
+ weight[i] = j << 8;
+ }
+ }
+ }
+
+ static void HbAssignCodes (int[] code, char[] length, int minLen, int maxLen, int alphaSize)
+ {
+ int vec = 0;
+ for (int n = minLen; n <= maxLen; ++n)
+ {
+ for (int i = 0; i < alphaSize; ++i)
+ {
+ if (length[i] == n)
+ {
+ code[i] = vec;
+ ++vec;
+ }
+ }
+ vec <<= 1;
+ }
+ }
+
+ static byte Med3(byte a, byte b, byte c )
+ {
+ byte t;
+ if (a > b)
+ {
+ t = a;
+ a = b;
+ b = t;
+ }
+ if (b > c)
+ {
+ t = b;
+ b = c;
+ c = t;
+ }
+ if (a > b)
+ {
+ b = a;
+ }
+ return b;
+ }
+
+ class StackElement
+ {
+ public int ll;
+ public int hh;
+ public int dd;
+ }
+
+ #region Instance Fields
+ bool isStreamOwner = true;
+
+ /*--
+ index of the last char in the block, so
+ the block size == last + 1.
+ --*/
+ int last;
+
+ /*--
+ index in zptr[] of original string after sorting.
+ --*/
+ int origPtr;
+
+ /*--
+ always: in the range 0 .. 9.
+ The current block size is 100000 * this number.
+ --*/
+ int blockSize100k;
+
+ bool blockRandomised;
+
+ int bytesOut;
+ int bsBuff;
+ int bsLive;
+ IChecksum mCrc = new StrangeCRC();
+
+ bool[] inUse = new bool[256];
+ int nInUse;
+
+ char[] seqToUnseq = new char[256];
+ char[] unseqToSeq = new char[256];
+
+ char[] selector = new char[BZip2Constants.MAX_SELECTORS];
+ char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS];
+
+ byte[] block;
+ int[] quadrant;
+ int[] zptr;
+ short[] szptr;
+ int[] ftab;
+
+ int nMTF;
+
+ int[] mtfFreq = new int[BZip2Constants.MAX_ALPHA_SIZE];
+
+ /*
+ * Used when sorting. If too many long comparisons
+ * happen, we stop sorting, randomise the block
+ * slightly, and try again.
+ */
+ int workFactor;
+ int workDone;
+ int workLimit;
+ bool firstAttempt;
+ int nBlocksRandomised;
+
+ int currentChar = -1;
+ int runLength;
+ uint blockCRC, combinedCRC;
+ int allowableBlockSize;
+ Stream baseStream;
+ bool disposed_;
+ #endregion
+ }
+}
+
+/* This file was derived from a file containing this license:
+ *
+ * This file is a part of bzip2 and/or libbzip2, a program and
+ * library for lossless, block-sorting data compression.
+ *
+ * Copyright (C) 1996-1998 Julian R Seward. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. The origin of this software must not be misrepresented; you must
+ * not claim that you wrote the original software. If you use this
+ * software in a product, an acknowledgment in the product
+ * documentation would be appreciated but is not required.
+ *
+ * 3. Altered source versions must be plainly marked as such, and must
+ * not be misrepresented as being the original software.
+ *
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Java version ported by Keiron Liddle, Aftex Software <keiron@aftexsw.com> 1999-2001
+ */
--- /dev/null
+// Adler32.cs - Computes Adler32 data checksum of a data stream
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression.Streams;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Checksums
+{
+ /// <summary>
+ /// Computes Adler32 checksum for a stream of data. An Adler32
+ /// checksum is not as reliable as a CRC32 checksum, but a lot faster to
+ /// compute.
+ ///
+ /// The specification for Adler32 may be found in RFC 1950.
+ /// ZLIB Compressed Data Format Specification version 3.3)
+ ///
+ ///
+ /// From that document:
+ ///
+ /// "ADLER32 (Adler-32 checksum)
+ /// This contains a checksum value of the uncompressed data
+ /// (excluding any dictionary data) computed according to Adler-32
+ /// algorithm. This algorithm is a 32-bit extension and improvement
+ /// of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073
+ /// standard.
+ ///
+ /// Adler-32 is composed of two sums accumulated per byte: s1 is
+ /// the sum of all bytes, s2 is the sum of all s1 values. Both sums
+ /// are done modulo 65521. s1 is initialized to 1, s2 to zero. The
+ /// Adler-32 checksum is stored as s2*65536 + s1 in most-
+ /// significant-byte first (network) order."
+ ///
+ /// "8.2. The Adler-32 algorithm
+ ///
+ /// The Adler-32 algorithm is much faster than the CRC32 algorithm yet
+ /// still provides an extremely low probability of undetected errors.
+ ///
+ /// The modulo on unsigned long accumulators can be delayed for 5552
+ /// bytes, so the modulo operation time is negligible. If the bytes
+ /// are a, b, c, the second sum is 3a + 2b + c + 3, and so is position
+ /// and order sensitive, unlike the first sum, which is just a
+ /// checksum. That 65521 is prime is important to avoid a possible
+ /// large class of two-byte errors that leave the check unchanged.
+ /// (The Fletcher checksum uses 255, which is not prime and which also
+ /// makes the Fletcher check insensitive to single byte changes 0 -
+ /// 255.)
+ ///
+ /// The sum s1 is initialized to 1 instead of zero to make the length
+ /// of the sequence part of s2, so that the length does not have to be
+ /// checked separately. (Any sequence of zeroes has a Fletcher
+ /// checksum of zero.)"
+ /// </summary>
+ /// <see cref="InflaterInputStream"/>
+ /// <see cref="DeflaterOutputStream"/>
+ public sealed class Adler32 : IChecksum
+ {
+ /// <summary>
+ /// largest prime smaller than 65536
+ /// </summary>
+ const uint BASE = 65521;
+
+ /// <summary>
+ /// Returns the Adler32 data checksum computed so far.
+ /// </summary>
+ public long Value {
+ get {
+ return checksum;
+ }
+ }
+
+ /// <summary>
+ /// Creates a new instance of the Adler32 class.
+ /// The checksum starts off with a value of 1.
+ /// </summary>
+ public Adler32()
+ {
+ Reset();
+ }
+
+ /// <summary>
+ /// Resets the Adler32 checksum to the initial value.
+ /// </summary>
+ public void Reset()
+ {
+ checksum = 1;
+ }
+
+ /// <summary>
+ /// Updates the checksum with a byte value.
+ /// </summary>
+ /// <param name="value">
+ /// The data value to add. The high byte of the int is ignored.
+ /// </param>
+ public void Update(int value)
+ {
+ // We could make a length 1 byte array and call update again, but I
+ // would rather not have that overhead
+ uint s1 = checksum & 0xFFFF;
+ uint s2 = checksum >> 16;
+
+ s1 = (s1 + ((uint)value & 0xFF)) % BASE;
+ s2 = (s1 + s2) % BASE;
+
+ checksum = (s2 << 16) + s1;
+ }
+
+ /// <summary>
+ /// Updates the checksum with an array of bytes.
+ /// </summary>
+ /// <param name="buffer">
+ /// The source of the data to update with.
+ /// </param>
+ public void Update(byte[] buffer)
+ {
+ if ( buffer == null ) {
+ throw new ArgumentNullException("buffer");
+ }
+
+ Update(buffer, 0, buffer.Length);
+ }
+
+ /// <summary>
+ /// Updates the checksum with the bytes taken from the array.
+ /// </summary>
+ /// <param name="buffer">
+ /// an array of bytes
+ /// </param>
+ /// <param name="offset">
+ /// the start of the data used for this update
+ /// </param>
+ /// <param name="count">
+ /// the number of bytes to use for this update
+ /// </param>
+ public void Update(byte[] buffer, int offset, int count)
+ {
+ if (buffer == null) {
+ throw new ArgumentNullException("buffer");
+ }
+
+ if (offset < 0) {
+ throw new ArgumentOutOfRangeException("offset", "cannot be negative");
+ }
+
+ if ( count < 0 )
+ {
+ throw new ArgumentOutOfRangeException("count", "cannot be negative");
+ }
+
+ if (offset >= buffer.Length)
+ {
+ throw new ArgumentOutOfRangeException("offset", "not a valid index into buffer");
+ }
+
+ if (offset + count > buffer.Length)
+ {
+ throw new ArgumentOutOfRangeException("count", "exceeds buffer size");
+ }
+
+ //(By Per Bothner)
+ var s1 = checksum & 0xFFFF;
+ var s2 = checksum >> 16;
+
+ while (count > 0) {
+ // We can defer the modulo operation:
+ // s1 maximally grows from 65521 to 65521 + 255 * 3800
+ // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31
+ var n = 3800;
+ if (n > count) {
+ n = count;
+ }
+ count -= n;
+ while (--n >= 0) {
+ s1 = s1 + (uint)(buffer[offset++] & 0xff);
+ s2 = s2 + s1;
+ }
+ s1 %= BASE;
+ s2 %= BASE;
+ }
+
+ checksum = (s2 << 16) | s1;
+ }
+
+ #region Instance Fields
+ uint checksum;
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+// CRC32.cs - Computes CRC32 data checksum of a data stream
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Checksums
+{
+ /// <summary>
+ /// Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
+ /// x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+ ///
+ /// Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ /// with the lowest powers in the most significant bit. Then adding polynomials
+ /// is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ /// one. If we call the above polynomial p, and represent a byte as the
+ /// polynomial q, also with the lowest power in the most significant bit (so the
+ /// byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+ /// where a mod b means the remainder after dividing a by b.
+ ///
+ /// This calculation is done using the shift-register method of multiplying and
+ /// taking the remainder. The register is initialized to zero, and for each
+ /// incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ /// x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ /// x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ /// out is a one). We start with the highest power (least significant bit) of
+ /// q and repeat for all eight bits of q.
+ ///
+ /// The table is simply the CRC of all possible eight bit values. This is all
+ /// the information needed to generate CRC's on data a byte at a time for all
+ /// combinations of CRC register values and incoming bytes.
+ /// </summary>
+ public sealed class Crc32 : IChecksum
+ {
+ private const uint CrcSeed = 0xFFFFFFFF;
+
+ readonly static uint[] CrcTable = new uint[] {
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419,
+ 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,
+ 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07,
+ 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
+ 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856,
+ 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
+ 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
+ 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,
+ 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A,
+ 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599,
+ 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
+ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190,
+ 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
+ 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E,
+ 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
+ 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
+ 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3,
+ 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
+ 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,
+ 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
+ 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010,
+ 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17,
+ 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6,
+ 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
+ 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
+ 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344,
+ 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
+ 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A,
+ 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1,
+ 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
+ 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,
+ 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
+ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE,
+ 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
+ 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C,
+ 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B,
+ 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
+ 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1,
+ 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
+ 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,
+ 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
+ 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66,
+ 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
+ 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8,
+ 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
+ 0x2D02EF8D
+ };
+
+ internal static uint ComputeCrc32(uint oldCrc, byte value)
+ {
+ return CrcTable[(oldCrc ^ value) & 0xFF] ^ (oldCrc >> 8);
+ }
+
+ /// <summary>
+ /// The crc data checksum so far.
+ /// </summary>
+ uint crc;
+
+ /// <summary>
+ /// Returns the CRC32 data checksum computed so far.
+ /// </summary>
+ public long Value {
+ get {
+ return crc;
+ }
+ set {
+ crc = (uint)value;
+ }
+ }
+
+ /// <summary>
+ /// Resets the CRC32 data checksum as if no update was ever called.
+ /// </summary>
+ public void Reset()
+ {
+ crc = 0;
+ }
+
+ /// <summary>
+ /// Updates the checksum with the int bval.
+ /// </summary>
+ /// <param name = "value">
+ /// the byte is taken as the lower 8 bits of value
+ /// </param>
+ public void Update(int value)
+ {
+ crc ^= CrcSeed;
+ crc = CrcTable[(crc ^ value) & 0xFF] ^ (crc >> 8);
+ crc ^= CrcSeed;
+ }
+
+ /// <summary>
+ /// Updates the checksum with the bytes taken from the array.
+ /// </summary>
+ /// <param name="buffer">
+ /// buffer an array of bytes
+ /// </param>
+ public void Update(byte[] buffer)
+ {
+ if (buffer == null) {
+ throw new ArgumentNullException("buffer");
+ }
+
+ Update(buffer, 0, buffer.Length);
+ }
+
+ /// <summary>
+ /// Adds the byte array to the data checksum.
+ /// </summary>
+ /// <param name = "buffer">
+ /// The buffer which contains the data
+ /// </param>
+ /// <param name = "offset">
+ /// The offset in the buffer where the data starts
+ /// </param>
+ /// <param name = "count">
+ /// The number of data bytes to update the CRC with.
+ /// </param>
+ public void Update(byte[] buffer, int offset, int count)
+ {
+ if (buffer == null) {
+ throw new ArgumentNullException("buffer");
+ }
+
+ if ( count < 0 ) {
+ throw new ArgumentOutOfRangeException("count", "Count cannot be less than zero");
+ }
+
+ if (offset < 0 || offset + count > buffer.Length) {
+ throw new ArgumentOutOfRangeException("offset");
+ }
+
+ crc ^= CrcSeed;
+
+ while (--count >= 0) {
+ crc = CrcTable[(crc ^ buffer[offset++]) & 0xFF] ^ (crc >> 8);
+ }
+
+ crc ^= CrcSeed;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// IChecksum.cs - Interface to compute a data checksum
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Checksums
+{
+ /// <summary>
+ /// Interface to compute a data checksum used by checked input/output streams.
+ /// A data checksum can be updated by one byte or with a byte array. After each
+ /// update the value of the current checksum can be returned by calling
+ /// <code>getValue</code>. The complete checksum object can also be reset
+ /// so it can be used again with new data.
+ /// </summary>
+ public interface IChecksum
+ {
+ /// <summary>
+ /// Returns the data checksum computed so far.
+ /// </summary>
+ long Value
+ {
+ get;
+ }
+
+ /// <summary>
+ /// Resets the data checksum as if no update was ever called.
+ /// </summary>
+ void Reset();
+
+ /// <summary>
+ /// Adds one byte to the data checksum.
+ /// </summary>
+ /// <param name = "value">
+ /// the data value to add. The high byte of the int is ignored.
+ /// </param>
+ void Update(int value);
+
+ /// <summary>
+ /// Updates the data checksum with the bytes taken from the array.
+ /// </summary>
+ /// <param name="buffer">
+ /// buffer an array of bytes
+ /// </param>
+ void Update(byte[] buffer);
+
+ /// <summary>
+ /// Adds the byte array to the data checksum.
+ /// </summary>
+ /// <param name = "buffer">
+ /// The buffer which contains the data
+ /// </param>
+ /// <param name = "offset">
+ /// The offset in the buffer where the data starts
+ /// </param>
+ /// <param name = "count">
+ /// the number of data bytes to add.
+ /// </param>
+ void Update(byte[] buffer, int offset, int count);
+ }
+}
\ No newline at end of file
--- /dev/null
+// StrangeCRC.cs - computes a crc used in the bziplib
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Checksums
+{
+ /// <summary>
+ /// Bzip2 checksum algorithm
+ /// </summary>
+ public class StrangeCRC : IChecksum
+ {
+ readonly static uint[] crc32Table = {
+ 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
+ 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
+ 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+ 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
+ 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
+ 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+ 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
+ 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
+ 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+ 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
+ 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
+ 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+ 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
+ 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
+ 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+ 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
+ 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
+ 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+ 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
+ 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
+ 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+ 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
+ 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
+ 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+ 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
+ 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
+ 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+ 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
+ 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
+ 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+ 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
+ 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
+ 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+ 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
+ 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
+ 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+ 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
+ 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
+ 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+ 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
+ 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
+ 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+ 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
+ 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
+ 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+ 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
+ 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
+ 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+ 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
+ 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
+ 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+ 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
+ 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
+ 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+ 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
+ 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
+ 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+ 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
+ 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
+ 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+ 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
+ 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
+ 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+ 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
+ };
+
+ int globalCrc;
+
+ /// <summary>
+ /// Initialise a default instance of <see cref="StrangeCRC"></see>
+ /// </summary>
+ public StrangeCRC()
+ {
+ Reset();
+ }
+
+ /// <summary>
+ /// Reset the state of Crc.
+ /// </summary>
+ public void Reset()
+ {
+ globalCrc = -1;
+ }
+
+ /// <summary>
+ /// Get the current Crc value.
+ /// </summary>
+ public long Value {
+ get {
+ return ~globalCrc;
+ }
+ }
+
+ /// <summary>
+ /// Update the Crc value.
+ /// </summary>
+ /// <param name="value">data update is based on</param>
+ public void Update(int value)
+ {
+ int temp = (globalCrc >> 24) ^ value;
+ if (temp < 0) {
+ temp = 256 + temp;
+ }
+ globalCrc = unchecked((int)((globalCrc << 8) ^ crc32Table[temp]));
+ }
+
+ /// <summary>
+ /// Update Crc based on a block of data
+ /// </summary>
+ /// <param name="buffer">The buffer containing data to update the crc with.</param>
+ public void Update(byte[] buffer)
+ {
+ if (buffer == null) {
+ throw new ArgumentNullException("buffer");
+ }
+
+ Update(buffer, 0, buffer.Length);
+ }
+
+ /// <summary>
+ /// Update Crc based on a portion of a block of data
+ /// </summary>
+ /// <param name="buffer">block of data</param>
+ /// <param name="offset">index of first byte to use</param>
+ /// <param name="count">number of bytes to use</param>
+ public void Update(byte[] buffer, int offset, int count)
+ {
+ if (buffer == null) {
+ throw new ArgumentNullException("buffer");
+ }
+
+ if ( offset < 0 )
+ {
+ throw new ArgumentOutOfRangeException("offset", "cannot be less than zero");
+ }
+
+ if ( count < 0 )
+ {
+ throw new ArgumentOutOfRangeException("count", "cannot be less than zero");
+ }
+
+ if ( offset + count > buffer.Length )
+ {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ for (int i = 0; i < count; ++i) {
+ Update(buffer[offset++]);
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Globalization;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Compat
+{
+ public static class Extensions
+ {
+ public static int Compare(this string left, string right, bool ignoreCase, CultureInfo info)
+ {
+ if (info == null)
+ {
+ throw new ArgumentNullException("CultureInfo cannot be null!");
+ }
+ return ignoreCase
+ ? info.CompareInfo.Compare(left, right, CompareOptions.IgnoreCase)
+ : info.CompareInfo.Compare(left, right, CompareOptions.None);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// FileSystemScanner.cs
+//
+// Copyright 2005 John Reilly
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+
+using System;
+using System.IO;
+using System.Linq;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Core
+{
+ /// <summary>
+ /// Event arguments for scanning.
+ /// </summary>
+ public class ScanEventArgs : EventArgs
+ {
+ #region Constructors
+
+ /// <summary>
+ /// Initialise a new instance of <see cref="ScanEventArgs"/>
+ /// </summary>
+ /// <param name="name">The file or directory name.</param>
+ public ScanEventArgs(string name)
+ {
+ name_ = name;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// The fie or directory name for this event.
+ /// </summary>
+ public string Name
+ {
+ get { return name_; }
+ }
+
+ /// <summary>
+ /// Get set a value indicating if scanning should continue or not.
+ /// </summary>
+ public bool ContinueRunning
+ {
+ get { return continueRunning_; }
+ set { continueRunning_ = value; }
+ }
+
+ #region Instance Fields
+
+ private readonly string name_;
+ private bool continueRunning_ = true;
+
+ #endregion
+ }
+
+ /// <summary>
+ /// Event arguments during processing of a single file or directory.
+ /// </summary>
+ public class ProgressEventArgs : EventArgs
+ {
+ #region Constructors
+
+ /// <summary>
+ /// Initialise a new instance of <see cref="ScanEventArgs"/>
+ /// </summary>
+ /// <param name="name">The file or directory name if known.</param>
+ /// <param name="processed">The number of bytes processed so far</param>
+ /// <param name="target">The total number of bytes to process, 0 if not known</param>
+ public ProgressEventArgs(string name, long processed, long target)
+ {
+ name_ = name;
+ processed_ = processed;
+ target_ = target;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// The name for this event if known.
+ /// </summary>
+ public string Name
+ {
+ get { return name_; }
+ }
+
+ /// <summary>
+ /// Get set a value indicating wether scanning should continue or not.
+ /// </summary>
+ public bool ContinueRunning
+ {
+ get { return continueRunning_; }
+ set { continueRunning_ = value; }
+ }
+
+ /// <summary>
+ /// Get a percentage representing how much of the <see cref="Target"></see> has been processed
+ /// </summary>
+ /// <value>0.0 to 100.0 percent; 0 if target is not known.</value>
+ public float PercentComplete
+ {
+ get
+ {
+ if (target_ <= 0)
+ {
+ return 0;
+ }
+ return (processed_/(float) target_)*100.0f;
+ }
+ }
+
+ /// <summary>
+ /// The number of bytes processed so far
+ /// </summary>
+ public long Processed
+ {
+ get { return processed_; }
+ }
+
+ /// <summary>
+ /// The number of bytes to process.
+ /// </summary>
+ /// <remarks>Target may be 0 or negative if the value isnt known.</remarks>
+ public long Target
+ {
+ get { return target_; }
+ }
+
+ #region Instance Fields
+
+ private readonly string name_;
+ private readonly long processed_;
+ private readonly long target_;
+ private bool continueRunning_ = true;
+
+ #endregion
+ }
+
+ /// <summary>
+ /// Event arguments for directories.
+ /// </summary>
+ public class DirectoryEventArgs : ScanEventArgs
+ {
+ #region Constructors
+
+ /// <summary>
+ /// Initialize an instance of <see cref="DirectoryEventArgs"></see>.
+ /// </summary>
+ /// <param name="name">The name for this directory.</param>
+ /// <param name="hasMatchingFiles">Flag value indicating if any matching files are contained in this directory.</param>
+ public DirectoryEventArgs(string name, bool hasMatchingFiles)
+ : base(name)
+ {
+ hasMatchingFiles_ = hasMatchingFiles;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Get a value indicating if the directory contains any matching files or not.
+ /// </summary>
+ public bool HasMatchingFiles
+ {
+ get { return hasMatchingFiles_; }
+ }
+
+ #region Instance Fields
+
+ private readonly bool hasMatchingFiles_;
+
+ #endregion
+ }
+
+ /// <summary>
+ /// Arguments passed when scan failures are detected.
+ /// </summary>
+ public class ScanFailureEventArgs
+ {
+ #region Constructors
+
+ /// <summary>
+ /// Initialise a new instance of <see cref="ScanFailureEventArgs"></see>
+ /// </summary>
+ /// <param name="name">The name to apply.</param>
+ /// <param name="e">The exception to use.</param>
+ public ScanFailureEventArgs(string name, Exception e)
+ {
+ name_ = name;
+ exception_ = e;
+ ContinueRunning = true;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// The applicable name.
+ /// </summary>
+ public string Name
+ {
+ get { return name_; }
+ }
+
+ /// <summary>
+ /// The applicable exception.
+ /// </summary>
+ public Exception Exception
+ {
+ get { return exception_; }
+ }
+
+ /// <summary>
+ /// Get / set a value indicating wether scanning should continue.
+ /// </summary>
+ public bool ContinueRunning { get; set; }
+
+ #region Instance Fields
+
+ private readonly Exception exception_;
+ private readonly string name_;
+
+ #endregion
+ }
+
+ /// <summary>
+ /// Delegate invoked before starting to process a directory.
+ /// </summary>
+ public delegate void ProcessDirectoryHandler(object sender, DirectoryEventArgs e);
+
+ /// <summary>
+ /// Delegate invoked before starting to process a file.
+ /// </summary>
+ /// <param name="sender">The source of the event</param>
+ /// <param name="e">The event arguments.</param>
+ public delegate void ProcessFileHandler(object sender, ScanEventArgs e);
+
+ /// <summary>
+ /// Delegate invoked during processing of a file or directory
+ /// </summary>
+ /// <param name="sender">The source of the event</param>
+ /// <param name="e">The event arguments.</param>
+ public delegate void ProgressHandler(object sender, ProgressEventArgs e);
+
+ /// <summary>
+ /// Delegate invoked when a file has been completely processed.
+ /// </summary>
+ /// <param name="sender">The source of the event</param>
+ /// <param name="e">The event arguments.</param>
+ public delegate void CompletedFileHandler(object sender, ScanEventArgs e);
+
+ /// <summary>
+ /// Delegate invoked when a directory failure is detected.
+ /// </summary>
+ /// <param name="sender">The source of the event</param>
+ /// <param name="e">The event arguments.</param>
+ public delegate void DirectoryFailureHandler(object sender, ScanFailureEventArgs e);
+
+ /// <summary>
+ /// Delegate invoked when a file failure is detected.
+ /// </summary>
+ /// <param name="sender">The source of the event</param>
+ /// <param name="e">The event arguments.</param>
+ public delegate void FileFailureHandler(object sender, ScanFailureEventArgs e);
+
+ /// <summary>
+ /// FileSystemScanner provides facilities scanning of files and directories.
+ /// </summary>
+ public class FileSystemScanner
+ {
+ #region Constructors
+
+ /// <summary>
+ /// Initialise a new instance of <see cref="FileSystemScanner"></see>
+ /// </summary>
+ /// <param name="filter">The <see cref="PathFilter">file filter</see> to apply when scanning.</param>
+ public FileSystemScanner(string filter)
+ {
+ fileFilter_ = new PathFilter(filter);
+ }
+
+ /// <summary>
+ /// Initialise a new instance of <see cref="FileSystemScanner"></see>
+ /// </summary>
+ /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>
+ /// <param name="directoryFilter">The <see cref="PathFilter"> directory filter</see> to apply.</param>
+ public FileSystemScanner(string fileFilter, string directoryFilter)
+ {
+ fileFilter_ = new PathFilter(fileFilter);
+ directoryFilter_ = new PathFilter(directoryFilter);
+ }
+
+ /// <summary>
+ /// Initialise a new instance of <see cref="FileSystemScanner"></see>
+ /// </summary>
+ /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see> to apply.</param>
+ public FileSystemScanner(IScanFilter fileFilter)
+ {
+ fileFilter_ = fileFilter;
+ }
+
+ /// <summary>
+ /// Initialise a new instance of <see cref="FileSystemScanner"></see>
+ /// </summary>
+ /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see> to apply.</param>
+ /// <param name="directoryFilter">The directory <see cref="IScanFilter">filter</see> to apply.</param>
+ public FileSystemScanner(IScanFilter fileFilter, IScanFilter directoryFilter)
+ {
+ fileFilter_ = fileFilter;
+ directoryFilter_ = directoryFilter;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Delegate to invoke when processing for a file has finished.
+ /// </summary>
+ public CompletedFileHandler CompletedFile;
+
+ /// <summary>
+ /// Delegate to invoke when a directory failure is detected.
+ /// </summary>
+ public DirectoryFailureHandler DirectoryFailure;
+
+ /// <summary>
+ /// Delegate to invoke when a file failure is detected.
+ /// </summary>
+ public FileFailureHandler FileFailure;
+
+ /// <summary>
+ /// Delegate to invoke when a directory is processed.
+ /// </summary>
+ public ProcessDirectoryHandler ProcessDirectory;
+
+ /// <summary>
+ /// Delegate to invoke when a file is processed.
+ /// </summary>
+ public ProcessFileHandler ProcessFile;
+
+ /// <summary>
+ /// Raise the DirectoryFailure event.
+ /// </summary>
+ /// <param name="directory">The directory name.</param>
+ /// <param name="e">The exception detected.</param>
+ private void OnDirectoryFailure(string directory, Exception e)
+ {
+ if (DirectoryFailure == null)
+ {
+ alive_ = false;
+ }
+ else
+ {
+ var args = new ScanFailureEventArgs(directory, e);
+ DirectoryFailure(this, args);
+ alive_ = args.ContinueRunning;
+ }
+ }
+
+ /// <summary>
+ /// Raise the FileFailure event.
+ /// </summary>
+ /// <param name="file">The file name.</param>
+ /// <param name="e">The exception detected.</param>
+ private void OnFileFailure(string file, Exception e)
+ {
+ if (FileFailure == null)
+ {
+ alive_ = false;
+ }
+ else
+ {
+ var args = new ScanFailureEventArgs(file, e);
+ FileFailure(this, args);
+ alive_ = args.ContinueRunning;
+ }
+ }
+
+ /// <summary>
+ /// Raise the ProcessFile event.
+ /// </summary>
+ /// <param name="file">The file name.</param>
+ private void OnProcessFile(string file)
+ {
+ if (ProcessFile != null)
+ {
+ var args = new ScanEventArgs(file);
+ ProcessFile(this, args);
+ alive_ = args.ContinueRunning;
+ }
+ }
+
+ /// <summary>
+ /// Raise the complete file event
+ /// </summary>
+ /// <param name="file">The file name</param>
+ private void OnCompleteFile(string file)
+ {
+ if (CompletedFile == null)
+ {
+ return;
+ }
+ var args = new ScanEventArgs(file);
+ CompletedFile(this, args);
+ alive_ = args.ContinueRunning;
+ }
+
+ /// <summary>
+ /// Raise the ProcessDirectory event.
+ /// </summary>
+ /// <param name="directory">The directory name.</param>
+ /// <param name="hasMatchingFiles">Flag indicating if the directory has matching files.</param>
+ private void OnProcessDirectory(string directory, bool hasMatchingFiles)
+ {
+ if (ProcessDirectory != null)
+ {
+ var args = new DirectoryEventArgs(directory, hasMatchingFiles);
+ ProcessDirectory(this, args);
+ alive_ = args.ContinueRunning;
+ }
+ }
+
+ /// <summary>
+ /// Scan a directory.
+ /// </summary>
+ /// <param name="directory">The base directory to scan.</param>
+ /// <param name="recurse">True to recurse subdirectories, false to scan a single directory.</param>
+ public void Scan(string directory, bool recurse)
+ {
+ alive_ = true;
+ ScanDir(directory, recurse);
+ }
+
+ private void ScanDir(string directory, bool recurse)
+ {
+ try
+ {
+#if !SL4
+ var names = Directory.GetFiles(directory);
+#else
+ var names = Directory.EnumerateFiles(directory).ToArray();
+#endif
+ var hasMatch = false;
+ for (var fileIndex = 0; fileIndex < names.Length; ++fileIndex)
+ {
+ if (!fileFilter_.IsMatch(names[fileIndex]))
+ {
+ names[fileIndex] = null;
+ }
+ else
+ {
+ hasMatch = true;
+ }
+ }
+
+ OnProcessDirectory(directory, hasMatch);
+
+ if (alive_ && hasMatch)
+ {
+ foreach (var fileName in names)
+ {
+ try
+ {
+ if (fileName != null)
+ {
+ OnProcessFile(fileName);
+ if (!alive_)
+ {
+ break;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ OnFileFailure(fileName, e);
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ OnDirectoryFailure(directory, e);
+ }
+
+ if (alive_ && recurse)
+ {
+ try
+ {
+#if !SL4
+ var names = Directory.GetDirectories(directory);
+#else
+ var names = System.IO.Directory.EnumerateDirectories(directory);
+#endif
+ foreach (var fulldir in names)
+ {
+ if ((directoryFilter_ == null) || (directoryFilter_.IsMatch(fulldir)))
+ {
+ ScanDir(fulldir, true);
+ if (!alive_)
+ {
+ break;
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ OnDirectoryFailure(directory, e);
+ }
+ }
+ }
+
+ #region Instance Fields
+
+ /// <summary>
+ /// The directory filter currently in use.
+ /// </summary>
+ private readonly IScanFilter directoryFilter_;
+
+ /// <summary>
+ /// The file filter currently in use.
+ /// </summary>
+ private readonly IScanFilter fileFilter_;
+
+ /// <summary>
+ /// Flag indicating if scanning should continue running.
+ /// </summary>
+ private bool alive_;
+
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+// INameTransform.cs
+//
+// Copyright 2005 John Reilly
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Core
+{
+ /// <summary>
+ /// INameTransform defines how file system names are transformed for use with archives.
+ /// </summary>
+ public interface INameTransform
+ {
+ /// <summary>
+ /// Given a file name determine the transformed value.
+ /// </summary>
+ /// <param name="name">The name to transform.</param>
+ /// <returns>The transformed file name.</returns>
+ string TransformFile(string name);
+
+ /// <summary>
+ /// Given a directory name determine the transformed value.
+ /// </summary>
+ /// <param name="name">The name to transform.</param>
+ /// <returns>The transformed directory name</returns>
+ string TransformDirectory(string name);
+ }
+}
\ No newline at end of file
--- /dev/null
+// IScanFilter.cs
+//
+// Copyright 2006 John Reilly
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Core
+{
+ /// <summary>
+ /// Scanning filters support filtering of names.
+ /// </summary>
+ public interface IScanFilter
+ {
+ /// <summary>
+ /// Test a name to see if it 'matches' the filter.
+ /// </summary>
+ /// <param name="name">The name to test.</param>
+ /// <returns>Returns true if the name matches the filter, false if it does not match.</returns>
+ bool IsMatch(string name);
+ }
+}
\ No newline at end of file
--- /dev/null
+// NameFilter.cs
+//
+// Copyright 2005 John Reilly
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Core
+{
+ /// <summary>
+ /// NameFilter is a string matching class which allows for both positive and negative
+ /// matching.
+ /// A filter is a sequence of independant <see cref="Regex">regular expressions</see> separated by semi-colons ';'
+ /// Each expression can be prefixed by a plus '+' sign or a minus '-' sign to denote the expression
+ /// is intended to include or exclude names. If neither a plus or minus sign is found include is the default
+ /// A given name is tested for inclusion before checking exclusions. Only names matching an include spec
+ /// and not matching an exclude spec are deemed to match the filter.
+ /// An empty filter matches any name.
+ /// </summary>
+ /// <example>The following expression includes all name ending in '.dat' with the exception of 'dummy.dat'
+ /// "+\.dat$;-^dummy\.dat$"
+ /// </example>
+ public class NameFilter : IScanFilter
+ {
+ #region Constructors
+
+ /// <summary>
+ /// Construct an instance based on the filter expression passed
+ /// </summary>
+ /// <param name="filter">The filter expression.</param>
+ public NameFilter(string filter)
+ {
+ filter_ = filter;
+ inclusions_ = new List<Regex>();
+ exclusions_ = new List<Regex>();
+ Compile();
+ }
+
+ #endregion
+
+ #region IScanFilter Members
+
+ /// <summary>
+ /// Test a value to see if it matches the filter.
+ /// </summary>
+ /// <param name="name">The value to test.</param>
+ /// <returns>True if the value matches, false otherwise.</returns>
+ public bool IsMatch(string name)
+ {
+ return IsIncluded(name) && (IsExcluded(name) == false);
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Test a string to see if it is a valid regular expression.
+ /// </summary>
+ /// <param name="expression">The expression to test.</param>
+ /// <returns>True if expression is a valid <see cref="System.Text.RegularExpressions.Regex"/> false otherwise.</returns>
+ public static bool IsValidExpression(string expression)
+ {
+ var result = true;
+ try
+ {
+ var exp = new Regex(expression, RegexOptions.IgnoreCase | RegexOptions.Singleline);
+ }
+ catch
+ {
+ result = false;
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Test an expression to see if it is valid as a filter.
+ /// </summary>
+ /// <param name="toTest">The filter expression to test.</param>
+ /// <returns>True if the expression is valid, false otherwise.</returns>
+ public static bool IsValidFilterExpression(string toTest)
+ {
+ if (toTest == null)
+ {
+ throw new ArgumentNullException("toTest");
+ }
+
+ var result = true;
+
+ try
+ {
+ var items = toTest.Split(';');
+ for (var i = 0; i < items.Length; ++i)
+ {
+ if (string.IsNullOrEmpty(items[i]))
+ {
+ continue;
+ }
+ string toCompile;
+
+ switch (items[i][0])
+ {
+ case '+':
+ toCompile = items[i].Substring(1, items[i].Length - 1);
+ break;
+ case '-':
+ toCompile = items[i].Substring(1, items[i].Length - 1);
+ break;
+ default:
+ toCompile = items[i];
+ break;
+ }
+ var testRegex = new Regex(toCompile, RegexOptions.IgnoreCase | RegexOptions.Singleline);
+ }
+ }
+ catch (Exception)
+ {
+ result = false;
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Convert this filter to its string equivalent.
+ /// </summary>
+ /// <returns>The string equivalent for this filter.</returns>
+ public override string ToString()
+ {
+ return filter_;
+ }
+
+ /// <summary>
+ /// Test a value to see if it is included by the filter.
+ /// </summary>
+ /// <param name="name">The value to test.</param>
+ /// <returns>True if the value is included, false otherwise.</returns>
+ public bool IsIncluded(string name)
+ {
+ var result = false;
+ if (inclusions_.Count == 0)
+ {
+ result = true;
+ }
+ else
+ {
+ foreach (var r in inclusions_)
+ {
+ if (r.IsMatch(name))
+ {
+ result = true;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Test a value to see if it is excluded by the filter.
+ /// </summary>
+ /// <param name="name">The value to test.</param>
+ /// <returns>True if the value is excluded, false otherwise.</returns>
+ public bool IsExcluded(string name)
+ {
+ var result = false;
+ foreach (var r in exclusions_)
+ {
+ if (r.IsMatch(name))
+ {
+ result = true;
+ break;
+ }
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Compile this filter.
+ /// </summary>
+ private void Compile()
+ {
+ // TODO: Check to see if combining RE's makes it faster/smaller.
+ // simple scheme would be to have one RE for inclusion and one for exclusion.
+ if (filter_ == null)
+ {
+ return;
+ }
+
+ // TODO: Allow for paths to include ';'
+ var items = filter_.Split(';');
+ for (var i = 0; i < items.Length; ++i)
+ {
+ if (string.IsNullOrEmpty(items[i]))
+ {
+ continue;
+ }
+ var include = (items[i][0] != '-');
+ string toCompile;
+
+ switch (items[i][0])
+ {
+ case '+':
+ toCompile = items[i].Substring(1, items[i].Length - 1);
+ break;
+ case '-':
+ toCompile = items[i].Substring(1, items[i].Length - 1);
+ break;
+ default:
+ toCompile = items[i];
+ break;
+ }
+
+ // NOTE: Regular expressions can fail to compile here for a number of reasons that cause an exception
+ // these are left unhandled here as the caller is responsible for ensuring all is valid.
+ // several functions IsValidFilterExpression and IsValidExpression are provided for such checking
+ if (include)
+ {
+ inclusions_.Add(new Regex(toCompile, RegexOptions.IgnoreCase | RegexOptions.Singleline));
+ }
+ else
+ {
+ exclusions_.Add(new Regex(toCompile, RegexOptions.IgnoreCase | RegexOptions.Singleline));
+ }
+ }
+ }
+
+ #region Instance Fields
+
+ private readonly List<Regex> exclusions_;
+ private readonly string filter_;
+ private readonly List<Regex> inclusions_;
+
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+// PathFilter.cs
+//
+// Copyright 2005 John Reilly
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Core
+{
+ /// <summary>
+ /// PathFilter filters directories and files using a form of <see cref="System.Text.RegularExpressions.Regex">regular expressions</see>
+ /// by full path name.
+ /// See <see cref="NameFilter">NameFilter</see> for more detail on filtering.
+ /// </summary>
+ public class PathFilter : IScanFilter
+ {
+ #region Constructors
+
+ /// <summary>
+ /// Initialise a new instance of <see cref="PathFilter"></see>.
+ /// </summary>
+ /// <param name="filter">The <see cref="NameFilter">filter</see> expression to apply.</param>
+ public PathFilter(string filter)
+ {
+ nameFilter_ = new NameFilter(filter);
+ }
+
+ #endregion
+
+ #region IScanFilter Members
+
+ /// <summary>
+ /// Test a name to see if it matches the filter.
+ /// </summary>
+ /// <param name="name">The name to test.</param>
+ /// <returns>True if the name matches, false otherwise.</returns>
+ public virtual bool IsMatch(string name)
+ {
+ var result = false;
+
+ if (name != null)
+ {
+ var cooked = (name.Length > 0) ? Path.GetFullPath(name) : "";
+ result = nameFilter_.IsMatch(cooked);
+ }
+ return result;
+ }
+
+ #endregion
+
+ #region Instance Fields
+
+ private readonly NameFilter nameFilter_;
+
+ #endregion
+ }
+
+ /// <summary>
+ /// ExtendedPathFilter filters based on name, file size, and the last write time of the file.
+ /// </summary>
+ /// <remarks>Provides an example of how to customise filtering.</remarks>
+ public class ExtendedPathFilter : PathFilter
+ {
+ #region Constructors
+
+ /// <summary>
+ /// Initialise a new instance of ExtendedPathFilter.
+ /// </summary>
+ /// <param name="filter">The filter to apply.</param>
+ /// <param name="minSize">The minimum file size to include.</param>
+ /// <param name="maxSize">The maximum file size to include.</param>
+ public ExtendedPathFilter(string filter,
+ long minSize, long maxSize)
+ : base(filter)
+ {
+ MinSize = minSize;
+ MaxSize = maxSize;
+ }
+
+ /// <summary>
+ /// Initialise a new instance of ExtendedPathFilter.
+ /// </summary>
+ /// <param name="filter">The filter to apply.</param>
+ /// <param name="minDate">The minimum <see cref="DateTime"/> to include.</param>
+ /// <param name="maxDate">The maximum <see cref="DateTime"/> to include.</param>
+ public ExtendedPathFilter(string filter,
+ DateTime minDate, DateTime maxDate)
+ : base(filter)
+ {
+ MinDate = minDate;
+ MaxDate = maxDate;
+ }
+
+ /// <summary>
+ /// Initialise a new instance of ExtendedPathFilter.
+ /// </summary>
+ /// <param name="filter">The filter to apply.</param>
+ /// <param name="minSize">The minimum file size to include.</param>
+ /// <param name="maxSize">The maximum file size to include.</param>
+ /// <param name="minDate">The minimum <see cref="DateTime"/> to include.</param>
+ /// <param name="maxDate">The maximum <see cref="DateTime"/> to include.</param>
+ public ExtendedPathFilter(string filter,
+ long minSize, long maxSize,
+ DateTime minDate, DateTime maxDate)
+ : base(filter)
+ {
+ MinSize = minSize;
+ MaxSize = maxSize;
+ MinDate = minDate;
+ MaxDate = maxDate;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Test a filename to see if it matches the filter.
+ /// </summary>
+ /// <param name="name">The filename to test.</param>
+ /// <returns>True if the filter matches, false otherwise.</returns>
+ public override bool IsMatch(string name)
+ {
+ var result = base.IsMatch(name);
+
+ if (result)
+ {
+ var fileInfo = new FileInfo(name);
+ result =
+ (MinSize <= fileInfo.Length) &&
+ (MaxSize >= fileInfo.Length) &&
+ (MinDate <= fileInfo.LastWriteTime) &&
+ (MaxDate >= fileInfo.LastWriteTime)
+ ;
+ }
+ return result;
+ }
+
+ #region Properties
+
+ /// <summary>
+ /// Get/set the minimum size for a file that will match this filter.
+ /// </summary>
+ public long MinSize
+ {
+ get { return minSize_; }
+ set
+ {
+ if ((value < 0) || (maxSize_ < value))
+ {
+ throw new ArgumentOutOfRangeException("value");
+ }
+
+ minSize_ = value;
+ }
+ }
+
+ /// <summary>
+ /// Get/set the maximum size for a file that will match this filter.
+ /// </summary>
+ public long MaxSize
+ {
+ get { return maxSize_; }
+ set
+ {
+ if ((value < 0) || (minSize_ > value))
+ {
+ throw new ArgumentOutOfRangeException("value");
+ }
+
+ maxSize_ = value;
+ }
+ }
+
+ /// <summary>
+ /// Get/set the minimum <see cref="DateTime"/> value that will match for this filter.
+ /// </summary>
+ /// <remarks>Files with a LastWrite time less than this value are excluded by the filter.</remarks>
+ public DateTime MinDate
+ {
+ get { return minDate_; }
+
+ set
+ {
+ if (value > maxDate_)
+ {
+ throw new ArgumentException("Exceeds MaxDate", "value");
+ }
+
+ minDate_ = value;
+ }
+ }
+
+ /// <summary>
+ /// Get/set the maximum <see cref="DateTime"/> value that will match for this filter.
+ /// </summary>
+ /// <remarks>Files with a LastWrite time greater than this value are excluded by the filter.</remarks>
+ public DateTime MaxDate
+ {
+ get { return maxDate_; }
+
+ set
+ {
+ if (minDate_ > value)
+ {
+ throw new ArgumentException("Exceeds MinDate", "value");
+ }
+
+ maxDate_ = value;
+ }
+ }
+
+ #endregion
+
+ #region Instance Fields
+
+ private DateTime maxDate_ = DateTime.MaxValue;
+ private long maxSize_ = long.MaxValue;
+ private DateTime minDate_ = DateTime.MinValue;
+ private long minSize_;
+
+ #endregion
+ }
+
+ /// <summary>
+ /// NameAndSizeFilter filters based on name and file size.
+ /// </summary>
+ /// <remarks>A sample showing how filters might be extended.</remarks>
+ [Obsolete("Use ExtendedPathFilter instead")]
+ public class NameAndSizeFilter : PathFilter
+ {
+ /// <summary>
+ /// Initialise a new instance of NameAndSizeFilter.
+ /// </summary>
+ /// <param name="filter">The filter to apply.</param>
+ /// <param name="minSize">The minimum file size to include.</param>
+ /// <param name="maxSize">The maximum file size to include.</param>
+ public NameAndSizeFilter(string filter, long minSize, long maxSize)
+ : base(filter)
+ {
+ MinSize = minSize;
+ MaxSize = maxSize;
+ }
+
+ /// <summary>
+ /// Get/set the minimum size for a file that will match this filter.
+ /// </summary>
+ public long MinSize
+ {
+ get { return minSize_; }
+ set
+ {
+ if ((value < 0) || (maxSize_ < value))
+ {
+ throw new ArgumentOutOfRangeException("value");
+ }
+
+ minSize_ = value;
+ }
+ }
+
+ /// <summary>
+ /// Get/set the maximum size for a file that will match this filter.
+ /// </summary>
+ public long MaxSize
+ {
+ get { return maxSize_; }
+ set
+ {
+ if ((value < 0) || (minSize_ > value))
+ {
+ throw new ArgumentOutOfRangeException("value");
+ }
+
+ maxSize_ = value;
+ }
+ }
+
+ #region Instance Fields
+
+ private long maxSize_ = long.MaxValue;
+ private long minSize_;
+
+ #endregion
+
+ /// <summary>
+ /// Test a filename to see if it matches the filter.
+ /// </summary>
+ /// <param name="name">The filename to test.</param>
+ /// <returns>True if the filter matches, false otherwise.</returns>
+ public override bool IsMatch(string name)
+ {
+ var result = base.IsMatch(name);
+
+ if (result)
+ {
+ var fileInfo = new FileInfo(name);
+ var length = fileInfo.Length;
+ result =
+ (MinSize <= length) &&
+ (MaxSize >= length);
+ }
+ return result;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// StreamUtils.cs
+//
+// Copyright 2005 John Reilly
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+using ICSharpCode.SharpZipLib.Silverlight.Core;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Core
+{
+ /// <summary>
+ /// Provides simple <see cref="Stream"/>" utilities.
+ /// </summary>
+ public static class StreamUtils
+ {
+ /// <summary>
+ /// Read from a <see cref="Stream"/> ensuring all the required data is read.
+ /// </summary>
+ /// <param name="stream">The stream to read.</param>
+ /// <param name="buffer">The buffer to fill.</param>
+ static public void ReadFully(Stream stream, byte[] buffer)
+ {
+ ReadFully(stream, buffer, 0, buffer.Length);
+ }
+
+ /// <summary>
+ /// Read from a <see cref="Stream"/>" ensuring all the required data is read.
+ /// </summary>
+ /// <param name="stream">The stream to read data from.</param>
+ /// <param name="buffer">The buffer to store data in.</param>
+ /// <param name="offset">The offset at which to begin storing data.</param>
+ /// <param name="count">The number of bytes of data to store.</param>
+ static public void ReadFully(Stream stream, byte[] buffer, int offset, int count)
+ {
+ if ( stream == null ) {
+ throw new ArgumentNullException("stream");
+ }
+
+ if ( buffer == null ) {
+ throw new ArgumentNullException("buffer");
+ }
+
+ // Offset can equal length when buffer and count are 0.
+ if ( (offset < 0) || (offset > buffer.Length) ) {
+ throw new ArgumentOutOfRangeException("offset");
+ }
+
+ if ( (count < 0) || (offset + count > buffer.Length) ) {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ while ( count > 0 ) {
+ int readCount = stream.Read(buffer, offset, count);
+ if ( readCount <= 0 ) {
+ throw new EndOfStreamException();
+ }
+ offset += readCount;
+ count -= readCount;
+ }
+ }
+
+ /// <summary>
+ /// Copy the contents of one <see cref="Stream"/> to another.
+ /// </summary>
+ /// <param name="source">The stream to source data from.</param>
+ /// <param name="destination">The stream to write data to.</param>
+ /// <param name="buffer">The buffer to use during copying.</param>
+ /// <param name="progressHandler">The <see cref="ProgressHandler">progress handler delegate</see> to use.</param>
+ /// <param name="updateInterval">The minimum <see cref="TimeSpan"/> between progress updates.</param>
+ /// <param name="sender">The source for this event.</param>
+ /// <param name="name">The name to use with the event.</param>
+ static public void Copy(Stream source, Stream destination,
+ byte[] buffer, ProgressHandler progressHandler, TimeSpan updateInterval, object sender, string name)
+ {
+ if (source == null) {
+ throw new ArgumentNullException("source");
+ }
+
+ if (destination == null) {
+ throw new ArgumentNullException("destination");
+ }
+
+ if (buffer == null) {
+ throw new ArgumentNullException("buffer");
+ }
+
+ // Ensure a reasonable size of buffer is used without being prohibitive.
+ if (buffer.Length < 128) {
+ throw new ArgumentException("Buffer is too small", "buffer");
+ }
+
+ if (progressHandler == null) {
+ throw new ArgumentNullException("progressHandler");
+ }
+
+ bool copying = true;
+
+ DateTime marker = DateTime.Now;
+ long processed = 0;
+ long target = 0;
+
+ if (source.CanSeek) {
+ target = source.Length - source.Position;
+ }
+
+ // Always fire 0% progress..
+ var args = new ProgressEventArgs(name, processed, target);
+ progressHandler(sender, args);
+
+ bool completeFired = false;
+
+ while (copying) {
+ int bytesRead = source.Read(buffer, 0, buffer.Length);
+ if (bytesRead > 0) {
+ processed += bytesRead;
+ destination.Write(buffer, 0, bytesRead);
+ }
+ else {
+ destination.Flush();
+ copying = false;
+ }
+
+ if (DateTime.Now - marker > updateInterval) {
+ completeFired = (processed == target);
+ marker = DateTime.Now;
+ args = new ProgressEventArgs(name, processed, target);
+ progressHandler(sender, args);
+
+ copying = args.ContinueRunning;
+ }
+ }
+
+ if (!completeFired) {
+ args = new ProgressEventArgs(name, processed, target);
+ progressHandler(sender, args);
+ }
+ }
+
+ /// <summary>
+ /// Copy the contents of one <see cref="Stream"/> to another.
+ /// </summary>
+ /// <param name="source">The stream to source data from.</param>
+ /// <param name="destination">The stream to write data to.</param>
+ /// <param name="buffer">The buffer to use during copying.</param>
+ static public void Copy(Stream source, Stream destination, byte[] buffer)
+ {
+ if ( source == null ) {
+ throw new ArgumentNullException("source");
+ }
+
+ if ( destination == null ) {
+ throw new ArgumentNullException("destination");
+ }
+
+ if ( buffer == null ) {
+ throw new ArgumentNullException("buffer");
+ }
+
+ // Ensure a reasonable size of buffer is used without being prohibitive.
+ if ( buffer.Length < 128 ) {
+ throw new ArgumentException("Buffer is too small", "buffer");
+ }
+
+ bool copying = true;
+
+ while ( copying ) {
+ int bytesRead = source.Read(buffer, 0, buffer.Length);
+ if ( bytesRead > 0 ) {
+ destination.Write(buffer, 0, bytesRead);
+ }
+ else {
+ destination.Flush();
+ copying = false;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// PkzipClassic encryption
+//
+// Copyright 2004 John Reilly
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+//
+
+using System;
+using System.Security.Cryptography;
+using ICSharpCode.SharpZipLib.Silverlight.Checksums;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Encryption
+{
+ /// <summary>
+ /// PkzipClassic embodies the classic or original encryption facilities used in Pkzip archives.
+ /// While it has been superceded by more recent and more powerful algorithms, its still in use and
+ /// is viable for preventing casual snooping
+ /// </summary>
+ public abstract class PkzipClassic : SymmetricAlgorithm
+ {
+ /// <summary>
+ /// Generates new encryption keys based on given seed
+ /// </summary>
+ /// <param name="seed">The seed value to initialise keys with.</param>
+ /// <returns>A new key value.</returns>
+ public static byte[] GenerateKeys(byte[] seed)
+ {
+ if (seed == null)
+ {
+ throw new ArgumentNullException("seed");
+ }
+
+ if (seed.Length == 0)
+ {
+ throw new ArgumentException("Length is zero", "seed");
+ }
+
+ var newKeys = new uint[]{
+ 0x12345678,
+ 0x23456789,
+ 0x34567890
+ };
+
+ for (var i = 0; i < seed.Length; ++i)
+ {
+ newKeys[0] = Crc32.ComputeCrc32(newKeys[0], seed[i]);
+ newKeys[1] = newKeys[1] + (byte) newKeys[0];
+ newKeys[1] = newKeys[1]*134775813 + 1;
+ newKeys[2] = Crc32.ComputeCrc32(newKeys[2], (byte) (newKeys[1] >> 24));
+ }
+
+ var result = new byte[12];
+ result[0] = (byte) (newKeys[0] & 0xff);
+ result[1] = (byte) ((newKeys[0] >> 8) & 0xff);
+ result[2] = (byte) ((newKeys[0] >> 16) & 0xff);
+ result[3] = (byte) ((newKeys[0] >> 24) & 0xff);
+ result[4] = (byte) (newKeys[1] & 0xff);
+ result[5] = (byte) ((newKeys[1] >> 8) & 0xff);
+ result[6] = (byte) ((newKeys[1] >> 16) & 0xff);
+ result[7] = (byte) ((newKeys[1] >> 24) & 0xff);
+ result[8] = (byte) (newKeys[2] & 0xff);
+ result[9] = (byte) ((newKeys[2] >> 8) & 0xff);
+ result[10] = (byte) ((newKeys[2] >> 16) & 0xff);
+ result[11] = (byte) ((newKeys[2] >> 24) & 0xff);
+ return result;
+ }
+ }
+
+ /// <summary>
+ /// PkzipClassicCryptoBase provides the low level facilities for encryption
+ /// and decryption using the PkzipClassic algorithm.
+ /// </summary>
+ internal class PkzipClassicCryptoBase
+ {
+ /// <summary>
+ /// Transform a single byte
+ /// </summary>
+ /// <returns>
+ /// The transformed value
+ /// </returns>
+ protected byte TransformByte()
+ {
+ var temp = ((keys[2] & 0xFFFF) | 2);
+ return (byte) ((temp*(temp ^ 1)) >> 8);
+ }
+
+ /// <summary>
+ /// Set the key schedule for encryption/decryption.
+ /// </summary>
+ /// <param name="keyData">The data use to set the keys from.</param>
+ protected void SetKeys(byte[] keyData)
+ {
+ if (keyData == null)
+ {
+ throw new ArgumentNullException("keyData");
+ }
+
+ if (keyData.Length != 12)
+ {
+ throw new InvalidOperationException("Key length is not valid");
+ }
+
+ keys = new uint[3];
+ keys[0] = (uint) ((keyData[3] << 24) | (keyData[2] << 16) | (keyData[1] << 8) | keyData[0]);
+ keys[1] = (uint) ((keyData[7] << 24) | (keyData[6] << 16) | (keyData[5] << 8) | keyData[4]);
+ keys[2] = (uint) ((keyData[11] << 24) | (keyData[10] << 16) | (keyData[9] << 8) | keyData[8]);
+ }
+
+ /// <summary>
+ /// Update encryption keys
+ /// </summary>
+ protected void UpdateKeys(byte ch)
+ {
+ keys[0] = Crc32.ComputeCrc32(keys[0], ch);
+ keys[1] = keys[1] + (byte) keys[0];
+ keys[1] = keys[1]*134775813 + 1;
+ keys[2] = Crc32.ComputeCrc32(keys[2], (byte) (keys[1] >> 24));
+ }
+
+ /// <summary>
+ /// Reset the internal state.
+ /// </summary>
+ protected void Reset()
+ {
+ keys[0] = 0;
+ keys[1] = 0;
+ keys[2] = 0;
+ }
+
+ #region Instance Fields
+
+ private uint[] keys;
+
+ #endregion
+ }
+
+ /// <summary>
+ /// PkzipClassic CryptoTransform for encryption.
+ /// </summary>
+ internal class PkzipClassicEncryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform
+ {
+ /// <summary>
+ /// Initialise a new instance of <see cref="PkzipClassicEncryptCryptoTransform"></see>
+ /// </summary>
+ /// <param name="keyBlock">The key block to use.</param>
+ internal PkzipClassicEncryptCryptoTransform(byte[] keyBlock)
+ {
+ SetKeys(keyBlock);
+ }
+
+ #region ICryptoTransform Members
+
+ /// <summary>
+ /// Transforms the specified region of the specified byte array.
+ /// </summary>
+ /// <param name="inputBuffer">The input for which to compute the transform.</param>
+ /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>
+ /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>
+ /// <returns>The computed transform.</returns>
+ public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
+ {
+ var result = new byte[inputCount];
+ TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);
+ return result;
+ }
+
+ /// <summary>
+ /// Transforms the specified region of the input byte array and copies
+ /// the resulting transform to the specified region of the output byte array.
+ /// </summary>
+ /// <param name="inputBuffer">The input for which to compute the transform.</param>
+ /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
+ /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
+ /// <param name="outputBuffer">The output to which to write the transform.</param>
+ /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
+ /// <returns>The number of bytes written.</returns>
+ public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer,
+ int outputOffset)
+ {
+ for (var i = inputOffset; i < inputOffset + inputCount; ++i)
+ {
+ var oldbyte = inputBuffer[i];
+ outputBuffer[outputOffset++] = (byte) (inputBuffer[i] ^ TransformByte());
+ UpdateKeys(oldbyte);
+ }
+ return inputCount;
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the current transform can be reused.
+ /// </summary>
+ public bool CanReuseTransform
+ {
+ get { return true; }
+ }
+
+ /// <summary>
+ /// Gets the size of the input data blocks in bytes.
+ /// </summary>
+ public int InputBlockSize
+ {
+ get { return 1; }
+ }
+
+ /// <summary>
+ /// Gets the size of the output data blocks in bytes.
+ /// </summary>
+ public int OutputBlockSize
+ {
+ get { return 1; }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether multiple blocks can be transformed.
+ /// </summary>
+ public bool CanTransformMultipleBlocks
+ {
+ get { return true; }
+ }
+
+ /// <summary>
+ /// Cleanup internal state.
+ /// </summary>
+ public void Dispose()
+ {
+ Reset();
+ }
+
+ #endregion
+ }
+
+ /// <summary>
+ /// PkzipClassic CryptoTransform for decryption.
+ /// </summary>
+ internal class PkzipClassicDecryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform
+ {
+ /// <summary>
+ /// Initialise a new instance of <see cref="PkzipClassicDecryptCryptoTransform"></see>.
+ /// </summary>
+ /// <param name="keyBlock">The key block to decrypt with.</param>
+ internal PkzipClassicDecryptCryptoTransform(byte[] keyBlock)
+ {
+ SetKeys(keyBlock);
+ }
+
+ #region ICryptoTransform Members
+
+ /// <summary>
+ /// Transforms the specified region of the specified byte array.
+ /// </summary>
+ /// <param name="inputBuffer">The input for which to compute the transform.</param>
+ /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>
+ /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>
+ /// <returns>The computed transform.</returns>
+ public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
+ {
+ var result = new byte[inputCount];
+ TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);
+ return result;
+ }
+
+ /// <summary>
+ /// Transforms the specified region of the input byte array and copies
+ /// the resulting transform to the specified region of the output byte array.
+ /// </summary>
+ /// <param name="inputBuffer">The input for which to compute the transform.</param>
+ /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
+ /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
+ /// <param name="outputBuffer">The output to which to write the transform.</param>
+ /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
+ /// <returns>The number of bytes written.</returns>
+ public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer,
+ int outputOffset)
+ {
+ for (var i = inputOffset; i < inputOffset + inputCount; ++i)
+ {
+ var newByte = (byte) (inputBuffer[i] ^ TransformByte());
+ outputBuffer[outputOffset++] = newByte;
+ UpdateKeys(newByte);
+ }
+ return inputCount;
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the current transform can be reused.
+ /// </summary>
+ public bool CanReuseTransform
+ {
+ get { return true; }
+ }
+
+ /// <summary>
+ /// Gets the size of the input data blocks in bytes.
+ /// </summary>
+ public int InputBlockSize
+ {
+ get { return 1; }
+ }
+
+ /// <summary>
+ /// Gets the size of the output data blocks in bytes.
+ /// </summary>
+ public int OutputBlockSize
+ {
+ get { return 1; }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether multiple blocks can be transformed.
+ /// </summary>
+ public bool CanTransformMultipleBlocks
+ {
+ get { return true; }
+ }
+
+ /// <summary>
+ /// Cleanup internal state.
+ /// </summary>
+ public void Dispose()
+ {
+ Reset();
+ }
+
+ #endregion
+ }
+
+ /// <summary>
+ /// Defines a wrapper object to access the Pkzip algorithm.
+ /// This class cannot be inherited.
+ /// </summary>
+ public sealed class PkzipClassicManaged : PkzipClassic
+ {
+ /// <summary>
+ /// Get / set the applicable block size in bits.
+ /// </summary>
+ /// <remarks>The only valid block size is 8.</remarks>
+ public override int BlockSize
+ {
+ get { return 8; }
+
+ set
+ {
+ if (value != 8)
+ {
+ throw new CryptographicException("Block size is invalid");
+ }
+ }
+ }
+
+ /// <summary>
+ /// Get an array of legal <see cref="KeySizes">key sizes.</see>
+ /// </summary>
+ public override KeySizes[] LegalKeySizes
+ {
+ get
+ {
+ var keySizes = new KeySizes[1];
+ keySizes[0] = new KeySizes(12*8, 12*8, 0);
+ return keySizes;
+ }
+ }
+
+ /// <summary>
+ /// Get an array of legal <see cref="KeySizes">block sizes</see>.
+ /// </summary>
+ public override KeySizes[] LegalBlockSizes
+ {
+ get
+ {
+ var keySizes = new KeySizes[1];
+ keySizes[0] = new KeySizes(1*8, 1*8, 0);
+ return keySizes;
+ }
+ }
+
+ /// <summary>
+ /// Get / set the key value applicable.
+ /// </summary>
+ public override byte[] Key
+ {
+ get
+ {
+ if (key_ == null)
+ {
+ GenerateKey();
+ }
+
+ return (byte[]) key_.Clone();
+ }
+
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("value");
+ }
+
+ if (value.Length != 12)
+ {
+ throw new CryptographicException("Key size is illegal");
+ }
+
+ key_ = (byte[]) value.Clone();
+ }
+ }
+
+ /// <summary>
+ /// Generate an initial vector.
+ /// </summary>
+ public override void GenerateIV()
+ {
+ // Do nothing.
+ }
+
+ /// <summary>
+ /// Generate a new random key.
+ /// </summary>
+ public override void GenerateKey()
+ {
+ key_ = new byte[12];
+ var rnd = new Random();
+ rnd.NextBytes(key_);
+ }
+
+ /// <summary>
+ /// Create an encryptor.
+ /// </summary>
+ /// <param name="rgbKey">The key to use for this encryptor.</param>
+ /// <param name="rgbIV">Initialisation vector for the new encryptor.</param>
+ /// <returns>Returns a new PkzipClassic encryptor</returns>
+ public override ICryptoTransform CreateEncryptor(
+ byte[] rgbKey,
+ byte[] rgbIV)
+ {
+ key_ = rgbKey;
+ return new PkzipClassicEncryptCryptoTransform(Key);
+ }
+
+ /// <summary>
+ /// Create a decryptor.
+ /// </summary>
+ /// <param name="rgbKey">Keys to use for this new decryptor.</param>
+ /// <param name="rgbIV">Initialisation vector for the new decryptor.</param>
+ /// <returns>Returns a new decryptor.</returns>
+ public override ICryptoTransform CreateDecryptor(
+ byte[] rgbKey,
+ byte[] rgbIV)
+ {
+ key_ = rgbKey;
+ return new PkzipClassicDecryptCryptoTransform(Key);
+ }
+
+ #region Instance Fields
+
+ private byte[] key_;
+
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+// GZipConstants.cs
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+namespace ICSharpCode.SharpZipLib.GZip
+{
+
+ /// <summary>
+ /// This class contains constants used for gzip.
+ /// </summary>
+ sealed public class GZipConstants
+ {
+ /// <summary>
+ /// Magic number found at start of GZIP header
+ /// </summary>
+ public const int GZIP_MAGIC = 0x1F8B;
+
+ /* The flag byte is divided into individual bits as follows:
+
+ bit 0 FTEXT
+ bit 1 FHCRC
+ bit 2 FEXTRA
+ bit 3 FNAME
+ bit 4 FCOMMENT
+ bit 5 reserved
+ bit 6 reserved
+ bit 7 reserved
+ */
+
+ /// <summary>
+ /// Flag bit mask for text
+ /// </summary>
+ public const int FTEXT = 0x1;
+
+ /// <summary>
+ /// Flag bitmask for Crc
+ /// </summary>
+ public const int FHCRC = 0x2;
+
+ /// <summary>
+ /// Flag bit mask for extra
+ /// </summary>
+ public const int FEXTRA = 0x4;
+
+ /// <summary>
+ /// flag bitmask for name
+ /// </summary>
+ public const int FNAME = 0x8;
+
+ /// <summary>
+ /// flag bit mask indicating comment is present
+ /// </summary>
+ public const int FCOMMENT = 0x10;
+
+ /// <summary>
+ /// Initialise default instance.
+ /// </summary>
+ /// <remarks>Constructor is private to prevent instances being created.</remarks>
+ GZipConstants()
+ {
+ }
+ }
+}
--- /dev/null
+// GZipException.cs
+//
+// Copyright 2004 John Reilly
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using ICSharpCode.SharpZipLib.Silverlight.Serialization;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.GZip
+{
+ /// <summary>
+ /// GZipException represents a Gzip specific exception
+ /// </summary>
+ public class GZipException : SharpZipBaseException
+ {
+ /// <summary>
+ /// Deserialization constructor
+ /// </summary>
+ /// <param name="info"><see cref="System.Runtime.Serialization.SerializationInfo"/> for this constructor</param>
+ protected GZipException(SerializationInfo info)
+ : base(info)
+ {
+
+ }
+
+ /// <summary>
+ /// Initialise a new instance of GZipException
+ /// </summary>
+ public GZipException()
+ {
+ }
+
+ /// <summary>
+ /// Initialise a new instance of GZipException with its message string.
+ /// </summary>
+ /// <param name="message">A <see cref="string"/> that describes the error.</param>
+ public GZipException(string message)
+ : base(message)
+ {
+ }
+
+ /// <summary>
+ /// Initialise a new instance of <see cref="GZipException"></see>.
+ /// </summary>
+ /// <param name="message">A <see cref="string"/> that describes the error.</param>
+ /// <param name="innerException">The <see cref="Exception"/> that caused this exception.</param>
+ public GZipException(string message, Exception innerException)
+ : base (message, innerException)
+ {
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// GzipInputStream.cs
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+using ICSharpCode.SharpZipLib.GZip;
+using ICSharpCode.SharpZipLib.Silverlight.Checksums;
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression;
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression.Streams;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.GZip
+{
+ /// <summary>
+ /// This filter stream is used to decompress a "GZIP" format stream.
+ /// The "GZIP" format is described baseInputStream RFC 1952.
+ ///
+ /// author of the original java version : John Leuner
+ /// </summary>
+ /// <example> This sample shows how to unzip a gzipped file
+ /// <code>
+ /// using System;
+ /// using System.IO;
+ ///
+ /// using ICSharpCode.SharpZipLib.Core;
+ /// using ICSharpCode.SharpZipLib.GZip;
+ ///
+ /// class MainClass
+ /// {
+ /// public static void Main(string[] args)
+ /// {
+ /// using (Stream inStream = new GZipInputStream(File.OpenRead(args[0])))
+ /// using (FileStream outStream = File.Create(Path.GetFileNameWithoutExtension(args[0]))) {
+ /// byte[] buffer = new byte[4096];
+ /// StreamUtils.Copy(inStream, outStream, buffer);
+ /// }
+ /// }
+ /// }
+ /// </code>
+ /// </example>
+ public class GZipInputStream : InflaterInputStream
+ {
+ #region Instance Fields
+
+ /// <summary>
+ /// CRC-32 value for uncompressed data
+ /// </summary>
+ protected Crc32 crc = new Crc32();
+
+ /// <summary>
+ /// Indicates end of stream
+ /// </summary>
+ protected bool eos;
+
+ // Have we read the GZIP header yet?
+ private bool readGZIPHeader;
+
+ #endregion
+
+ #region Constructors
+
+ /// <summary>
+ /// Creates a GZipInputStream with the default buffer size
+ /// </summary>
+ /// <param name="baseInputStream">
+ /// The stream to read compressed data from (baseInputStream GZIP format)
+ /// </param>
+ public GZipInputStream(Stream baseInputStream)
+ : this(baseInputStream, 4096)
+ {
+ }
+
+ /// <summary>
+ /// Creates a GZIPInputStream with the specified buffer size
+ /// </summary>
+ /// <param name="baseInputStream">
+ /// The stream to read compressed data from (baseInputStream GZIP format)
+ /// </param>
+ /// <param name="size">
+ /// Size of the buffer to use
+ /// </param>
+ public GZipInputStream(Stream baseInputStream, int size)
+ : base(baseInputStream, new Inflater(true), size)
+ {
+ }
+
+ #endregion
+
+ #region Stream overrides
+
+ /// <summary>
+ /// Reads uncompressed data into an array of bytes
+ /// </summary>
+ /// <param name="buffer">
+ /// The buffer to read uncompressed data into
+ /// </param>
+ /// <param name="offset">
+ /// The offset indicating where the data should be placed
+ /// </param>
+ /// <param name="count">
+ /// The number of uncompressed bytes to be read
+ /// </param>
+ /// <returns>Returns the number of bytes actually read.</returns>
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ // We first have to read the GZIP header, then we feed all the
+ // rest of the data to the base class.
+ //
+ // As we do that we continually update the CRC32. Once the data is
+ // finished, we check the CRC32
+ //
+ // This means we don't need our own buffer, as everything is done
+ // in baseInputStream the superclass.
+ if (!readGZIPHeader)
+ {
+ ReadHeader();
+ }
+
+ if (eos)
+ {
+ return 0;
+ }
+
+ // We don't have to read the header, so we just grab data from the superclass
+ var bytesRead = base.Read(buffer, offset, count);
+ if (bytesRead > 0)
+ {
+ crc.Update(buffer, offset, bytesRead);
+ }
+
+ if (inf.IsFinished)
+ {
+ ReadFooter();
+ }
+ return bytesRead;
+ }
+
+ #endregion
+
+ #region Support routines
+
+ private void ReadHeader()
+ {
+ // 1. Check the two magic bytes
+ var headCRC = new Crc32();
+ var magic = baseInputStream.ReadByte();
+
+ if (magic < 0)
+ {
+ throw new EndOfStreamException("EOS reading GZIP header");
+ }
+
+ headCRC.Update(magic);
+ if (magic != (GZipConstants.GZIP_MAGIC >> 8))
+ {
+ throw new GZipException("Error GZIP header, first magic byte doesn't match");
+ }
+
+ magic = baseInputStream.ReadByte();
+
+ if (magic < 0)
+ {
+ throw new EndOfStreamException("EOS reading GZIP header");
+ }
+
+ if (magic != (GZipConstants.GZIP_MAGIC & 0xFF))
+ {
+ throw new GZipException("Error GZIP header, second magic byte doesn't match");
+ }
+
+ headCRC.Update(magic);
+
+ // 2. Check the compression type (must be 8)
+ var compressionType = baseInputStream.ReadByte();
+
+ if (compressionType < 0)
+ {
+ throw new EndOfStreamException("EOS reading GZIP header");
+ }
+
+ if (compressionType != 8)
+ {
+ throw new GZipException("Error GZIP header, data not in deflate format");
+ }
+ headCRC.Update(compressionType);
+
+ // 3. Check the flags
+ var flags = baseInputStream.ReadByte();
+ if (flags < 0)
+ {
+ throw new EndOfStreamException("EOS reading GZIP header");
+ }
+ headCRC.Update(flags);
+
+ /* This flag byte is divided into individual bits as follows:
+
+ bit 0 FTEXT
+ bit 1 FHCRC
+ bit 2 FEXTRA
+ bit 3 FNAME
+ bit 4 FCOMMENT
+ bit 5 reserved
+ bit 6 reserved
+ bit 7 reserved
+ */
+
+ // 3.1 Check the reserved bits are zero
+
+ if ((flags & 0xd0) != 0)
+ {
+ throw new GZipException("Reserved flag bits in GZIP header != 0");
+ }
+
+ // 4.-6. Skip the modification time, extra flags, and OS type
+ for (var i = 0; i < 6; i++)
+ {
+ var readByte = baseInputStream.ReadByte();
+ if (readByte < 0)
+ {
+ throw new EndOfStreamException("EOS reading GZIP header");
+ }
+ headCRC.Update(readByte);
+ }
+
+ // 7. Read extra field
+ if ((flags & GZipConstants.FEXTRA) != 0)
+ {
+ // Skip subfield id
+ for (var i = 0; i < 2; i++)
+ {
+ var readByte = baseInputStream.ReadByte();
+ if (readByte < 0)
+ {
+ throw new EndOfStreamException("EOS reading GZIP header");
+ }
+ headCRC.Update(readByte);
+ }
+
+ if (baseInputStream.ReadByte() < 0 || baseInputStream.ReadByte() < 0)
+ {
+ throw new EndOfStreamException("EOS reading GZIP header");
+ }
+
+ var len1 = baseInputStream.ReadByte();
+ var len2 = baseInputStream.ReadByte();
+ if ((len1 < 0) || (len2 < 0))
+ {
+ throw new EndOfStreamException("EOS reading GZIP header");
+ }
+ headCRC.Update(len1);
+ headCRC.Update(len2);
+
+ var extraLen = (len1 << 8) | len2;
+ for (var i = 0; i < extraLen; i++)
+ {
+ var readByte = baseInputStream.ReadByte();
+ if (readByte < 0)
+ {
+ throw new EndOfStreamException("EOS reading GZIP header");
+ }
+ headCRC.Update(readByte);
+ }
+ }
+
+ // 8. Read file name
+ if ((flags & GZipConstants.FNAME) != 0)
+ {
+ int readByte;
+ while ((readByte = baseInputStream.ReadByte()) > 0)
+ {
+ headCRC.Update(readByte);
+ }
+
+ if (readByte < 0)
+ {
+ throw new EndOfStreamException("EOS reading GZIP header");
+ }
+ headCRC.Update(readByte);
+ }
+
+ // 9. Read comment
+ if ((flags & GZipConstants.FCOMMENT) != 0)
+ {
+ int readByte;
+ while ((readByte = baseInputStream.ReadByte()) > 0)
+ {
+ headCRC.Update(readByte);
+ }
+
+ if (readByte < 0)
+ {
+ throw new EndOfStreamException("EOS reading GZIP header");
+ }
+
+ headCRC.Update(readByte);
+ }
+
+ // 10. Read header CRC
+ if ((flags & GZipConstants.FHCRC) != 0)
+ {
+ var crcval = baseInputStream.ReadByte();
+ if (crcval < 0)
+ {
+ throw new EndOfStreamException("EOS reading GZIP header");
+ }
+
+ int tempByte = baseInputStream.ReadByte();
+ if (tempByte < 0)
+ {
+ throw new EndOfStreamException("EOS reading GZIP header");
+ }
+
+ crcval = (crcval << 8) | tempByte;
+ if (crcval != ((int) headCRC.Value & 0xffff))
+ {
+ throw new GZipException("Header CRC value mismatch");
+ }
+ }
+
+ readGZIPHeader = true;
+ }
+
+ private void ReadFooter()
+ {
+ var footer = new byte[8];
+ var avail = inf.RemainingInput;
+
+ if (avail > 8)
+ {
+ avail = 8;
+ }
+
+ Array.Copy(inputBuffer.RawData, inputBuffer.RawLength - inf.RemainingInput, footer, 0, avail);
+ var needed = 8 - avail;
+
+ while (needed > 0)
+ {
+ var count = baseInputStream.Read(footer, 8 - needed, needed);
+ if (count <= 0)
+ {
+ throw new EndOfStreamException("EOS reading GZIP footer");
+ }
+ needed -= count; // Jewel Jan 16
+ }
+
+ var crcval = (footer[0] & 0xff) | ((footer[1] & 0xff) << 8) | ((footer[2] & 0xff) << 16) | (footer[3] << 24);
+ if (crcval != (int) crc.Value)
+ {
+ throw new GZipException("GZIP crc sum mismatch, theirs \"" + crcval + "\" and ours \"" + (int) crc.Value);
+ }
+
+ // NOTE The total here is the original total modulo 2 ^ 32.
+ var total =
+ ((uint) footer[4] & 0xff) |
+ (((uint) footer[5] & 0xff) << 8) |
+ (((uint) footer[6] & 0xff) << 16) |
+ ((uint) footer[7] << 24);
+
+ if ((inf.TotalOut & 0xffffffff) != total)
+ {
+ throw new GZipException("Number of bytes mismatch in footer");
+ }
+
+ // Should we support multiple gzip members.
+ // Difficult, since there may be some bytes still in baseInputStream dataBuffer
+ eos = true;
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+// GZipOutputStream.cs
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+using ICSharpCode.SharpZipLib.GZip;
+using ICSharpCode.SharpZipLib.Silverlight.Checksums;
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression;
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression.Streams;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.GZip
+{
+ /// <summary>
+ /// This filter stream is used to compress a stream into a "GZIP" stream.
+ /// The "GZIP" format is described in RFC 1952.
+ ///
+ /// author of the original java version : John Leuner
+ /// </summary>
+ /// <example> This sample shows how to gzip a file
+ /// <code>
+ /// using System;
+ /// using System.IO;
+ ///
+ /// using ICSharpCode.SharpZipLib.GZip;
+ /// using ICSharpCode.SharpZipLib.Core;
+ ///
+ /// class MainClass
+ /// {
+ /// public static void Main(string[] args)
+ /// {
+ /// using (Stream s = new GZipOutputStream(File.Create(args[0] + ".gz")))
+ /// using (FileStream fs = File.OpenRead(args[0])) {
+ /// byte[] writeData = new byte[4096];
+ /// Streamutils.Copy(s, fs, writeData);
+ /// }
+ /// }
+ /// }
+ /// }
+ /// </code>
+ /// </example>
+ public class GZipOutputStream : DeflaterOutputStream
+ {
+ #region Instance Fields
+
+ /// <summary>
+ /// CRC-32 value for uncompressed data
+ /// </summary>
+ protected Crc32 crc = new Crc32();
+
+ private bool headerWritten_;
+
+ #endregion
+
+ #region Constructors
+
+ /// <summary>
+ /// Creates a GzipOutputStream with the default buffer size
+ /// </summary>
+ /// <param name="baseOutputStream">
+ /// The stream to read data (to be compressed) from
+ /// </param>
+ public GZipOutputStream(Stream baseOutputStream) : this(baseOutputStream, 4096)
+ {
+ }
+
+ /// <summary>
+ /// Creates a GZipOutputStream with the specified buffer size
+ /// </summary>
+ /// <param name="baseOutputStream">
+ /// The stream to read data (to be compressed) from
+ /// </param>
+ /// <param name="size">
+ /// Size of the buffer to use
+ /// </param>
+ public GZipOutputStream(Stream baseOutputStream, int size)
+ : base(baseOutputStream, new Deflater(Deflater.DEFAULT_COMPRESSION, true), size)
+ {
+ }
+
+ #endregion
+
+ #region Public API
+
+ /// <summary>
+ /// Sets the active compression level (1-9). The new level will be activated
+ /// immediately.
+ /// </summary>
+ /// <param name="level">The compression level to set.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Level specified is not supported.
+ /// </exception>
+ /// <see cref="Deflater"/>
+ public void SetLevel(int level)
+ {
+ if (level < Deflater.BEST_SPEED)
+ {
+ throw new ArgumentOutOfRangeException("level");
+ }
+ deflater_.SetLevel(level);
+ }
+
+ /// <summary>
+ /// Get the current compression level.
+ /// </summary>
+ /// <returns>The current compression level.</returns>
+ public int GetLevel()
+ {
+ return deflater_.GetLevel();
+ }
+
+ #endregion
+
+ #region Stream overrides
+
+ /// <summary>
+ /// Write given buffer to output updating crc
+ /// </summary>
+ /// <param name="buffer">Buffer to write</param>
+ /// <param name="offset">Offset of first byte in buf to write</param>
+ /// <param name="count">Number of bytes to write</param>
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ if (! headerWritten_)
+ {
+ WriteHeader();
+ }
+
+ crc.Update(buffer, offset, count);
+ base.Write(buffer, offset, count);
+ }
+
+ /// <summary>
+ /// Writes remaining compressed output data to the output stream
+ /// and closes it.
+ /// </summary>
+ public override void Close()
+ {
+ try
+ {
+ Finish();
+ }
+ finally
+ {
+ if (IsStreamOwner)
+ {
+ baseOutputStream_.Close();
+ }
+ }
+ }
+
+ #endregion
+
+ #region DeflaterOutputStream overrides
+
+ /// <summary>
+ /// Finish compression and write any footer information required to stream
+ /// </summary>
+ public override void Finish()
+ {
+ // If no data has been written a header should be added.
+ if (!headerWritten_)
+ {
+ WriteHeader();
+ }
+
+ base.Finish();
+
+ var totalin = deflater_.TotalIn;
+ var crcval = (int) (crc.Value & 0xffffffff);
+
+ byte[] gzipFooter = {
+ (byte) crcval, (byte) (crcval >> 8),
+ (byte) (crcval >> 16), (byte) (crcval >> 24),
+ (byte) totalin, (byte) (totalin >> 8),
+ (byte) (totalin >> 16), (byte) (totalin >> 24)
+ };
+
+ baseOutputStream_.Write(gzipFooter, 0, gzipFooter.Length);
+ }
+
+ #endregion
+
+ #region Support Routines
+
+ private void WriteHeader()
+ {
+ if (!headerWritten_)
+ {
+ headerWritten_ = true;
+ var mod_time = (int) ((DateTime.Now.Ticks - new DateTime(1970, 1, 1).Ticks)/10000000L);
+ // Ticks give back 100ns intervals
+ byte[] gzipHeader = {
+ // The two magic bytes
+ (GZipConstants.GZIP_MAGIC >> 8), (GZipConstants.GZIP_MAGIC & 0xff),
+ // The compression type
+ Deflater.DEFLATED,
+ // The flags (not set)
+ 0,
+ // The modification time
+ (byte) mod_time, (byte) (mod_time >> 8),
+ (byte) (mod_time >> 16), (byte) (mod_time >> 24),
+ // The extra flags
+ 0,
+ // The OS type (unknown)
+ 255
+ };
+ baseOutputStream_.Write(gzipHeader, 0, gzipHeader.Length);
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Condition="'$(MSBuildToolsVersion)' == '3.5'">
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ </PropertyGroup>
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{2E420750-6124-473B-808D-41755C907648}</ProjectGuid>
+ <ProjectTypeGuids>{A1591282-1198-4647-A2B1-27E5FF5F6F3B};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>ICSharpCode.SharpZipLib.Silverlight</RootNamespace>
+ <AssemblyName>ICSharpCode.SharpZipLib.Silverlight</AssemblyName>
+ <TargetFrameworkVersion>v3.0</TargetFrameworkVersion>
+ <SilverlightApplication>false</SilverlightApplication>
+ <ValidateXaml>true</ValidateXaml>
+ <ThrowErrorsInValidation>false</ThrowErrorsInValidation>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>3.5</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ <IsWebBootstrapper>false</IsWebBootstrapper>
+ <SignAssembly>true</SignAssembly>
+ <AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
+ <TargetFrameworkIdentifier>Silverlight</TargetFrameworkIdentifier>
+ <SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion>
+ <PublishUrl>publish\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Disk</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>Bin\Debug</OutputPath>
+ <DefineConstants>DEBUG;TRACE;SILVERLIGHT</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>Bin\Release</OutputPath>
+ <DefineConstants>TRACE;SILVERLIGHT</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System.ServiceModel.Web" />
+ <Reference Include="System.Windows" />
+ <Reference Include="mscorlib" />
+ <Reference Include="system" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml" />
+ <Reference Include="System.Net" />
+ <Reference Include="System.Windows.Browser" />
+ <Reference Include="System.Xml.Linq, Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="BZip2\BZip2.cs" />
+ <Compile Include="BZip2\BZip2Constants.cs" />
+ <Compile Include="BZip2\BZip2Exception.cs" />
+ <Compile Include="BZip2\BZip2InputStream.cs" />
+ <Compile Include="BZip2\BZip2OutputStream.cs" />
+ <Compile Include="Checksums\Adler32.cs" />
+ <Compile Include="Checksums\CRC32.cs" />
+ <Compile Include="Checksums\IChecksum.cs" />
+ <Compile Include="Checksums\StrangeCRC.cs" />
+ <Compile Include="Compat\Extensions.cs" />
+ <Compile Include="Core\FileSystemScanner.cs" />
+ <Compile Include="Core\INameTransform.cs" />
+ <Compile Include="Core\IScanFilter.cs" />
+ <Compile Include="Core\NameFilter.cs" />
+ <Compile Include="Core\PathFilter.cs" />
+ <Compile Include="Core\StreamUtils.cs" />
+ <Compile Include="Encryption\PkzipClassic.cs" />
+ <Compile Include="GZip\GZIPConstants.cs" />
+ <Compile Include="GZip\GZipException.cs" />
+ <Compile Include="GZip\GzipInputStream.cs" />
+ <Compile Include="GZip\GzipOutputStream.cs" />
+ <Compile Include="Main.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Serialization\ISerializable.cs" />
+ <Compile Include="Serialization\NonSerializedAttribute.cs" />
+ <Compile Include="Serialization\SerializableAttribute.cs" />
+ <Compile Include="Serialization\SerializableBase.cs" />
+ <Compile Include="Serialization\SerializableDateTime.cs" />
+ <Compile Include="Serialization\SerializableString.cs" />
+ <Compile Include="Serialization\SerializationInfo.cs" />
+ <Compile Include="Serialization\XmlFormatter.Deserialize.cs" />
+ <Compile Include="Serialization\XmlFormatter.Serialize.cs" />
+ <Compile Include="SharpZipBaseException.cs" />
+ <Compile Include="Tar\InvalidHeaderException.cs" />
+ <Compile Include="Tar\TarArchive.cs" />
+ <Compile Include="Tar\TarBuffer.cs" />
+ <Compile Include="Tar\TarEntry.cs" />
+ <Compile Include="Tar\TarException.cs" />
+ <Compile Include="Tar\TarHeader.cs" />
+ <Compile Include="Tar\TarInputStream.cs" />
+ <Compile Include="Tar\TarOutputStream.cs" />
+ <Compile Include="Zip\Compression\Deflater.cs" />
+ <Compile Include="Zip\Compression\DeflaterConstants.cs" />
+ <Compile Include="Zip\Compression\DeflaterEngine.cs" />
+ <Compile Include="Zip\Compression\DeflaterHuffman.cs" />
+ <Compile Include="Zip\Compression\DeflaterPending.cs" />
+ <Compile Include="Zip\Compression\Inflater.cs" />
+ <Compile Include="Zip\Compression\InflaterDynHeader.cs" />
+ <Compile Include="Zip\Compression\InflaterHuffmanTree.cs" />
+ <Compile Include="Zip\Compression\PendingBuffer.cs" />
+ <Compile Include="Zip\Compression\Streams\DeflaterOutputStream.cs" />
+ <Compile Include="Zip\Compression\Streams\InflaterInputStream.cs" />
+ <Compile Include="Zip\Compression\Streams\OutputWindow.cs" />
+ <Compile Include="Zip\Compression\Streams\StreamManipulator.cs" />
+ <Compile Include="Zip\FastZip.cs" />
+ <Compile Include="Zip\IEntryFactory.cs" />
+ <Compile Include="Zip\ZipConstants.cs" />
+ <Compile Include="Zip\ZipEntry.cs" />
+ <Compile Include="Zip\ZipEntryFactory.cs" />
+ <Compile Include="Zip\ZipException.cs" />
+ <Compile Include="Zip\ZipExtraData.cs" />
+ <Compile Include="Zip\ZipFile.cs" />
+ <Compile Include="Zip\ZipHelperStream.cs" />
+ <Compile Include="Zip\ZipInputStream.cs" />
+ <Compile Include="Zip\ZipNameTransform.cs" />
+ <Compile Include="Zip\ZipOutputStream.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 2.0 %28x86%29</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.0 %28x86%29</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+ <Visible>False</Visible>
+ <ProductName>Windows Installer 3.1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="key.snk" />
+ </ItemGroup>
+ <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\$(SilverlightVersion)\Microsoft.Silverlight.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+ <ProjectExtensions>
+ <VisualStudio>
+ <FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
+ <SilverlightProjectProperties />
+ </FlavorProperties>
+ </VisualStudio>
+ </ProjectExtensions>
+</Project>
\ No newline at end of file
--- /dev/null
+// Main.cs
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+//
+
--- /dev/null
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 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("SharpZipLibSilverlight")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("SharpZipLibSilverlight")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("4637877e-ab6e-4e03-a771-87d88d1d33ac")]
+
+// 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.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null
+namespace ICSharpCode.SharpZipLib.Silverlight.Serialization
+{
+ /// <summary>
+ /// Code originally authored by Rockford Lhotka:
+ /// http://www.lhotka.net/weblog/SilverlightSerialization.aspx,
+ /// presented here with minor naming and code changes.
+ /// </summary>
+ public interface ISerializable
+ {
+ void Serialize(SerializationInfo info, XmlFormatter formatter);
+ void Deserialize(SerializationInfo info, XmlFormatter formatter);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Serialization
+{
+ /// <summary>
+ /// Code originally authored by Rockford Lhotka:
+ /// http://www.lhotka.net/weblog/SilverlightSerialization.aspx,
+ /// presented here with minor naming and code changes.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Field)]
+ public class NonSerializedAttribute : Attribute
+ {
+ //
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Serialization
+{
+ /// <summary>
+ /// Code originally authored by Rockford Lhotka:
+ /// http://www.lhotka.net/weblog/SilverlightSerialization.aspx,
+ /// presented here with minor naming and code changes.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Class)]
+ public class SerializableAttribute : Attribute
+ {
+ //
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Reflection;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Serialization
+{
+ /// <summary>
+ /// Code originally authored by Rockford Lhotka:
+ /// http://www.lhotka.net/weblog/SilverlightSerialization.aspx,
+ /// presented here with minor naming and code changes.
+ /// </summary>
+ [Serializable]
+ public abstract class SerializableBase : ISerializable
+ {
+ #region ISerializable Members
+
+ void ISerializable.Serialize(SerializationInfo info, XmlFormatter formatter)
+ {
+ var thisType = GetType();
+ info.TypeName = string.Format("{0},{1}", thisType.FullName, thisType.Assembly.FullName);
+ Serialize(info, formatter);
+ }
+
+ void ISerializable.Deserialize(SerializationInfo info, XmlFormatter formatter)
+ {
+ Deserialize(info, formatter);
+ }
+
+ #endregion
+
+ protected virtual void Serialize(SerializationInfo info, XmlFormatter formatter)
+ {
+ var currentType = GetType();
+
+ while (currentType != null)
+ {
+ var fields = currentType.GetFields(
+ BindingFlags.NonPublic |
+ BindingFlags.Instance |
+ BindingFlags.Public);
+
+ foreach (var field in fields)
+ {
+ if (field.IsNotSerialized || IsNonSerialized(field))
+ {
+ continue;
+ }
+
+ var value = GetValue(field);
+ var mobile = value as ISerializable;
+ info.AddValue(
+ string.Format("{0}!{1}", field.DeclaringType.Name, field.Name),
+ mobile == null ? value : formatter.SerializeObject(mobile));
+ }
+ currentType = currentType.BaseType;
+ }
+ }
+
+ private static bool IsNonSerialized(ICustomAttributeProvider field)
+ {
+ var a = field.GetCustomAttributes(typeof(NonSerializedAttribute), false);
+ return a.Length > 0;
+ }
+
+ protected virtual void Deserialize(SerializationInfo info, XmlFormatter formatter)
+ {
+ var currentType = GetType();
+
+ while (currentType != null)
+ {
+ // get the list of fields in this type
+ var fields = currentType.GetFields(
+ BindingFlags.NonPublic |
+ BindingFlags.Instance |
+ BindingFlags.Public);
+
+ foreach (var field in fields)
+ {
+ // see if this field is marked as not undoable
+ if (field.IsNotSerialized || IsNonSerialized(field))
+ {
+ continue;
+ }
+
+ var value = info.GetValue(string.Format("{0}!{1}", field.DeclaringType.Name, field.Name));
+ var valueInfo = value as SerializationInfo;
+ if (valueInfo == null)
+ {
+ SetValue(field, Convert.ChangeType(value, field.FieldType, null));
+ }
+ else
+ {
+ SetValue(field, formatter.GetObject(valueInfo.ReferenceId));
+ }
+ }
+ currentType = currentType.BaseType;
+ }
+ }
+
+ protected abstract void SetValue(FieldInfo field, object value);
+ protected abstract object GetValue(FieldInfo field);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Serialization
+{
+ [Serializable]
+ public class SerializableDateTime : SerializableBase
+ {
+ public DateTime DateTime { get; set; }
+
+ public SerializableDateTime(int year, int month, int day)
+ {
+ DateTime = new DateTime(year, month, day);
+ }
+
+ public SerializableDateTime()
+ {
+
+ }
+
+ protected override object GetValue(System.Reflection.FieldInfo field)
+ {
+ return field.DeclaringType == typeof (SerializableDateTime) ? field.GetValue(this) : null;
+ }
+
+ protected override void SetValue(System.Reflection.FieldInfo field, object value)
+ {
+ if (field.DeclaringType == typeof(SerializableDateTime))
+ {
+ field.SetValue(this, value);
+ }
+ }
+
+ public bool Equals(SerializableDateTime other)
+ {
+ if (ReferenceEquals(null, other))
+ {
+ return false;
+ }
+ return ReferenceEquals(this, other) || Equals(other.DateTime, DateTime);
+ }
+
+ public override bool Equals(object other)
+ {
+ if (ReferenceEquals(null, other))
+ {
+ return false;
+ }
+ if (ReferenceEquals(this, other))
+ {
+ return true;
+ }
+ return other.GetType() == typeof (SerializableDateTime) && Equals((SerializableDateTime) other);
+ }
+
+ public override int GetHashCode()
+ {
+ return DateTime.GetHashCode();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace ICSharpCode.SharpZipLib.Silverlight.Serialization
+{
+ [Serializable]
+ public class SerializableString : SerializableBase
+ {
+ public string String { get; set; }
+
+ public SerializableString (string value)
+ {
+ String = value;
+ }
+
+ public SerializableString()
+ {
+
+ }
+
+ protected override object GetValue(System.Reflection.FieldInfo field)
+ {
+ return field.DeclaringType == typeof (SerializableString) ? field.GetValue(this) : null;
+ }
+
+ public bool Equals(SerializableString other)
+ {
+ if (ReferenceEquals(null, other))
+ {
+ return false;
+ }
+ return ReferenceEquals(this, other) || Equals(other.String, String);
+ }
+
+ public override bool Equals(object other)
+ {
+ if (ReferenceEquals(null, other))
+ {
+ return false;
+ }
+ if (ReferenceEquals(this, other))
+ {
+ return true;
+ }
+ return other.GetType() == typeof (SerializableString) && Equals((SerializableString) other);
+ }
+
+ public override int GetHashCode()
+ {
+ return (String != null ? String.GetHashCode() : 0);
+ }
+
+ protected override void SetValue(System.Reflection.FieldInfo field, object value)
+ {
+ if (field.DeclaringType == typeof(SerializableString))
+ {
+ field.SetValue(this, value);
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Linq;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Serialization
+{
+ /// <summary>
+ /// Code originally authored by Rockford Lhotka:
+ /// http://www.lhotka.net/weblog/SilverlightSerialization.aspx,
+ /// presented here with minor naming and code changes.
+ /// </summary>
+ public class SerializationInfo
+ {
+ private class ValueEntry
+ {
+ public string Name { get; private set; }
+ public object Value { get; private set; }
+
+ public ValueEntry(string name, object value)
+ {
+ Name = name;
+ Value = value;
+ }
+ }
+
+ private readonly Dictionary<string, ValueEntry> _values = new Dictionary<string, ValueEntry>();
+
+ internal SerializationInfo(int referenceId)
+ {
+ ReferenceId = referenceId;
+ }
+
+ internal int ReferenceId { get; private set; }
+
+ public string TypeName { get; set; }
+
+ public void AddValue(string name, object value)
+ {
+ _values.Add(name, new ValueEntry(name, value));
+ }
+
+ public object GetValue(string name)
+ {
+ ValueEntry result;
+ return _values.TryGetValue(name, out result) ? result.Value : null;
+ }
+
+ internal XElement ToXElement()
+ {
+ var root = new XElement("o");
+ root.Add(new XAttribute("i", ReferenceId));
+ root.Add(new XAttribute("t", TypeName));
+
+ foreach (var item in _values)
+ {
+ var info = item.Value.Value as SerializationInfo;
+ if (info == null)
+ {
+ var list = item.Value.Value as List<SerializationInfo>;
+ if (list == null)
+ {
+ if (item.Value.Value != null)
+ root.Add(new XElement("f",
+ new XAttribute("n", item.Value.Name),
+ new XAttribute("v", item.Value.Value)));
+ }
+ else
+ {
+ var listElement = new XElement("l",
+ new XAttribute("n", item.Value.Name));
+ foreach (var listItem in list)
+ listElement.Add(new XElement("r",
+ new XAttribute("i", listItem.ReferenceId)));
+ root.Add(listElement);
+ }
+ }
+ else
+ root.Add(new XElement("r",
+ new XAttribute("n", item.Value.Name),
+ new XAttribute("i", info.ReferenceId)));
+ }
+ return root;
+ }
+
+ internal SerializationInfo(XElement data)
+ {
+ ReferenceId = Convert.ToInt32(data.Attribute("i").Value);
+ if (data.Name == "o")
+ {
+ TypeName = data.Attribute("t").Value;
+ }
+ }
+
+ internal void Deserialize(XElement data, XmlFormatter formatter)
+ {
+ foreach (var item in data.Elements())
+ {
+ if (item.Name == "f")
+ {
+ var entry = new ValueEntry(item.Attribute("n").Value, item.Attribute("v").Value);
+ _values.Add(entry.Name, entry);
+ }
+ else if (item.Name == "l")
+ {
+ var listItems = item.Elements().Select(content => new SerializationInfo(content)).ToList();
+
+ var entry = new ValueEntry(item.Attribute("n").Value, listItems);
+ _values.Add(entry.Name, entry);
+ }
+ else
+ {
+ var referenceId = Convert.ToInt32(item.Attribute("i").Value);
+ var entry = new ValueEntry(
+ item.Attribute("n").Value,
+ new SerializationInfo(referenceId));
+ _values.Add(entry.Name, entry);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Xml;
+using System.Xml.Linq;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Serialization
+{
+ /// <summary>
+ /// Code originally authored by Rockford Lhotka:
+ /// http://www.lhotka.net/weblog/SilverlightSerialization.aspx,
+ /// presented here with minor naming and code changes.
+ /// </summary>
+ public sealed partial class XmlFormatter
+ {
+ private readonly Dictionary<ISerializable, SerializationInfo> _serializationReferences =
+ new Dictionary<ISerializable, SerializationInfo>();
+
+ public void Serialize(Stream serializationStream, object graph)
+ {
+ var writer = XmlWriter.Create(serializationStream);
+ Serialize(writer, graph);
+ if (writer != null)
+ {
+ writer.Flush();
+ }
+ }
+
+ public void Serialize(TextWriter textWriter, object graph)
+ {
+ var writer = XmlWriter.Create(textWriter);
+ Serialize(writer, graph);
+ if (writer != null)
+ {
+ writer.Flush();
+ }
+ }
+
+ public void Serialize(XmlWriter writer, object graph)
+ {
+ _serializationReferences.Clear();
+
+ var document = new XDocument();
+ SerializeObject(graph);
+ var root = new XElement("g");
+ foreach (var item in _serializationReferences)
+ {
+ root.Add(item.Value.ToXElement());
+ }
+ document.Add(root);
+ document.Save(writer);
+ }
+
+ internal SerializationInfo SerializeObject(object obj)
+ {
+ var thisType = obj.GetType();
+ if (!IsSerializable(thisType))
+ {
+ throw new InvalidOperationException("Object not serializable");
+ }
+ var mobile = obj as ISerializable;
+ if (mobile == null)
+ {
+ throw new InvalidOperationException(
+ string.Format("Type {0} must implement ISerializable",
+ thisType.Name));
+ }
+
+ SerializationInfo info;
+ if (!_serializationReferences.TryGetValue(mobile, out info))
+ {
+ info = new SerializationInfo(_serializationReferences.Count + 1);
+ _serializationReferences.Add(mobile, info);
+ mobile.Serialize(info, this);
+ }
+ return info;
+ }
+
+ private static bool IsSerializable(ICustomAttributeProvider objectType)
+ {
+ var a = objectType.GetCustomAttributes(typeof (SerializableAttribute), false);
+ return a.Length > 0;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Xml;
+using System.Xml.Linq;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Serialization
+{
+ /// <summary>
+ /// Code originally authored by Rockford Lhotka:
+ /// http://www.lhotka.net/weblog/SilverlightSerialization.aspx,
+ /// presented here with minor naming and code changes.
+ /// </summary>
+ public sealed partial class XmlFormatter
+ {
+ private readonly Dictionary<int, ISerializable> _deserializationReferences =
+ new Dictionary<int, ISerializable>();
+
+ public object Deserialize(Stream serializationStream)
+ {
+ var reader = XmlReader.Create(serializationStream);
+ return Deserialize(reader);
+ }
+
+ public object Deserialize(TextReader textReader)
+ {
+ var reader = XmlReader.Create(textReader);
+ return Deserialize(reader);
+ }
+
+ public object Deserialize(XmlReader reader)
+ {
+ var doc = XDocument.Load(reader);
+ var root = (XElement) doc.FirstNode;
+
+ _deserializationReferences.Clear();
+
+ var objects = from e in root.Elements()
+ where e.Name == "o"
+ select e;
+
+ var infos = new Dictionary<int, SerializationInfo>();
+
+ foreach (var item in objects)
+ {
+ var info = new SerializationInfo(item);
+ infos.Add(info.ReferenceId, info);
+ var objType = Type.GetType(info.TypeName);
+ var mobile = Activator.CreateInstance(objType) as ISerializable;
+ _deserializationReferences.Add(info.ReferenceId, mobile);
+ }
+
+ foreach (var item in objects)
+ {
+ if (item == null)
+ {
+ continue;
+ }
+
+ var referenceId = Convert.ToInt32(item.Attribute("i").Value);
+ var info = infos[referenceId];
+ info.Deserialize(item, this);
+ }
+
+ foreach (var info in infos)
+ {
+ GetObject(info.Value.ReferenceId).Deserialize(info.Value, this);
+ }
+
+ return _deserializationReferences[1];
+ }
+
+ internal ISerializable GetObject(int referenceId)
+ {
+ return _deserializationReferences[referenceId];
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// SharpZipBaseException.cs
+//
+// Copyright 2004 John Reilly
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using ICSharpCode.SharpZipLib.Silverlight.Serialization;
+
+namespace ICSharpCode.SharpZipLib.Silverlight
+{
+ /// <summary>
+ /// SharpZipBaseException is the base exception class for the SharpZipLibrary.
+ /// All library exceptions are derived from this.
+ /// </summary>
+ /// <remarks>NOTE: Not all exceptions thrown will be derived from this class.
+ /// A variety of other exceptions are possible for example <see cref="ArgumentNullException"></see></remarks>
+ [Serializable]
+ public class SharpZipBaseException : Exception
+ {
+ /// <summary>
+ /// Deserialization constructor
+ /// </summary>
+ /// <param name="info"><see cref="System.Runtime.Serialization.SerializationInfo"/> for this constructor</param>
+ protected SharpZipBaseException(SerializationInfo info)
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the SharpZipBaseException class.
+ /// </summary>
+ public SharpZipBaseException()
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the SharpZipBaseException class with a specified error message.
+ /// </summary>
+ /// <param name="message">A message describing the exception.</param>
+ public SharpZipBaseException(string message)
+ : base(message)
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the SharpZipBaseException class with a specified
+ /// error message and a reference to the inner exception that is the cause of this exception.
+ /// </summary>
+ /// <param name="message">A message describing the exception.</param>
+ /// <param name="innerException">The inner exception</param>
+ public SharpZipBaseException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// InvalidHeaderException.cs
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using ICSharpCode.SharpZipLib.Silverlight.Serialization;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Tar
+{
+ /// <summary>
+ /// This exception is used to indicate that there is a problem
+ /// with a TAR archive header.
+ /// </summary>
+ [Serializable]
+ public class InvalidHeaderException : TarException
+ {
+ /// <summary>
+ /// Deserialization constructor
+ /// </summary>
+ /// <param name="information"><see cref="System.Runtime.Serialization.SerializationInfo"/> for this constructor</param>
+ protected InvalidHeaderException(SerializationInfo information)
+ : base(information)
+ {
+ }
+
+ /// <summary>
+ /// Initialise a new instance of the InvalidHeaderException class.
+ /// </summary>
+ public InvalidHeaderException()
+ {
+ }
+
+ /// <summary>
+ /// Initialises a new instance of the InvalidHeaderException class with a specified message.
+ /// </summary>
+ /// <param name="message">Message describing the exception cause.</param>
+ public InvalidHeaderException(string message)
+ : base(message)
+ {
+ }
+
+ /// <summary>
+ /// Initialise a new instance of InvalidHeaderException
+ /// </summary>
+ /// <param name="message">Message describing the problem.</param>
+ /// <param name="exception">The exception that is the cause of the current exception.</param>
+ public InvalidHeaderException(string message, Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
+
+/* The original Java file had this header:
+** Authored by Timothy Gerard Endres
+** <mailto:time@gjt.org> <http://www.trustice.com>
+**
+** This work has been placed into the public domain.
+** You may use this work in any way and for any purpose you wish.
+**
+** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
+** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
+** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
+** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
+** REDISTRIBUTION OF THIS SOFTWARE.
+**
+*/
\ No newline at end of file
--- /dev/null
+// TarArchive.cs
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+using System.Text;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Tar
+{
+ /// <summary>
+ /// Used to advise clients of 'events' while processing archives
+ /// </summary>
+ public delegate void ProgressMessageHandler(TarArchive archive, TarEntry entry, string message);
+
+ /// <summary>
+ /// The TarArchive class implements the concept of a
+ /// 'Tape Archive'. A tar archive is a series of entries, each of
+ /// which represents a file system object. Each entry in
+ /// the archive consists of a header block followed by 0 or more data blocks.
+ /// Directory entries consist only of the header block, and are followed by entries
+ /// for the directory's contents. File entries consist of a
+ /// header followed by the number of blocks needed to
+ /// contain the file's contents. All entries are written on
+ /// block boundaries. Blocks are 512 bytes long.
+ ///
+ /// TarArchives are instantiated in either read or write mode,
+ /// based upon whether they are instantiated with an InputStream
+ /// or an OutputStream. Once instantiated TarArchives read/write
+ /// mode can not be changed.
+ ///
+ /// There is currently no support for random access to tar archives.
+ /// However, it seems that subclassing TarArchive, and using the
+ /// TarBuffer.CurrentRecord and TarBuffer.CurrentBlock
+ /// properties, this would be rather trivial.
+ /// </summary>
+ public class TarArchive : IDisposable
+ {
+ /// <summary>
+ /// Get/set the ascii file translation flag. If ascii file translation
+ /// is true, then the file is checked to see if it a binary file or not.
+ /// If the flag is true and the test indicates it is ascii text
+ /// file, it will be translated. The translation converts the local
+ /// operating system's concept of line ends into the UNIX line end,
+ /// '\n', which is the defacto standard for a TAR archive. This makes
+ /// text files compatible with UNIX.
+ /// </summary>
+ public bool AsciiTranslate
+ {
+ get
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException("TarArchive");
+ }
+
+ return _asciiTranslate;
+ }
+
+ set
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException("TarArchive");
+ }
+
+ _asciiTranslate = value;
+ }
+ }
+
+ /// <summary>
+ /// PathPrefix is added to entry names as they are written if the value is not null.
+ /// A slash character is appended after PathPrefix
+ /// </summary>
+ public string PathPrefix
+ {
+ get
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException("TarArchive");
+ }
+
+ return pathPrefix;
+ }
+
+ set
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException("TarArchive");
+ }
+
+ pathPrefix = value;
+ }
+ }
+
+ /// <summary>
+ /// RootPath is removed from entry names if it is found at the
+ /// beginning of the name.
+ /// </summary>
+ public string RootPath
+ {
+ get
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException("TarArchive");
+ }
+
+ return rootPath;
+ }
+
+ set
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException("TarArchive");
+ }
+
+ rootPath = value;
+ }
+ }
+
+ /// <summary>
+ /// Get or set a value indicating if overrides defined by <see cref="SetUserInfo">SetUserInfo</see> should be applied.
+ /// </summary>
+ /// <remarks>If overrides are not applied then the values as set in each header will be used.</remarks>
+ public bool ApplyUserInfoOverrides
+ {
+ get
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException("TarArchive");
+ }
+
+ return _applyUserInfoOverrides;
+ }
+
+ set
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException("TarArchive");
+ }
+
+ _applyUserInfoOverrides = value;
+ }
+ }
+
+ /// <summary>
+ /// Get the archive user id.
+ /// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail
+ /// on how to allow setting values on a per entry basis.
+ /// </summary>
+ /// <returns>
+ /// The current user id.
+ /// </returns>
+ public int UserId
+ {
+ get
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException("TarArchive");
+ }
+
+ return _userId;
+ }
+ }
+
+ /// <summary>
+ /// Get the archive user name.
+ /// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail
+ /// on how to allow setting values on a per entry basis.
+ /// </summary>
+ /// <returns>
+ /// The current user name.
+ /// </returns>
+ public string UserName
+ {
+ get
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException("TarArchive");
+ }
+
+ return _userName;
+ }
+ }
+
+ /// <summary>
+ /// Get the archive group id.
+ /// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail
+ /// on how to allow setting values on a per entry basis.
+ /// </summary>
+ /// <returns>
+ /// The current group id.
+ /// </returns>
+ public int GroupId
+ {
+ get
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException("TarArchive");
+ }
+
+ return _groupId;
+ }
+ }
+
+ /// <summary>
+ /// Get the archive group name.
+ /// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail
+ /// on how to allow setting values on a per entry basis.
+ /// </summary>
+ /// <returns>
+ /// The current group name.
+ /// </returns>
+ public string GroupName
+ {
+ get
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException("TarArchive");
+ }
+
+ return _groupName;
+ }
+ }
+
+ /// <summary>
+ /// Get the archive's record size. Tar archives are composed of
+ /// a series of RECORDS each containing a number of BLOCKS.
+ /// This allowed tar archives to match the IO characteristics of
+ /// the physical device being used. Archives are expected
+ /// to be properly "blocked".
+ /// </summary>
+ /// <returns>
+ /// The record size this archive is using.
+ /// </returns>
+ public int RecordSize
+ {
+ get
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException("TarArchive");
+ }
+
+ if (tarIn != null)
+ {
+ return tarIn.RecordSize;
+ }
+ if (tarOut != null)
+ {
+ return tarOut.RecordSize;
+ }
+ return TarBuffer.DefaultRecordSize;
+ }
+ }
+
+ #region IDisposable Members
+
+ void IDisposable.Dispose()
+ {
+ Close();
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Client hook allowing detailed information to be reported during processing
+ /// </summary>
+ public event ProgressMessageHandler ProgressMessageEvent;
+
+ /// <summary>
+ /// Raises the ProgressMessage event
+ /// </summary>
+ /// <param name="entry">The <see cref="TarEntry">TarEntry</see> for this event</param>
+ /// <param name="message">message for this event. Null is no message</param>
+ protected virtual void OnProgressMessageEvent(TarEntry entry, string message)
+ {
+ if (ProgressMessageEvent != null)
+ {
+ ProgressMessageEvent(this, entry, message);
+ }
+ }
+
+ /// <summary>
+ /// Set the flag that determines whether existing files are
+ /// kept, or overwritten during extraction.
+ /// </summary>
+ /// <param name="keepOldFiles">
+ /// If true, do not overwrite existing files.
+ /// </param>
+ public void SetKeepOldFiles(bool keepOldFiles)
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException("TarArchive");
+ }
+ _keepOldFiles = keepOldFiles;
+ }
+
+ /// <summary>
+ /// Set the ascii file translation flag.
+ /// </summary>
+ /// <param name= "asciiTranslate">
+ /// If true, translate ascii text files.
+ /// </param>
+ [Obsolete("Use the AsciiTranslate property")]
+ public void SetAsciiTranslation(bool asciiTranslate)
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException("TarArchive");
+ }
+
+ _asciiTranslate = asciiTranslate;
+ }
+
+ /// <summary>
+ /// Set user and group information that will be used to fill in the
+ /// tar archive's entry headers. This information based on that available
+ /// for the linux operating system, which is not always available on other
+ /// operating systems. TarArchive allows the programmer to specify values
+ /// to be used in their place.
+ /// <see cref="ApplyUserInfoOverrides"/> is set to true by this call.
+ /// </summary>
+ /// <param name="userId">
+ /// The user id to use in the headers.
+ /// </param>
+ /// <param name="userName">
+ /// The user name to use in the headers.
+ /// </param>
+ /// <param name="groupId">
+ /// The group id to use in the headers.
+ /// </param>
+ /// <param name="groupName">
+ /// The group name to use in the headers.
+ /// </param>
+ public void SetUserInfo(int userId, string userName, int groupId, string groupName)
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException("TarArchive");
+ }
+
+ _userId = userId;
+ _userName = userName;
+ _groupId = groupId;
+ _groupName = groupName;
+ _applyUserInfoOverrides = true;
+ }
+
+ /// <summary>
+ /// Close the archive.
+ /// </summary>
+ [Obsolete("Use Close instead")]
+ public void CloseArchive()
+ {
+ Close();
+ }
+
+ /// <summary>
+ /// Perform the "list" command for the archive contents.
+ ///
+ /// NOTE That this method uses the <see cref="ProgressMessageEvent"> progress event</see> to actually list
+ /// the contents. If the progress display event is not set, nothing will be listed!
+ /// </summary>
+ public void ListContents()
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException("TarArchive");
+ }
+
+ while (true)
+ {
+ var entry = tarIn.GetNextEntry();
+
+ if (entry == null)
+ {
+ break;
+ }
+ OnProgressMessageEvent(entry, null);
+ }
+ }
+
+ /// <summary>
+ /// Perform the "extract" command and extract the contents of the archive.
+ /// </summary>
+ /// <param name="destinationDirectory">
+ /// The destination directory into which to extract.
+ /// </param>
+ public void ExtractContents(string destinationDirectory)
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException("TarArchive");
+ }
+
+ while (true)
+ {
+ var entry = tarIn.GetNextEntry();
+
+ if (entry == null)
+ {
+ break;
+ }
+
+ ExtractEntry(destinationDirectory, entry);
+ }
+ }
+
+ /// <summary>
+ /// Extract an entry from the archive. This method assumes that the
+ /// tarIn stream has been properly set with a call to GetNextEntry().
+ /// </summary>
+ /// <param name="destDir">
+ /// The destination directory into which to extract.
+ /// </param>
+ /// <param name="entry">
+ /// The TarEntry returned by tarIn.GetNextEntry().
+ /// </param>
+ private void ExtractEntry(string destDir, TarEntry entry)
+ {
+ OnProgressMessageEvent(entry, null);
+
+ var name = entry.Name;
+
+ if (Path.IsPathRooted(name))
+ {
+ // NOTE:
+ // for UNC names... \\machine\share\zoom\beet.txt gives \zoom\beet.txt
+ name = name.Substring(Path.GetPathRoot(name).Length);
+ }
+
+ name = name.Replace('/', Path.DirectorySeparatorChar);
+
+ var destFile = Path.Combine(destDir, name);
+
+ if (entry.IsDirectory)
+ {
+ EnsureDirectoryExists(destFile);
+ }
+ else
+ {
+ var parentDirectory = Path.GetDirectoryName(destFile);
+ EnsureDirectoryExists(parentDirectory);
+
+ var process = true;
+ var fileInfo = new FileInfo(destFile);
+ if (fileInfo.Exists)
+ {
+ if (_keepOldFiles)
+ {
+ OnProgressMessageEvent(entry, "Destination file already exists");
+ process = false;
+ }
+ else if ((fileInfo.Attributes & FileAttributes.ReadOnly) != 0)
+ {
+ OnProgressMessageEvent(entry, "Destination file already exists, and is read-only");
+ process = false;
+ }
+ }
+
+ if (process)
+ {
+ var asciiTrans = false;
+
+ Stream outputStream = File.Create(destFile);
+ if (_asciiTranslate)
+ {
+ asciiTrans = !IsBinary(destFile);
+ }
+
+ StreamWriter outw = null;
+ if (asciiTrans)
+ {
+ outw = new StreamWriter(outputStream);
+ }
+
+ var rdbuf = new byte[32*1024];
+
+ while (true)
+ {
+ var numRead = tarIn.Read(rdbuf, 0, rdbuf.Length);
+
+ if (numRead <= 0)
+ {
+ break;
+ }
+
+ if (asciiTrans)
+ {
+ for (int off = 0, b = 0; b < numRead; ++b)
+ {
+ if (rdbuf[b] == 10)
+ {
+ var s = Encoding.UTF8.GetString(rdbuf, off, (b - off));
+ outw.WriteLine(s);
+ off = b + 1;
+ }
+ }
+ }
+ else
+ {
+ outputStream.Write(rdbuf, 0, numRead);
+ }
+ }
+
+ if (asciiTrans)
+ {
+ outw.Close();
+ }
+ else
+ {
+ outputStream.Close();
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Write an entry to the archive. This method will call the putNextEntry
+ /// and then write the contents of the entry, and finally call closeEntry()
+ /// for entries that are files. For directories, it will call putNextEntry(),
+ /// and then, if the recurse flag is true, process each entry that is a
+ /// child of the directory.
+ /// </summary>
+ /// <param name="sourceEntry">
+ /// The TarEntry representing the entry to write to the archive.
+ /// </param>
+ /// <param name="recurse">
+ /// If true, process the children of directory entries.
+ /// </param>
+ public void WriteEntry(TarEntry sourceEntry, bool recurse)
+ {
+ if (sourceEntry == null)
+ {
+ throw new ArgumentNullException("sourceEntry");
+ }
+
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException("TarArchive");
+ }
+
+ try
+ {
+ if (recurse)
+ {
+ TarHeader.SetValueDefaults(sourceEntry.UserId, sourceEntry.UserName,
+ sourceEntry.GroupId, sourceEntry.GroupName);
+ }
+ InternalWriteEntry(sourceEntry, recurse);
+ }
+ finally
+ {
+ if (recurse)
+ {
+ TarHeader.RestoreSetValues();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Write an entry to the archive. This method will call the putNextEntry
+ /// and then write the contents of the entry, and finally call closeEntry()
+ /// for entries that are files. For directories, it will call putNextEntry(),
+ /// and then, if the recurse flag is true, process each entry that is a
+ /// child of the directory.
+ /// </summary>
+ /// <param name="sourceEntry">
+ /// The TarEntry representing the entry to write to the archive.
+ /// </param>
+ /// <param name="recurse">
+ /// If true, process the children of directory entries.
+ /// </param>
+ private void InternalWriteEntry(TarEntry sourceEntry, bool recurse)
+ {
+ string tempFileName = null;
+ var entryFilename = sourceEntry.File;
+
+ var entry = (TarEntry) sourceEntry.Clone();
+
+ if (_applyUserInfoOverrides)
+ {
+ entry.GroupId = _groupId;
+ entry.GroupName = _groupName;
+ entry.UserId = _userId;
+ entry.UserName = _userName;
+ }
+
+ OnProgressMessageEvent(entry, null);
+
+ if (_asciiTranslate && !entry.IsDirectory)
+ {
+ var asciiTrans = !IsBinary(entryFilename);
+
+ if (asciiTrans)
+ {
+ tempFileName = Path.GetTempFileName();
+
+ using (var inStream = File.OpenText(entryFilename))
+ {
+ using (Stream outStream = File.Create(tempFileName))
+ {
+ while (true)
+ {
+ var line = inStream.ReadLine();
+ if (line == null)
+ {
+ break;
+ }
+ var data = Encoding.UTF8.GetBytes(line);
+ outStream.Write(data, 0, data.Length);
+ outStream.WriteByte((byte) '\n');
+ }
+
+ outStream.Flush();
+ }
+ }
+
+ entry.Size = new FileInfo(tempFileName).Length;
+ entryFilename = tempFileName;
+ }
+ }
+
+ string newName = null;
+
+ if (rootPath != null)
+ {
+ if (entry.Name.StartsWith(rootPath))
+ {
+ newName = entry.Name.Substring(rootPath.Length + 1);
+ }
+ }
+
+ if (pathPrefix != null)
+ {
+ newName = (newName == null) ? string.Format("{0}/{1}", pathPrefix, entry.Name) : pathPrefix + "/" + newName;
+ }
+
+ if (newName != null)
+ {
+ entry.Name = newName;
+ }
+
+ tarOut.PutNextEntry(entry);
+
+ if (entry.IsDirectory)
+ {
+ if (recurse)
+ {
+ var list = entry.GetDirectoryEntries();
+ for (var i = 0; i < list.Length; ++i)
+ {
+ InternalWriteEntry(list[i], recurse);
+ }
+ }
+ }
+ else
+ {
+ using (Stream inputStream = File.OpenRead(entryFilename))
+ {
+ var localBuffer = new byte[32*1024];
+ while (true)
+ {
+ var numRead = inputStream.Read(localBuffer, 0, localBuffer.Length);
+
+ if (numRead <= 0)
+ {
+ break;
+ }
+
+ tarOut.Write(localBuffer, 0, numRead);
+ }
+ }
+
+ if (!string.IsNullOrEmpty(tempFileName))
+ {
+ File.Delete(tempFileName);
+ }
+
+ tarOut.CloseEntry();
+ }
+ }
+
+ /// <summary>
+ /// Releases the unmanaged resources used by the FileStream and optionally releases the managed resources.
+ /// </summary>
+ /// <param name="disposing">true to release both managed and unmanaged resources;
+ /// false to release only unmanaged resources.</param>
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!isDisposed)
+ {
+ isDisposed = true;
+ if (disposing)
+ {
+ if (tarOut != null)
+ {
+ tarOut.Flush();
+ tarOut.Close();
+ }
+
+ if (tarIn != null)
+ {
+ tarIn.Close();
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Closes the archive and releases any associated resources.
+ /// </summary>
+ public virtual void Close()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// Ensures that resources are freed and other cleanup operations are performed
+ /// when the garbage collector reclaims the <see cref="TarArchive"/>.
+ /// </summary>
+ ~TarArchive()
+ {
+ Dispose(false);
+ }
+
+ private static void EnsureDirectoryExists(string directoryName)
+ {
+ if (!Directory.Exists(directoryName))
+ {
+ try
+ {
+ Directory.CreateDirectory(directoryName);
+ }
+ catch (Exception e)
+ {
+ throw new TarException("Exception creating directory '" + directoryName + "', " + e.Message, e);
+ }
+ }
+ }
+
+ // TODO: TarArchive - Is there a better way to test for a text file?
+ // It no longer reads entire files into memory but is still a weak test!
+ // This assumes that byte values 0-7, 14-31 or 255 are binary
+ // and that all non text files contain one of these values
+ private static bool IsBinary(string filename)
+ {
+ using (var fs = File.OpenRead(filename))
+ {
+ var sampleSize = Math.Min(4096, (int) fs.Length);
+ var content = new byte[sampleSize];
+
+ var bytesRead = fs.Read(content, 0, sampleSize);
+
+ for (var i = 0; i < bytesRead; ++i)
+ {
+ var b = content[i];
+ if ((b < 8) || ((b > 13) && (b < 32)) || (b == 255))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ #region Instance Fields
+
+ private readonly TarInputStream tarIn;
+ private readonly TarOutputStream tarOut;
+ private bool _applyUserInfoOverrides;
+ private bool _asciiTranslate;
+
+ private int _groupId;
+ private string _groupName = string.Empty;
+
+ private bool isDisposed;
+ private bool _keepOldFiles;
+ private string pathPrefix;
+ private string rootPath;
+ private int _userId;
+ private string _userName = string.Empty;
+
+ #endregion
+
+ #region Constructors
+
+ /// <summary>
+ /// Constructor for a default <see cref="TarArchive"/>.
+ /// </summary>
+ protected TarArchive()
+ {
+ }
+
+ /// <summary>
+ /// Initalise a TarArchive for input.
+ /// </summary>
+ /// <param name="stream">The <see cref="TarInputStream"/> to use for input.</param>
+ protected TarArchive(TarInputStream stream)
+ {
+ if (stream == null)
+ {
+ throw new ArgumentNullException("stream");
+ }
+
+ tarIn = stream;
+ }
+
+ /// <summary>
+ /// Initialise a TarArchive for output.
+ /// </summary>
+ /// <param name="stream">The <see cref="TarOutputStream"/> to use for output.</param>
+ protected TarArchive(TarOutputStream stream)
+ {
+ if (stream == null)
+ {
+ throw new ArgumentNullException("stream");
+ }
+
+ tarOut = stream;
+ }
+
+ #endregion
+
+ #region Static factory methods
+
+ /// <summary>
+ /// The InputStream based constructors create a TarArchive for the
+ /// purposes of extracting or listing a tar archive. Thus, use
+ /// these constructors when you wish to extract files from or list
+ /// the contents of an existing tar archive.
+ /// </summary>
+ /// <param name="inputStream">The stream to retrieve archive data from.</param>
+ /// <returns>Returns a new <see cref="TarArchive"/> suitable for reading from.</returns>
+ public static TarArchive CreateInputTarArchive(Stream inputStream)
+ {
+ if (inputStream == null)
+ {
+ throw new ArgumentNullException("inputStream");
+ }
+
+ return CreateInputTarArchive(inputStream, TarBuffer.DefaultBlockFactor);
+ }
+
+ /// <summary>
+ /// Create TarArchive for reading setting block factor
+ /// </summary>
+ /// <param name="inputStream">Stream for tar archive contents</param>
+ /// <param name="blockFactor">The blocking factor to apply</param>
+ /// <returns>Returns a <see cref="TarArchive"/> suitable for reading.</returns>
+ public static TarArchive CreateInputTarArchive(Stream inputStream, int blockFactor)
+ {
+ if (inputStream == null)
+ {
+ throw new ArgumentNullException("inputStream");
+ }
+
+ return new TarArchive(new TarInputStream(inputStream, blockFactor));
+ }
+
+ /// <summary>
+ /// Create a TarArchive for writing to, using the default blocking factor
+ /// </summary>
+ /// <param name="outputStream">The <see cref="Stream"/> to write to</param>
+ /// <returns>Returns a <see cref="TarArchive"/> suitable for writing.</returns>
+ public static TarArchive CreateOutputTarArchive(Stream outputStream)
+ {
+ if (outputStream == null)
+ {
+ throw new ArgumentNullException("outputStream");
+ }
+
+ return CreateOutputTarArchive(outputStream, TarBuffer.DefaultBlockFactor);
+ }
+
+ /// <summary>
+ /// Create a TarArchive for writing to
+ /// </summary>
+ /// <param name="outputStream">The stream to write to</param>
+ /// <param name="blockFactor">The blocking factor to use for buffering.</param>
+ /// <returns>Returns a <see cref="TarArchive"/> suitable for writing.</returns>
+ public static TarArchive CreateOutputTarArchive(Stream outputStream, int blockFactor)
+ {
+ if (outputStream == null)
+ {
+ throw new ArgumentNullException("outputStream");
+ }
+
+ return new TarArchive(new TarOutputStream(outputStream, blockFactor));
+ }
+
+ #endregion
+ }
+}
+
+/* The original Java file had this header:
+ ** Authored by Timothy Gerard Endres
+ ** <mailto:time@gjt.org> <http://www.trustice.com>
+ **
+ ** This work has been placed into the public domain.
+ ** You may use this work in any way and for any purpose you wish.
+ **
+ ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
+ ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
+ ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
+ ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
+ ** REDISTRIBUTION OF THIS SOFTWARE.
+ **
+ */
\ No newline at end of file
--- /dev/null
+// TarBuffer.cs
+// Copyright (C) 2001 Mike Krueger
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Tar
+{
+ /// <summary>
+ /// The TarBuffer class implements the tar archive concept
+ /// of a buffered input stream. This concept goes back to the
+ /// days of blocked tape drives and special io devices. In the
+ /// C# universe, the only real function that this class
+ /// performs is to ensure that files have the correct "record"
+ /// size, or other tars will complain.
+ /// <p>
+ /// You should never have a need to access this class directly.
+ /// TarBuffers are created by Tar IO Streams.
+ /// </p>
+ /// </summary>
+ public class TarBuffer
+ {
+ #region Constants
+
+ /// <summary>
+ /// The size of a block in a tar archive in bytes.
+ /// </summary>
+ /// <remarks>This is 512 bytes.</remarks>
+ public const int BlockSize = 512;
+
+ /// <summary>
+ /// The number of blocks in a default record.
+ /// </summary>
+ /// <remarks>
+ /// The default value is 20 blocks per record.
+ /// </remarks>
+ public const int DefaultBlockFactor = 20;
+
+ /// <summary>
+ /// The size in bytes of a default record.
+ /// </summary>
+ /// <remarks>
+ /// The default size is 10KB.
+ /// </remarks>
+ public const int DefaultRecordSize = BlockSize*DefaultBlockFactor;
+
+ #endregion
+
+/* A quote from GNU tar man file on blocking and records
+ A `tar' archive file contains a series of blocks. Each block
+contains `BLOCKSIZE' bytes. Although this format may be thought of as
+being on magnetic tape, other media are often used.
+
+ Each file archived is represented by a header block which describes
+the file, followed by zero or more blocks which give the contents of
+the file. At the end of the archive file there may be a block filled
+with binary zeros as an end-of-file marker. A reasonable system should
+write a block of zeros at the end, but must not assume that such a
+block exists when reading an archive.
+
+ The blocks may be "blocked" for physical I/O operations. Each
+record of N blocks is written with a single 'write ()'
+operation. On magnetic tapes, the result of such a write is a single
+record. When writing an archive, the last record of blocks should be
+written at the full size, with blocks after the zero block containing
+all zeros. When reading an archive, a reasonable system should
+properly handle an archive whose last record is shorter than the rest,
+or which contains garbage records after a zero block.
+*/
+
+ /// <summary>
+ /// Construct a default TarBuffer
+ /// </summary>
+ protected TarBuffer()
+ {
+ }
+
+ /// <summary>
+ /// Get the record size for this buffer
+ /// </summary>
+ /// <value>The record size in bytes.
+ /// This is equal to the <see cref="BlockFactor"/> multiplied by the <see cref="BlockSize"/></value>
+ public int RecordSize
+ {
+ get { return recordSize; }
+ }
+
+ /// <summary>
+ /// Get the Blocking factor for the buffer
+ /// </summary>
+ /// <value>This is the number of block in each record.</value>
+ public int BlockFactor
+ {
+ get { return _blockFactor; }
+ }
+
+ /// <summary>
+ /// Get the current block number, within the current record, zero based.
+ /// </summary>
+ public int CurrentBlock
+ {
+ get { return currentBlockIndex; }
+ }
+
+ /// <summary>
+ /// Get the current record number.
+ /// </summary>
+ /// <returns>
+ /// The current zero based record number.
+ /// </returns>
+ public int CurrentRecord
+ {
+ get { return currentRecordIndex; }
+ }
+
+ /// <summary>
+ /// Get the TAR Buffer's record size.
+ /// </summary>
+ /// <returns>The record size in bytes.
+ /// This is equal to the <see cref="BlockFactor"/> multiplied by the <see cref="BlockSize"/></returns>
+ [Obsolete("Use RecordSize property instead")]
+ public int GetRecordSize()
+ {
+ return recordSize;
+ }
+
+ /// <summary>
+ /// Get the TAR Buffer's block factor
+ /// </summary>
+ /// <returns>The block factor; the number of blocks per record.</returns>
+ [Obsolete("Use BlockFactor property instead")]
+ public int GetBlockFactor()
+ {
+ return _blockFactor;
+ }
+
+ /// <summary>
+ /// Create TarBuffer for reading with default BlockFactor
+ /// </summary>
+ /// <param name="inputStream">Stream to buffer</param>
+ /// <returns>A new <see cref="TarBuffer"/> suitable for input.</returns>
+ public static TarBuffer CreateInputTarBuffer(Stream inputStream)
+ {
+ if (inputStream == null)
+ {
+ throw new ArgumentNullException("inputStream");
+ }
+
+ return CreateInputTarBuffer(inputStream, DefaultBlockFactor);
+ }
+
+ /// <summary>
+ /// Construct TarBuffer for reading inputStream setting BlockFactor
+ /// </summary>
+ /// <param name="inputStream">Stream to buffer</param>
+ /// <param name="blockFactor">Blocking factor to apply</param>
+ /// <returns>A new <see cref="TarBuffer"/> suitable for input.</returns>
+ public static TarBuffer CreateInputTarBuffer(Stream inputStream, int blockFactor)
+ {
+ if (inputStream == null)
+ {
+ throw new ArgumentNullException("inputStream");
+ }
+
+ if (blockFactor <= 0)
+ {
+ throw new ArgumentOutOfRangeException("blockFactor", "Factor cannot be negative");
+ }
+
+ var tarBuffer = new TarBuffer{inputStream = inputStream, outputStream = null};
+ tarBuffer.Initialize(blockFactor);
+
+ return tarBuffer;
+ }
+
+ /// <summary>
+ /// Construct TarBuffer for writing with default BlockFactor
+ /// </summary>
+ /// <param name="outputStream">output stream for buffer</param>
+ /// <returns>A new <see cref="TarBuffer"/> suitable for output.</returns>
+ public static TarBuffer CreateOutputTarBuffer(Stream outputStream)
+ {
+ if (outputStream == null)
+ {
+ throw new ArgumentNullException("outputStream");
+ }
+
+ return CreateOutputTarBuffer(outputStream, DefaultBlockFactor);
+ }
+
+ /// <summary>
+ /// Construct TarBuffer for writing Tar output to streams.
+ /// </summary>
+ /// <param name="outputStream">Output stream to write to.</param>
+ /// <param name="blockFactor">Blocking factor to apply</param>
+ /// <returns>A new <see cref="TarBuffer"/> suitable for output.</returns>
+ public static TarBuffer CreateOutputTarBuffer(Stream outputStream, int blockFactor)
+ {
+ if (outputStream == null)
+ {
+ throw new ArgumentNullException("outputStream");
+ }
+
+ if (blockFactor <= 0)
+ {
+ throw new ArgumentOutOfRangeException("blockFactor", "Factor cannot be negative");
+ }
+
+ var tarBuffer = new TarBuffer{inputStream = null, outputStream = outputStream};
+ tarBuffer.Initialize(blockFactor);
+
+ return tarBuffer;
+ }
+
+ /// <summary>
+ /// Initialization common to all constructors.
+ /// </summary>
+ private void Initialize(int blockFactor)
+ {
+ _blockFactor = blockFactor;
+ recordSize = blockFactor*BlockSize;
+ recordBuffer = new byte[RecordSize];
+
+ if (inputStream != null)
+ {
+ currentRecordIndex = -1;
+ currentBlockIndex = BlockFactor;
+ }
+ else
+ {
+ currentRecordIndex = 0;
+ currentBlockIndex = 0;
+ }
+ }
+
+ // TODO: IsEOFBlock could/should be static but this is a breaking change.
+
+ /// <summary>
+ /// Determine if an archive block indicates End of Archive. End of
+ /// archive is indicated by a block that consists entirely of null bytes.
+ /// All remaining blocks for the record should also be null's
+ /// However some older tars only do a couple of null blocks (Old GNU tar for one)
+ /// and also partial records
+ /// </summary>
+ /// <param name = "block">The data block to check.</param>
+ /// <returns>Returns true if the block is an EOF block; false otherwise.</returns>
+ public bool IsEOFBlock(byte[] block)
+ {
+ if (block == null)
+ {
+ throw new ArgumentNullException("block");
+ }
+
+ if (block.Length != BlockSize)
+ {
+ throw new ArgumentException("block length is invalid");
+ }
+
+ for (var i = 0; i < BlockSize; ++i)
+ {
+ if (block[i] != 0)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Skip over a block on the input stream.
+ /// </summary>
+ public void SkipBlock()
+ {
+ if (inputStream == null)
+ {
+ throw new TarException("no input stream defined");
+ }
+
+ if (currentBlockIndex >= BlockFactor)
+ {
+ if (!ReadRecord())
+ {
+ throw new TarException("Failed to read a record");
+ }
+ }
+
+ currentBlockIndex++;
+ }
+
+ /// <summary>
+ /// Read a block from the input stream.
+ /// </summary>
+ /// <returns>
+ /// The block of data read.
+ /// </returns>
+ public byte[] ReadBlock()
+ {
+ if (inputStream == null)
+ {
+ throw new TarException("TarBuffer.ReadBlock - no input stream defined");
+ }
+
+ if (currentBlockIndex >= BlockFactor)
+ {
+ if (!ReadRecord())
+ {
+ throw new TarException("Failed to read a record");
+ }
+ }
+
+ var result = new byte[BlockSize];
+
+ Array.Copy(recordBuffer, (currentBlockIndex*BlockSize), result, 0, BlockSize);
+ currentBlockIndex++;
+ return result;
+ }
+
+ /// <summary>
+ /// Read a record from data stream.
+ /// </summary>
+ /// <returns>
+ /// false if End-Of-File, else true.
+ /// </returns>
+ private bool ReadRecord()
+ {
+ if (inputStream == null)
+ {
+ throw new TarException("no input stream stream defined");
+ }
+
+ currentBlockIndex = 0;
+
+ var offset = 0;
+ var bytesNeeded = RecordSize;
+
+ while (bytesNeeded > 0)
+ {
+ long numBytes = inputStream.Read(recordBuffer, offset, bytesNeeded);
+
+ //
+ // NOTE
+ // We have found EOF, and the record is not full!
+ //
+ // This is a broken archive. It does not follow the standard
+ // blocking algorithm. However, because we are generous, and
+ // it requires little effort, we will simply ignore the error
+ // and continue as if the entire record were read. This does
+ // not appear to break anything upstream. We used to return
+ // false in this case.
+ //
+ // Thanks to 'Yohann.Roussel@alcatel.fr' for this fix.
+ //
+ if (numBytes <= 0)
+ {
+ break;
+ }
+
+ offset += (int) numBytes;
+ bytesNeeded -= (int) numBytes;
+ }
+
+ currentRecordIndex++;
+ return true;
+ }
+
+ /// <summary>
+ /// Get the current block number, within the current record, zero based.
+ /// </summary>
+ /// <returns>
+ /// The current zero based block number.
+ /// </returns>
+ /// <remarks>
+ /// The absolute block number = (<see cref="GetCurrentRecordNum">record number</see> * <see cref="BlockFactor">block factor</see>) + <see cref="GetCurrentBlockNum">block number</see>.
+ /// </remarks>
+ [Obsolete("Use CurrentBlock property instead")]
+ public int GetCurrentBlockNum()
+ {
+ return currentBlockIndex;
+ }
+
+ /// <summary>
+ /// Get the current record number.
+ /// </summary>
+ /// <returns>
+ /// The current zero based record number.
+ /// </returns>
+ [Obsolete("Use CurrentRecord property instead")]
+ public int GetCurrentRecordNum()
+ {
+ return currentRecordIndex;
+ }
+
+ /// <summary>
+ /// Write a block of data to the archive.
+ /// </summary>
+ /// <param name="block">
+ /// The data to write to the archive.
+ /// </param>
+ public void WriteBlock(byte[] block)
+ {
+ if (block == null)
+ {
+ throw new ArgumentNullException("block");
+ }
+
+ if (outputStream == null)
+ {
+ throw new TarException("TarBuffer.WriteBlock - no output stream defined");
+ }
+
+ if (block.Length != BlockSize)
+ {
+ var errorText =
+ string.Format(
+ "TarBuffer.WriteBlock - block to write has length '{0}' which is not the block size of '{1}'",
+ block.Length, BlockSize);
+ throw new TarException(errorText);
+ }
+
+ if (currentBlockIndex >= BlockFactor)
+ {
+ WriteRecord();
+ }
+
+ Array.Copy(block, 0, recordBuffer, (currentBlockIndex*BlockSize), BlockSize);
+ currentBlockIndex++;
+ }
+
+ /// <summary>
+ /// Write an archive record to the archive, where the record may be
+ /// inside of a larger array buffer. The buffer must be "offset plus
+ /// record size" long.
+ /// </summary>
+ /// <param name="buffer">
+ /// The buffer containing the record data to write.
+ /// </param>
+ /// <param name="offset">
+ /// The offset of the record data within buffer.
+ /// </param>
+ public void WriteBlock(byte[] buffer, int offset)
+ {
+ if (buffer == null)
+ {
+ throw new ArgumentNullException("buffer");
+ }
+
+ if (outputStream == null)
+ {
+ throw new TarException("TarBuffer.WriteBlock - no output stream stream defined");
+ }
+
+ if ((offset < 0) || (offset >= buffer.Length))
+ {
+ throw new ArgumentOutOfRangeException("offset");
+ }
+
+ if ((offset + BlockSize) > buffer.Length)
+ {
+ var errorText =
+ string.Format(
+ "TarBuffer.WriteBlock - record has length '{0}' with offset '{1}' which is less than the record size of '{2}'",
+ buffer.Length, offset, recordSize);
+ throw new TarException(errorText);
+ }
+
+ if (currentBlockIndex >= BlockFactor)
+ {
+ WriteRecord();
+ }
+
+ Array.Copy(buffer, offset, recordBuffer, (currentBlockIndex*BlockSize), BlockSize);
+
+ currentBlockIndex++;
+ }
+
+ /// <summary>
+ /// Write a TarBuffer record to the archive.
+ /// </summary>
+ private void WriteRecord()
+ {
+ if (outputStream == null)
+ {
+ throw new TarException("TarBuffer.WriteRecord no output stream defined");
+ }
+
+ outputStream.Write(recordBuffer, 0, RecordSize);
+ outputStream.Flush();
+
+ currentBlockIndex = 0;
+ currentRecordIndex++;
+ }
+
+ /// <summary>
+ /// Flush the current record if it has any data in it.
+ /// </summary>
+ private void Flush()
+ {
+ if (outputStream == null)
+ {
+ throw new TarException("TarBuffer.Flush no output stream defined");
+ }
+
+ if (currentBlockIndex > 0)
+ {
+ var dataBytes = currentBlockIndex*BlockSize;
+ Array.Clear(recordBuffer, dataBytes, RecordSize - dataBytes);
+ WriteRecord();
+ }
+
+ outputStream.Flush();
+ }
+
+ /// <summary>
+ /// Close the TarBuffer. If this is an output buffer, also flush the
+ /// current block before closing.
+ /// </summary>
+ public void Close()
+ {
+ if (outputStream != null)
+ {
+ Flush();
+
+ outputStream.Close();
+ outputStream = null;
+ }
+ else if (inputStream != null)
+ {
+ inputStream.Close();
+ inputStream = null;
+ }
+ }
+
+ #region Instance Fields
+
+ private int _blockFactor = DefaultBlockFactor;
+ private int currentBlockIndex;
+ private int currentRecordIndex;
+ private Stream inputStream;
+ private Stream outputStream;
+
+ private byte[] recordBuffer;
+
+ private int recordSize = DefaultRecordSize;
+
+ #endregion
+ }
+}
+
+/* The original Java file had this header:
+ *
+ ** Authored by Timothy Gerard Endres
+ ** <mailto:time@gjt.org> <http://www.trustice.com>
+ **
+ ** This work has been placed into the public domain.
+ ** You may use this work in any way and for any purpose you wish.
+ **
+ ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
+ ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
+ ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
+ ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
+ ** REDISTRIBUTION OF THIS SOFTWARE.
+ **
+ */
\ No newline at end of file
--- /dev/null
+// TarEntry.cs
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+using System.Linq;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Tar
+{
+ /// <summary>
+ /// This class represents an entry in a Tar archive. It consists
+ /// of the entry's _header, as well as the entry's File. Entries
+ /// can be instantiated in one of three ways, depending on how
+ /// they are to be used.
+ /// <p>
+ /// TarEntries that are created from the _header bytes read from
+ /// an archive are instantiated with the TarEntry( byte[] )
+ /// constructor. These entries will be used when extracting from
+ /// or listing the contents of an archive. These entries have their
+ /// _header filled in using the _header bytes. They also set the File
+ /// to null, since they reference an archive entry not a _file.</p>
+ /// <p>
+ /// TarEntries that are created from files that are to be written
+ /// into an archive are instantiated with the CreateEntryFromFile(string)
+ /// pseudo constructor. These entries have their _header filled in using
+ /// the File's information. They also keep a reference to the File
+ /// for convenience when writing entries.</p>
+ /// <p>
+ /// Finally, TarEntries can be constructed from nothing but a name.
+ /// This allows the programmer to construct the entry by hand, for
+ /// instance when only an InputStream is available for writing to
+ /// the archive, and the _header information is constructed from
+ /// other information. In this case the _header fields are set to
+ /// defaults and the File is set to null.</p>
+ /// <see cref="TarHeader"/>
+ /// </summary>
+ public class TarEntry
+ {
+ #region Constructors
+
+ /// <summary>
+ /// Initialise a default instance of <see cref="TarEntry"/>.
+ /// </summary>
+ private TarEntry()
+ {
+ _header = new TarHeader();
+ }
+
+ /// <summary>
+ /// Construct an entry from an archive's _header bytes. File is set
+ /// to null.
+ /// </summary>
+ /// <param name = "headerBuffer">
+ /// The _header bytes from a tar archive entry.
+ /// </param>
+ public TarEntry(byte[] headerBuffer)
+ {
+ _header = new TarHeader();
+ _header.ParseBuffer(headerBuffer);
+ }
+
+ /// <summary>
+ /// Construct a TarEntry using the <paramref name="header">_header</paramref> provided
+ /// </summary>
+ /// <param name="header">Header details for entry</param>
+ public TarEntry(TarHeader header)
+ {
+ if (header == null)
+ {
+ throw new ArgumentNullException("header");
+ }
+
+ _header = (TarHeader) header.Clone();
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Get this entry's _header.
+ /// </summary>
+ /// <returns>
+ /// This entry's TarHeader.
+ /// </returns>
+ public TarHeader TarHeader
+ {
+ get { return _header; }
+ }
+
+ /// <summary>
+ /// Get/Set this entry's name.
+ /// </summary>
+ public string Name
+ {
+ get { return _header.Name; }
+ set { _header.Name = value; }
+ }
+
+ /// <summary>
+ /// Get/set this entry's user id.
+ /// </summary>
+ public int UserId
+ {
+ get { return _header.UserId; }
+ set { _header.UserId = value; }
+ }
+
+ /// <summary>
+ /// Get/set this entry's group id.
+ /// </summary>
+ public int GroupId
+ {
+ get { return _header.GroupId; }
+ set { _header.GroupId = value; }
+ }
+
+ /// <summary>
+ /// Get/set this entry's user name.
+ /// </summary>
+ public string UserName
+ {
+ get { return _header.UserName; }
+ set { _header.UserName = value; }
+ }
+
+ /// <summary>
+ /// Get/set this entry's group name.
+ /// </summary>
+ public string GroupName
+ {
+ get { return _header.GroupName; }
+ set { _header.GroupName = value; }
+ }
+
+ /// <summary>
+ /// Get/Set the modification time for this entry
+ /// </summary>
+ public DateTime ModTime
+ {
+ get { return _header.ModTime; }
+ set { _header.ModTime = value; }
+ }
+
+ /// <summary>
+ /// Get this entry's _file.
+ /// </summary>
+ /// <returns>
+ /// This entry's _file.
+ /// </returns>
+ public string File
+ {
+ get { return _file; }
+ }
+
+ /// <summary>
+ /// Get/set this entry's recorded _file size.
+ /// </summary>
+ public long Size
+ {
+ get { return _header.Size; }
+ set { _header.Size = value; }
+ }
+
+ /// <summary>
+ /// Return true if this entry represents a directory, false otherwise
+ /// </summary>
+ /// <returns>
+ /// True if this entry is a directory.
+ /// </returns>
+ public bool IsDirectory
+ {
+ get
+ {
+ if (_file != null)
+ {
+ return Directory.Exists(_file);
+ }
+
+ if (_header != null)
+ {
+ if ((_header.TypeFlag == TarHeader.LF_DIR) || Name.EndsWith("/"))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Clone this tar entry.
+ /// </summary>
+ /// <returns>Returns a clone of this entry.</returns>
+ public object Clone()
+ {
+ var entry = new TarEntry{_file = _file, _header = ((TarHeader) _header.Clone()), Name = Name};
+ return entry;
+ }
+
+ /// <summary>
+ /// Construct an entry with only a <paramref name="name">name</paramref>.
+ /// This allows the programmer to construct the entry's _header "by hand".
+ /// </summary>
+ /// <param name="name">The name to use for the entry</param>
+ /// <returns>Returns the newly created <see cref="TarEntry"/></returns>
+ public static TarEntry CreateTarEntry(string name)
+ {
+ var entry = new TarEntry();
+ NameTarHeader(entry._header, name);
+ return entry;
+ }
+
+ /// <summary>
+ /// Construct an entry for a _file. File is set to _file, and the
+ /// _header is constructed from information from the _file.
+ /// </summary>
+ /// <param name = "fileName">The _file name that the entry represents.</param>
+ /// <returns>Returns the newly created <see cref="TarEntry"/></returns>
+ public static TarEntry CreateEntryFromFile(string fileName)
+ {
+ var entry = new TarEntry();
+ entry.GetFileTarHeader(entry._header, fileName);
+ return entry;
+ }
+
+ /// <summary>
+ /// Determine if the two entries are equal. Equality is determined
+ /// by the _header names being equal.
+ /// </summary>
+ /// <param name="obj">The <see cref="object"/> to compare with the current Object.</param>
+ /// <returns>
+ /// True if the entries are equal; false if not.
+ /// </returns>
+ public override bool Equals(object obj)
+ {
+ var localEntry = obj as TarEntry;
+
+ if (localEntry != null)
+ {
+ return Name.Equals(localEntry.Name);
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Derive a Hash value for the current <see cref="object"/>
+ /// </summary>
+ /// <returns>A Hash code for the current <see cref="object"/></returns>
+ public override int GetHashCode()
+ {
+ return Name.GetHashCode();
+ }
+
+ /// <summary>
+ /// Determine if the given entry is a descendant of this entry.
+ /// Descendancy is determined by the name of the descendant
+ /// starting with this entry's name.
+ /// </summary>
+ /// <param name = "toTest">
+ /// Entry to be checked as a descendent of this.
+ /// </param>
+ /// <returns>
+ /// True if entry is a descendant of this.
+ /// </returns>
+ public bool IsDescendent(TarEntry toTest)
+ {
+ if (toTest == null)
+ {
+ throw new ArgumentNullException("toTest");
+ }
+
+ return toTest.Name.StartsWith(Name);
+ }
+
+ /// <summary>
+ /// Convenience method to set this entry's group and user ids.
+ /// </summary>
+ /// <param name="userId">
+ /// This entry's new user id.
+ /// </param>
+ /// <param name="groupId">
+ /// This entry's new group id.
+ /// </param>
+ public void SetIds(int userId, int groupId)
+ {
+ UserId = userId;
+ GroupId = groupId;
+ }
+
+ /// <summary>
+ /// Convenience method to set this entry's group and user names.
+ /// </summary>
+ /// <param name="userName">
+ /// This entry's new user name.
+ /// </param>
+ /// <param name="groupName">
+ /// This entry's new group name.
+ /// </param>
+ public void SetNames(string userName, string groupName)
+ {
+ UserName = userName;
+ GroupName = groupName;
+ }
+
+ /// <summary>
+ /// Fill in a TarHeader with information from a File.
+ /// </summary>
+ /// <param name="header">
+ /// The TarHeader to fill in.
+ /// </param>
+ /// <param name="file">
+ /// The _file from which to get the _header information.
+ /// </param>
+ public void GetFileTarHeader(TarHeader header, string file)
+ {
+ if (header == null)
+ {
+ throw new ArgumentNullException("header");
+ }
+
+ if (file == null)
+ {
+ throw new ArgumentNullException("file");
+ }
+
+ _file = file;
+
+ // bugfix from torhovl from #D forum:
+ var name = file;
+
+ // 23-Jan-2004 GnuTar allows device names in path where the name is not local to the current directory
+ if (name.IndexOf(Environment.CurrentDirectory) == 0)
+ {
+ name = name.Substring(Environment.CurrentDirectory.Length);
+ }
+/*
+ if (Path.DirectorySeparatorChar == '\\')
+ {
+ // check if the OS is Windows
+ // Strip off drive letters!
+ if (name.Length > 2)
+ {
+ char ch1 = name[0];
+ char ch2 = name[1];
+
+ if (ch2 == ':' && Char.IsLetter(ch1))
+ {
+ name = name.Substring(2);
+ }
+ }
+ }
+*/
+
+ name = name.Replace(Path.DirectorySeparatorChar, '/');
+
+ // No absolute pathnames
+ // Windows (and Posix?) paths can start with UNC style "\\NetworkDrive\",
+ // so we loop on starting /'s.
+ while (name.StartsWith("/"))
+ {
+ name = name.Substring(1);
+ }
+
+ header.LinkName = String.Empty;
+ header.Name = name;
+
+ if (Directory.Exists(file))
+ {
+ header.Mode = 1003; // Magic number for security access for a UNIX filesystem
+ header.TypeFlag = TarHeader.LF_DIR;
+ if ((header.Name.Length == 0) || header.Name[header.Name.Length - 1] != '/')
+ {
+ header.Name = header.Name + "/";
+ }
+
+ header.Size = 0;
+ }
+ else
+ {
+ header.Mode = 33216; // Magic number for security access for a UNIX filesystem
+ header.TypeFlag = TarHeader.LF_NORMAL;
+ header.Size = new FileInfo(file.Replace('/', Path.DirectorySeparatorChar)).Length;
+ }
+
+ header.ModTime =
+ System.IO.File.GetLastWriteTime(file.Replace('/', Path.DirectorySeparatorChar)).ToUniversalTime();
+ header.DevMajor = 0;
+ header.DevMinor = 0;
+ }
+
+ /// <summary>
+ /// Get entries for all files present in this entries directory.
+ /// If this entry doesnt represent a directory zero entries are returned.
+ /// </summary>
+ /// <returns>
+ /// An array of TarEntry's for this entry's children.
+ /// </returns>
+ public TarEntry[] GetDirectoryEntries()
+ {
+ if ((_file == null) || !Directory.Exists(_file))
+ {
+ return new TarEntry[0];
+ }
+
+#if !SL4
+ var list = Directory.GetFileSystemEntries(_file);
+#else
+ var list = Directory.EnumerateFileSystemEntries(_file).ToArray();
+#endif
+ var result = new TarEntry[list.Length];
+
+ for (var i = 0; i < list.Length; ++i)
+ {
+ result[i] = CreateEntryFromFile(list[i]);
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Write an entry's _header information to a _header buffer.
+ /// </summary>
+ /// <param name = "outBuffer">
+ /// The tar entry _header buffer to fill in.
+ /// </param>
+ public void WriteEntryHeader(byte[] outBuffer)
+ {
+ _header.WriteHeader(outBuffer);
+ }
+
+ /// <summary>
+ /// Convenience method that will modify an entry's name directly
+ /// in place in an entry _header buffer byte array.
+ /// </summary>
+ /// <param name="buffer">
+ /// The buffer containing the entry _header to modify.
+ /// </param>
+ /// <param name="newName">
+ /// The new name to place into the _header buffer.
+ /// </param>
+ public static void AdjustEntryName(byte[] buffer, string newName)
+ {
+ var offset = 0;
+ TarHeader.GetNameBytes(newName, buffer, offset, TarHeader.NAMELEN);
+ }
+
+ /// <summary>
+ /// Fill in a TarHeader given only the entry's name.
+ /// </summary>
+ /// <param name="header">
+ /// The TarHeader to fill in.
+ /// </param>
+ /// <param name="name">
+ /// The tar entry name.
+ /// </param>
+ public static void NameTarHeader(TarHeader header, string name)
+ {
+ if (header == null)
+ {
+ throw new ArgumentNullException("header");
+ }
+
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+
+ var isDir = name.EndsWith("/");
+
+ header.Name = name;
+ header.Mode = isDir ? 1003 : 33216;
+ header.UserId = 0;
+ header.GroupId = 0;
+ header.Size = 0;
+
+ header.ModTime = DateTime.UtcNow;
+
+ header.TypeFlag = isDir ? TarHeader.LF_DIR : TarHeader.LF_NORMAL;
+
+ header.LinkName = String.Empty;
+ header.UserName = String.Empty;
+ header.GroupName = String.Empty;
+
+ header.DevMajor = 0;
+ header.DevMinor = 0;
+ }
+
+ #region Instance Fields
+
+ /// <summary>
+ /// The name of the _file this entry represents or null if the entry is not based on a _file.
+ /// </summary>
+ private string _file;
+
+ /// <summary>
+ /// The entry's _header information.
+ /// </summary>
+ private TarHeader _header;
+
+ #endregion
+ }
+}
+
+/* The original Java file had this header:
+ *
+ ** Authored by Timothy Gerard Endres
+ ** <mailto:time@gjt.org> <http://www.trustice.com>
+ **
+ ** This work has been placed into the public domain.
+ ** You may use this work in any way and for any purpose you wish.
+ **
+ ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
+ ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
+ ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
+ ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
+ ** REDISTRIBUTION OF THIS SOFTWARE.
+ **
+ */
\ No newline at end of file
--- /dev/null
+// TarException.cs
+//
+// Copyright 2004 John Reilly
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using ICSharpCode.SharpZipLib.Silverlight.Serialization;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Tar
+{
+ /// <summary>
+ /// TarExceptions are used for exceptions specific to tar classes and code.
+ /// </summary>
+ [Serializable]
+ public class TarException : SharpZipBaseException
+ {
+ /// <summary>
+ /// Deserialization constructor
+ /// </summary>
+ /// <param name="info"><see cref="System.Runtime.Serialization.SerializationInfo"/> for this constructor</param>
+ protected TarException(SerializationInfo info)
+ : base(info)
+ {
+
+ }
+
+ /// <summary>
+ /// Initialises a new instance of the TarException class.
+ /// </summary>
+ public TarException()
+ {
+
+ }
+
+ /// <summary>
+ /// Initialises a new instance of the TarException class with a specified message.
+ /// </summary>
+ /// <param name="message">The message that describes the error.</param>
+ public TarException(string message)
+ : base(message)
+ {
+
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="message">A message describing the error.</param>
+ /// <param name="exception">The exception that is the cause of the current exception.</param>
+ public TarException(string message, Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// TarHeader.cs
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+
+/* The tar format and its POSIX successor PAX have a long history which makes for compatability
+ issues when creating and reading files.
+
+ This is further complicated by a large number of programs with variations on formats
+ One common issue is the handling of names longer than 100 characters.
+ GNU style long names are currently supported.
+
+This is the ustar (Posix 1003.1) header.
+
+struct header
+{
+ char t_name[100]; // 0 Filename
+ char t_mode[8]; // 100 Permissions
+ char t_uid[8]; // 108 Numerical User ID
+ char t_gid[8]; // 116 Numerical Group ID
+ char t_size[12]; // 124 Filesize
+ char t_mtime[12]; // 136 st_mtime
+ char t_chksum[8]; // 148 Checksum
+ char t_typeflag; // 156 Type of File
+ char t_linkname[100]; // 157 Target of Links
+ char t_magic[6]; // 257 "ustar" or other...
+ char t_version[2]; // 263 Version fixed to 00
+ char t_uname[32]; // 265 User Name
+ char t_gname[32]; // 297 Group Name
+ char t_devmajor[8]; // 329 Major for devices
+ char t_devminor[8]; // 337 Minor for devices
+ char t_prefix[155]; // 345 Prefix for t_name
+ char t_mfill[12]; // 500 Filler up to 512
+};
+
+*/
+
+using System;
+using System.Text;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Tar
+{
+ /// <summary>
+ /// This class encapsulates the Tar Entry Header used in Tar Archives.
+ /// The class also holds a number of tar constants, used mostly in headers.
+ /// </summary>
+ public class TarHeader
+ {
+ #region Constants
+
+ /// <summary>
+ /// The length of the checksum field in a header buffer.
+ /// </summary>
+ public const int CHKSUMLEN = 8;
+
+ /// <summary>
+ /// Offset of checksum in a header buffer.
+ /// </summary>
+ public const int CHKSUMOFS = 148;
+
+ /// <summary>
+ /// The length of the devices field in a header buffer.
+ /// </summary>
+ public const int DEVLEN = 8;
+
+ /// <summary>
+ /// The length of the group id field in a header buffer.
+ /// </summary>
+ public const int GIDLEN = 8;
+
+ /// <summary>
+ /// The length of the group name field in a header buffer.
+ /// </summary>
+ public const int GNAMELEN = 32;
+
+ /// <summary>
+ /// The magic tag representing an old GNU tar archive where version is included in magic and overwrites it
+ /// </summary>
+ public const string GNU_TMAGIC = "ustar ";
+
+ /// <summary>
+ /// Solaris access control list file type
+ /// </summary>
+ public const byte LF_ACL = (byte) 'A';
+
+ //
+ // LF_ constants represent the "type" of an entry
+ //
+
+ /// <summary>
+ /// Block device file type.
+ /// </summary>
+ public const byte LF_BLK = (byte) '4';
+
+ /// <summary>
+ /// Character device file type.
+ /// </summary>
+ public const byte LF_CHR = (byte) '3';
+
+ /// <summary>
+ /// Contiguous file type.
+ /// </summary>
+ public const byte LF_CONTIG = (byte) '7';
+
+ /// <summary>
+ /// Directory file type.
+ /// </summary>
+ public const byte LF_DIR = (byte) '5';
+
+ /// <summary>
+ /// Solaris Extended Attribute File
+ /// </summary>
+ public const byte LF_EXTATTR = (byte) 'E';
+
+ /// <summary>
+ /// FIFO (pipe) file type.
+ /// </summary>
+ public const byte LF_FIFO = (byte) '6';
+
+ /// <summary>
+ /// Posix.1 2001 global extended header
+ /// </summary>
+ public const byte LF_GHDR = (byte) 'g';
+
+ /// <summary>
+ /// GNU dir dump file type
+ /// This is a dir entry that contains the names of files that were in the
+ /// dir at the time the dump was made
+ /// </summary>
+ public const byte LF_GNU_DUMPDIR = (byte) 'D';
+
+ /// <summary>
+ /// Identifies the next file on the tape as having a long link name
+ /// </summary>
+ public const byte LF_GNU_LONGLINK = (byte) 'K';
+
+ /// <summary>
+ /// Identifies the next file on the tape as having a long name
+ /// </summary>
+ public const byte LF_GNU_LONGNAME = (byte) 'L';
+
+ /// <summary>
+ /// Continuation of a file that began on another volume
+ /// </summary>
+ public const byte LF_GNU_MULTIVOL = (byte) 'M';
+
+ /// <summary>
+ /// For storing filenames that dont fit in the main header (old GNU)
+ /// </summary>
+ public const byte LF_GNU_NAMES = (byte) 'N';
+
+ /// <summary>
+ /// GNU Sparse file
+ /// </summary>
+ public const byte LF_GNU_SPARSE = (byte) 'S';
+
+ /// <summary>
+ /// GNU Tape/volume header ignore on extraction
+ /// </summary>
+ public const byte LF_GNU_VOLHDR = (byte) 'V';
+
+ /// <summary>
+ /// Link file type.
+ /// </summary>
+ public const byte LF_LINK = (byte) '1';
+
+ /// <summary>
+ /// Inode (metadata only) no file content
+ /// </summary>
+ public const byte LF_META = (byte) 'I';
+
+ /// <summary>
+ /// Normal file type.
+ /// </summary>
+ public const byte LF_NORMAL = (byte) '0';
+
+ /// <summary>
+ /// The "old way" of indicating a normal file.
+ /// </summary>
+ public const byte LF_OLDNORM = 0;
+
+ /// <summary>
+ /// Symbolic link file type.
+ /// </summary>
+ public const byte LF_SYMLINK = (byte) '2';
+
+ /// <summary>
+ /// Posix.1 2001 extended header
+ /// </summary>
+ public const byte LF_XHDR = (byte) 'x';
+
+ /// <summary>
+ /// The length of the magic field in a header buffer.
+ /// </summary>
+ public const int MAGICLEN = 6;
+
+ /// <summary>
+ /// The length of the mode field in a header buffer.
+ /// </summary>
+ public const int MODELEN = 8;
+
+ /// <summary>
+ /// The length of the modification time field in a header buffer.
+ /// </summary>
+ public const int MODTIMELEN = 12;
+
+ /// <summary>
+ /// The length of the name field in a header buffer.
+ /// </summary>
+ public const int NAMELEN = 100;
+
+ /// <summary>
+ /// The length of the size field in a header buffer.
+ /// </summary>
+ public const int SIZELEN = 12;
+
+ private const long timeConversionFactor = 10000000L; // 1 tick == 100 nanoseconds
+
+ /// <summary>
+ /// The magic tag representing a POSIX tar archive. (includes trailing NULL)
+ /// </summary>
+ public const string TMAGIC = "ustar ";
+
+ /// <summary>
+ /// The length of the user id field in a header buffer.
+ /// </summary>
+ public const int UIDLEN = 8;
+
+ /// <summary>
+ /// The length of the user name field in a header buffer.
+ /// </summary>
+ public const int UNAMELEN = 32;
+
+ /// <summary>
+ /// The length of the version field in a header buffer.
+ /// </summary>
+ public const int VERSIONLEN = 2;
+
+ private static readonly DateTime dateTime1970 = new DateTime(1970, 1, 1, 0, 0, 0, 0);
+
+ #endregion
+
+ #region Constructors
+
+ /// <summary>
+ /// Initialise a default TarHeader instance
+ /// </summary>
+ public TarHeader()
+ {
+ Magic = TMAGIC;
+ Version = " ";
+
+ Name = "";
+ LinkName = "";
+
+ UserId = defaultUserId;
+ GroupId = defaultGroupId;
+ UserName = defaultUser;
+ GroupName = defaultGroupName;
+ Size = 0;
+ }
+
+ #endregion
+
+ #region Properties
+
+ /// <summary>
+ /// Get/set the name for this tar entry.
+ /// </summary>
+ /// <exception cref="ArgumentNullException">Thrown when attempting to set the property to null.</exception>
+ public string Name
+ {
+ get { return name; }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("value");
+ }
+ name = value;
+ }
+ }
+
+ /// <summary>
+ /// Get/set the entry's Unix style permission mode.
+ /// </summary>
+ public int Mode
+ {
+ get { return mode; }
+ set { mode = value; }
+ }
+
+
+ /// <summary>
+ /// The entry's user id.
+ /// </summary>
+ /// <remarks>
+ /// This is only directly relevant to unix systems.
+ /// The default is zero.
+ /// </remarks>
+ public int UserId { get; set; }
+
+
+ /// <summary>
+ /// Get/set the entry's group id.
+ /// </summary>
+ /// <remarks>
+ /// This is only directly relevant to linux/unix systems.
+ /// The default value is zero.
+ /// </remarks>
+ public int GroupId { get; set; }
+
+
+ /// <summary>
+ /// Get/set the entry's size.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">Thrown when setting the size to less than zero.</exception>
+ public long Size
+ {
+ get { return _size; }
+ set
+ {
+ if (value < 0)
+ {
+ throw new ArgumentOutOfRangeException("value", "Cannot be less than zero");
+ }
+ _size = value;
+ }
+ }
+
+
+ /// <summary>
+ /// Get/set the entry's modification time.
+ /// </summary>
+ /// <remarks>
+ /// The modification time is only accurate to within a second.
+ /// </remarks>
+ /// <exception cref="ArgumentOutOfRangeException">Thrown when setting the date time to less than 1/1/1970.</exception>
+ public DateTime ModTime
+ {
+ get { return modTime; }
+ set
+ {
+ if (value < dateTime1970)
+ {
+ throw new ArgumentOutOfRangeException("value", "ModTime cannot be before Jan 1st 1970");
+ }
+ modTime = new DateTime(value.Year, value.Month, value.Day, value.Hour, value.Minute, value.Second);
+ }
+ }
+
+
+ /// <summary>
+ /// Get the entry's checksum. This is only valid/updated after writing or reading an entry.
+ /// </summary>
+ public int Checksum { get; private set; }
+
+ /// <summary>
+ /// Get value of true if the header checksum is valid, false otherwise.
+ /// </summary>
+ public bool IsChecksumValid { get; private set; }
+
+ /// <summary>
+ /// Get/set the entry's type flag.
+ /// </summary>
+ public byte TypeFlag { get; set; }
+
+ /// <summary>
+ /// The entry's link name.
+ /// </summary>
+ /// <exception cref="ArgumentNullException">Thrown when attempting to set LinkName to null.</exception>
+ public string LinkName
+ {
+ get { return linkName; }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("value");
+ }
+ linkName = value;
+ }
+ }
+
+
+ /// <summary>
+ /// Get/set the entry's magic tag.
+ /// </summary>
+ /// <exception cref="ArgumentNullException">Thrown when attempting to set Magic to null.</exception>
+ public string Magic
+ {
+ get { return magic; }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("value");
+ }
+ magic = value;
+ }
+ }
+
+
+ /// <summary>
+ /// The entry's version.
+ /// </summary>
+ /// <exception cref="ArgumentNullException">Thrown when attempting to set Version to null.</exception>
+ public string Version
+ {
+ get { return version; }
+
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("value");
+ }
+ version = value;
+ }
+ }
+
+
+ /// <summary>
+ /// The entry's user name.
+ /// </summary>
+ public string UserName
+ {
+ get { return userName; }
+ set
+ {
+ if (value != null)
+ {
+ userName = value.Substring(0, Math.Min(UNAMELEN, value.Length));
+ }
+ else
+ {
+ var currentUser = "Silverlight"; //Environment.UserName;
+ if (currentUser.Length > UNAMELEN)
+ {
+ currentUser = currentUser.Substring(0, UNAMELEN);
+ }
+ userName = currentUser;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Get/set the entry's group name.
+ /// </summary>
+ /// <remarks>
+ /// This is only directly relevant to unix systems.
+ /// </remarks>
+ public string GroupName
+ {
+ get { return groupName; }
+ set
+ {
+ groupName = value ?? "None";
+ }
+ }
+
+
+ /// <summary>
+ /// Get/set the entry's major device number.
+ /// </summary>
+ public int DevMajor { get; set; }
+
+
+ /// <summary>
+ /// Get/set the entry's minor device number.
+ /// </summary>
+ public int DevMinor { get; set; }
+
+ /// <summary>
+ /// Get the name of this entry.
+ /// </summary>
+ /// <returns>The entry's name.</returns>
+ [Obsolete("Use the Name property instead", true)]
+ public string GetName()
+ {
+ return name;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Create a new <see cref="TarHeader"/> that is a copy of the current instance.
+ /// </summary>
+ /// <returns>A new <see cref="Object"/> that is a copy of the current instance.</returns>
+ public object Clone()
+ {
+ return MemberwiseClone();
+ }
+
+ /// <summary>
+ /// Parse TarHeader information from a header buffer.
+ /// </summary>
+ /// <param name = "header">
+ /// The tar entry header buffer to get information from.
+ /// </param>
+ public void ParseBuffer(byte[] header)
+ {
+ if (header == null)
+ {
+ throw new ArgumentNullException("header");
+ }
+
+ var offset = 0;
+
+ name = ParseName(header, offset, NAMELEN).ToString();
+ offset += NAMELEN;
+
+ mode = (int) ParseOctal(header, offset, MODELEN);
+ offset += MODELEN;
+
+ UserId = (int) ParseOctal(header, offset, UIDLEN);
+ offset += UIDLEN;
+
+ GroupId = (int) ParseOctal(header, offset, GIDLEN);
+ offset += GIDLEN;
+
+ Size = ParseOctal(header, offset, SIZELEN);
+ offset += SIZELEN;
+
+ ModTime = GetDateTimeFromCTime(ParseOctal(header, offset, MODTIMELEN));
+ offset += MODTIMELEN;
+
+ Checksum = (int) ParseOctal(header, offset, CHKSUMLEN);
+ offset += CHKSUMLEN;
+
+ TypeFlag = header[offset++];
+
+ LinkName = ParseName(header, offset, NAMELEN).ToString();
+ offset += NAMELEN;
+
+ Magic = ParseName(header, offset, MAGICLEN).ToString();
+ offset += MAGICLEN;
+
+ Version = ParseName(header, offset, VERSIONLEN).ToString();
+ offset += VERSIONLEN;
+
+ UserName = ParseName(header, offset, UNAMELEN).ToString();
+ offset += UNAMELEN;
+
+ GroupName = ParseName(header, offset, GNAMELEN).ToString();
+ offset += GNAMELEN;
+
+ DevMajor = (int) ParseOctal(header, offset, DEVLEN);
+ offset += DEVLEN;
+
+ DevMinor = (int) ParseOctal(header, offset, DEVLEN);
+
+ // Fields past this point not currently parsed or used...
+
+ IsChecksumValid = Checksum == MakeCheckSum(header);
+ }
+
+ /// <summary>
+ /// 'Write' header information to buffer provided, updating the <see cref="Checksum">check sum</see>.
+ /// </summary>
+ /// <param name="outBuffer">output buffer for header information</param>
+ public void WriteHeader(byte[] outBuffer)
+ {
+ if (outBuffer == null)
+ {
+ throw new ArgumentNullException("outBuffer");
+ }
+
+ var offset = 0;
+
+ offset = GetNameBytes(Name, outBuffer, offset, NAMELEN);
+ offset = GetOctalBytes(mode, outBuffer, offset, MODELEN);
+ offset = GetOctalBytes(UserId, outBuffer, offset, UIDLEN);
+ offset = GetOctalBytes(GroupId, outBuffer, offset, GIDLEN);
+
+ var size = Size;
+
+ offset = GetLongOctalBytes(size, outBuffer, offset, SIZELEN);
+ offset = GetLongOctalBytes(GetCTime(ModTime), outBuffer, offset, MODTIMELEN);
+
+ var csOffset = offset;
+ for (var c = 0; c < CHKSUMLEN; ++c)
+ {
+ outBuffer[offset++] = (byte) ' ';
+ }
+
+ outBuffer[offset++] = TypeFlag;
+
+ offset = GetNameBytes(LinkName, outBuffer, offset, NAMELEN);
+ offset = GetAsciiBytes(Magic, 0, outBuffer, offset, MAGICLEN);
+ offset = GetNameBytes(Version, outBuffer, offset, VERSIONLEN);
+ offset = GetNameBytes(UserName, outBuffer, offset, UNAMELEN);
+ offset = GetNameBytes(GroupName, outBuffer, offset, GNAMELEN);
+
+ if (TypeFlag == LF_CHR || TypeFlag == LF_BLK)
+ {
+ offset = GetOctalBytes(DevMajor, outBuffer, offset, DEVLEN);
+ offset = GetOctalBytes(DevMinor, outBuffer, offset, DEVLEN);
+ }
+
+ for (; offset < outBuffer.Length;)
+ {
+ outBuffer[offset++] = 0;
+ }
+
+ Checksum = ComputeCheckSum(outBuffer);
+
+ GetCheckSumOctalBytes(Checksum, outBuffer, csOffset, CHKSUMLEN);
+ IsChecksumValid = true;
+ }
+
+ /// <summary>
+ /// Get a hash code for the current object.
+ /// </summary>
+ /// <returns>A hash code for the current object.</returns>
+ public override int GetHashCode()
+ {
+ return Name.GetHashCode();
+ }
+
+ /// <summary>
+ /// Determines if this instance is equal to the specified object.
+ /// </summary>
+ /// <param name="obj">The object to compare with.</param>
+ /// <returns>true if the objects are equal, false otherwise.</returns>
+ public override bool Equals(object obj)
+ {
+ var localHeader = obj as TarHeader;
+
+ if (localHeader != null)
+ {
+ return name == localHeader.name
+ && mode == localHeader.mode
+ && UserId == localHeader.UserId
+ && GroupId == localHeader.GroupId
+ && Size == localHeader.Size
+ && ModTime == localHeader.ModTime
+ && Checksum == localHeader.Checksum
+ && TypeFlag == localHeader.TypeFlag
+ && LinkName == localHeader.LinkName
+ && Magic == localHeader.Magic
+ && Version == localHeader.Version
+ && UserName == localHeader.UserName
+ && GroupName == localHeader.GroupName
+ && DevMajor == localHeader.DevMajor
+ && DevMinor == localHeader.DevMinor;
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Set defaults for values used when constructing a TarHeader instance.
+ /// </summary>
+ /// <param name="userId">Value to apply as a default for userId.</param>
+ /// <param name="userName">Value to apply as a default for userName.</param>
+ /// <param name="groupId">Value to apply as a default for groupId.</param>
+ /// <param name="groupName">Value to apply as a default for groupName.</param>
+ internal static void SetValueDefaults(int userId, string userName, int groupId, string groupName)
+ {
+ defaultUserId = userIdAsSet = userId;
+ defaultUser = userNameAsSet = userName;
+ defaultGroupId = groupIdAsSet = groupId;
+ defaultGroupName = groupNameAsSet = groupName;
+ }
+
+ internal static void RestoreSetValues()
+ {
+ defaultUserId = userIdAsSet;
+ defaultUser = userNameAsSet;
+ defaultGroupId = groupIdAsSet;
+ defaultGroupName = groupNameAsSet;
+ }
+
+ /// <summary>
+ /// Parse an octal string from a header buffer.
+ /// </summary>
+ /// <param name = "header">The header buffer from which to parse.</param>
+ /// <param name = "offset">The offset into the buffer from which to parse.</param>
+ /// <param name = "length">The number of header bytes to parse.</param>
+ /// <returns>The long equivalent of the octal string.</returns>
+ public static long ParseOctal(byte[] header, int offset, int length)
+ {
+ if (header == null)
+ {
+ throw new NullReferenceException("header");
+ }
+
+ long result = 0;
+ var stillPadding = true;
+
+ var end = offset + length;
+ for (var i = offset; i < end; ++i)
+ {
+ if (header[i] == 0)
+ {
+ break;
+ }
+
+ if (header[i] == (byte) ' ' || header[i] == '0')
+ {
+ if (stillPadding)
+ {
+ continue;
+ }
+
+ if (header[i] == (byte) ' ')
+ {
+ break;
+ }
+ }
+
+ stillPadding = false;
+
+ result = (result << 3) + (header[i] - '0');
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Parse a name from a header buffer.
+ /// </summary>
+ /// <param name="header">
+ /// The header buffer from which to parse.
+ /// </param>
+ /// <param name="offset">
+ /// The offset into the buffer from which to parse.
+ /// </param>
+ /// <param name="length">
+ /// The number of header bytes to parse.
+ /// </param>
+ /// <returns>
+ /// The name parsed.
+ /// </returns>
+ public static StringBuilder ParseName(byte[] header, int offset, int length)
+ {
+ if (header == null)
+ {
+ throw new ArgumentNullException("header");
+ }
+
+ if (offset < 0)
+ {
+ throw new ArgumentOutOfRangeException("offset", "Cannot be less than zero");
+ }
+
+ if (length < 0)
+ {
+ throw new ArgumentOutOfRangeException("length", "Cannot be less than zero");
+ }
+
+ if (offset + length > header.Length)
+ {
+ throw new ArgumentException("Exceeds header size", "length");
+ }
+
+ var result = new StringBuilder(length);
+
+ for (var i = offset; i < offset + length; ++i)
+ {
+ if (header[i] == 0)
+ {
+ break;
+ }
+ result.Append((char) header[i]);
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Add <paramref name="name">name</paramref> to the buffer as a collection of bytes
+ /// </summary>
+ /// <param name="name">The name to add</param>
+ /// <param name="nameOffset">The offset of the first character</param>
+ /// <param name="buffer">The buffer to add to</param>
+ /// <param name="bufferOffset">The index of the first byte to add</param>
+ /// <param name="length">The number of characters/bytes to add</param>
+ /// <returns>The next free index in the <paramref name="buffer">buffer</paramref></returns>
+ public static int GetNameBytes(StringBuilder name, int nameOffset, byte[] buffer, int bufferOffset, int length)
+ {
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+
+ if (buffer == null)
+ {
+ throw new ArgumentNullException("buffer");
+ }
+
+ return GetNameBytes(name.ToString(), nameOffset, buffer, bufferOffset, length);
+ }
+
+ /// <summary>
+ /// Add <paramref name="name">name</paramref> to the buffer as a collection of bytes
+ /// </summary>
+ /// <param name="name">The name to add</param>
+ /// <param name="nameOffset">The offset of the first character</param>
+ /// <param name="buffer">The buffer to add to</param>
+ /// <param name="bufferOffset">The index of the first byte to add</param>
+ /// <param name="length">The number of characters/bytes to add</param>
+ /// <returns>The next free index in the <paramref name="buffer">buffer</paramref></returns>
+ public static int GetNameBytes(string name, int nameOffset, byte[] buffer, int bufferOffset, int length)
+ {
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+
+ if (buffer == null)
+ {
+ throw new ArgumentNullException("buffer");
+ }
+
+ int i;
+
+ for (i = 0; i < length - 1 && nameOffset + i < name.Length; ++i)
+ {
+ buffer[bufferOffset + i] = (byte) name[nameOffset + i];
+ }
+
+ for (; i < length; ++i)
+ {
+ buffer[bufferOffset + i] = 0;
+ }
+
+ return bufferOffset + length;
+ }
+
+ /// <summary>
+ /// Add an entry name to the buffer
+ /// </summary>
+ /// <param name="name">
+ /// The name to add
+ /// </param>
+ /// <param name="buffer">
+ /// The buffer to add to
+ /// </param>
+ /// <param name="offset">
+ /// The offset into the buffer from which to start adding
+ /// </param>
+ /// <param name="length">
+ /// The number of header bytes to add
+ /// </param>
+ /// <returns>
+ /// The index of the next free byte in the buffer
+ /// </returns>
+ public static int GetNameBytes(StringBuilder name, byte[] buffer, int offset, int length)
+ {
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+
+ if (buffer == null)
+ {
+ throw new ArgumentNullException("buffer");
+ }
+
+ return GetNameBytes(name.ToString(), 0, buffer, offset, length);
+ }
+
+ /// <summary>
+ /// Add an entry name to the buffer
+ /// </summary>
+ /// <param name="name">The name to add</param>
+ /// <param name="buffer">The buffer to add to</param>
+ /// <param name="offset">The offset into the buffer from which to start adding</param>
+ /// <param name="length">The number of header bytes to add</param>
+ /// <returns>The index of the next free byte in the buffer</returns>
+ public static int GetNameBytes(string name, byte[] buffer, int offset, int length)
+ {
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+
+ if (buffer == null)
+ {
+ throw new ArgumentNullException("buffer");
+ }
+
+ return GetNameBytes(name, 0, buffer, offset, length);
+ }
+
+ /// <summary>
+ /// Add a string to a buffer as a collection of ascii bytes.
+ /// </summary>
+ /// <param name="toAdd">The string to add</param>
+ /// <param name="nameOffset">The offset of the first character to add.</param>
+ /// <param name="buffer">The buffer to add to.</param>
+ /// <param name="bufferOffset">The offset to start adding at.</param>
+ /// <param name="length">The number of ascii characters to add.</param>
+ /// <returns>The next free index in the buffer.</returns>
+ public static int GetAsciiBytes(string toAdd, int nameOffset, byte[] buffer, int bufferOffset, int length)
+ {
+ if (toAdd == null)
+ {
+ throw new ArgumentNullException("toAdd");
+ }
+
+ if (buffer == null)
+ {
+ throw new ArgumentNullException("buffer");
+ }
+
+ for (var i = 0; i < length && nameOffset + i < toAdd.Length; ++i)
+ {
+ buffer[bufferOffset + i] = (byte) toAdd[nameOffset + i];
+ }
+ return bufferOffset + length;
+ }
+
+ /// <summary>
+ /// Put an octal representation of a value into a buffer
+ /// </summary>
+ /// <param name = "value">
+ /// the value to be converted to octal
+ /// </param>
+ /// <param name = "buffer">
+ /// buffer to store the octal string
+ /// </param>
+ /// <param name = "offset">
+ /// The offset into the buffer where the value starts
+ /// </param>
+ /// <param name = "length">
+ /// The length of the octal string to create
+ /// </param>
+ /// <returns>
+ /// The offset of the character next byte after the octal string
+ /// </returns>
+ public static int GetOctalBytes(long value, byte[] buffer, int offset, int length)
+ {
+ if (buffer == null)
+ {
+ throw new ArgumentNullException("buffer");
+ }
+
+ var localIndex = length - 1;
+
+ // Either a space or null is valid here. We use NULL as per GNUTar
+ buffer[offset + localIndex] = 0;
+ --localIndex;
+
+ if (value > 0)
+ {
+ for (var v = value; (localIndex >= 0) && (v > 0); --localIndex)
+ {
+ buffer[offset + localIndex] = (byte) ((byte) '0' + (byte) (v & 7));
+ v >>= 3;
+ }
+ }
+
+ for (; localIndex >= 0; --localIndex)
+ {
+ buffer[offset + localIndex] = (byte) '0';
+ }
+
+ return offset + length;
+ }
+
+ /// <summary>
+ /// Put an octal representation of a value into a buffer
+ /// </summary>
+ /// <param name = "value">Value to be convert to octal</param>
+ /// <param name = "buffer">The buffer to update</param>
+ /// <param name = "offset">The offset into the buffer to store the value</param>
+ /// <param name = "length">The length of the octal string</param>
+ /// <returns>Index of next byte</returns>
+ public static int GetLongOctalBytes(long value, byte[] buffer, int offset, int length)
+ {
+ return GetOctalBytes(value, buffer, offset, length);
+ }
+
+ /// <summary>
+ /// Add the checksum integer to header buffer.
+ /// </summary>
+ /// <param name = "value"></param>
+ /// <param name = "buffer">The header buffer to set the checksum for</param>
+ /// <param name = "offset">The offset into the buffer for the checksum</param>
+ /// <param name = "length">The number of header bytes to update.
+ /// It's formatted differently from the other fields: it has 6 digits, a
+ /// null, then a space -- rather than digits, a space, then a null.
+ /// The final space is already there, from checksumming
+ /// </param>
+ /// <returns>The modified buffer offset</returns>
+ private static int GetCheckSumOctalBytes(long value, byte[] buffer, int offset, int length)
+ {
+ GetOctalBytes(value, buffer, offset, length - 1);
+ return offset + length;
+ }
+
+ /// <summary>
+ /// Compute the checksum for a tar entry header.
+ /// The checksum field must be all spaces prior to this happening
+ /// </summary>
+ /// <param name = "buffer">The tar entry's header buffer.</param>
+ /// <returns>The computed checksum.</returns>
+ private static int ComputeCheckSum(byte[] buffer)
+ {
+ var sum = 0;
+ for (var i = 0; i < buffer.Length; ++i)
+ {
+ sum += buffer[i];
+ }
+ return sum;
+ }
+
+ /// <summary>
+ /// Make a checksum for a tar entry ignoring the checksum contents.
+ /// </summary>
+ /// <param name = "buffer">The tar entry's header buffer.</param>
+ /// <returns>The checksum for the buffer</returns>
+ private static int MakeCheckSum(byte[] buffer)
+ {
+ var sum = 0;
+ for (var i = 0; i < CHKSUMOFS; ++i)
+ {
+ sum += buffer[i];
+ }
+
+ for (var i = 0; i < CHKSUMLEN; ++i)
+ {
+ sum += (byte) ' ';
+ }
+
+ for (var i = CHKSUMOFS + CHKSUMLEN; i < buffer.Length; ++i)
+ {
+ sum += buffer[i];
+ }
+ return sum;
+ }
+
+ private static int GetCTime(DateTime dateTime)
+ {
+ return unchecked((int) ((dateTime.Ticks - dateTime1970.Ticks)/timeConversionFactor));
+ }
+
+ private static DateTime GetDateTimeFromCTime(long ticks)
+ {
+ DateTime result;
+
+ try
+ {
+ result = new DateTime(dateTime1970.Ticks + ticks*timeConversionFactor);
+ }
+ catch (ArgumentOutOfRangeException)
+ {
+ result = dateTime1970;
+ }
+ return result;
+ }
+
+ #region Instance Fields
+
+ private string groupName;
+ private string linkName;
+ private string magic;
+ private int mode;
+ private DateTime modTime;
+ private string name;
+ private long _size;
+ private string userName;
+ private string version;
+
+ #endregion
+
+ #region Class Fields
+
+ // Values used during recursive operations.
+ internal static int defaultGroupId;
+ internal static string defaultGroupName = "None";
+ internal static string defaultUser;
+ internal static int defaultUserId;
+ internal static int groupIdAsSet;
+ internal static string groupNameAsSet = "None";
+ internal static int userIdAsSet;
+ internal static string userNameAsSet;
+
+ #endregion
+ }
+}
+
+/* The original Java file had this header:
+ *
+** Authored by Timothy Gerard Endres
+** <mailto:time@gjt.org> <http://www.trustice.com>
+**
+** This work has been placed into the public domain.
+** You may use this work in any way and for any purpose you wish.
+**
+** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
+** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
+** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
+** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
+** REDISTRIBUTION OF THIS SOFTWARE.
+**
+*/
\ No newline at end of file
--- /dev/null
+// TarInputStream.cs
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+using System.Text;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Tar
+{
+ /// <summary>
+ /// The TarInputStream reads a UNIX tar archive as an InputStream.
+ /// methods are provided to position at each successive entry in
+ /// the archive, and the read each entry as a normal input stream
+ /// using read().
+ /// </summary>
+ public class TarInputStream : Stream
+ {
+ #region Constructors
+
+ /// <summary>
+ /// Construct a TarInputStream with default block factor
+ /// </summary>
+ /// <param name="inputStream">stream to source data from</param>
+ public TarInputStream(Stream inputStream)
+ : this(inputStream, TarBuffer.DefaultBlockFactor)
+ {
+ }
+
+ /// <summary>
+ /// Construct a TarInputStream with user specified block factor
+ /// </summary>
+ /// <param name="inputStream">stream to source data from</param>
+ /// <param name="blockFactor">block factor to apply to archive</param>
+ public TarInputStream(Stream inputStream, int blockFactor)
+ {
+ this.inputStream = inputStream;
+ _buffer = TarBuffer.CreateInputTarBuffer(inputStream, blockFactor);
+ }
+
+ #endregion
+
+ #region Stream Overrides
+
+ /// <summary>
+ /// Gets a value indicating whether the current stream supports reading
+ /// </summary>
+ public override bool CanRead
+ {
+ get { return inputStream.CanRead; }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the current stream supports seeking
+ /// This property always returns false.
+ /// </summary>
+ public override bool CanSeek
+ {
+ get { return false; }
+ }
+
+ /// <summary>
+ /// Gets a value indicating if the stream supports writing.
+ /// This property always returns false.
+ /// </summary>
+ public override bool CanWrite
+ {
+ get { return false; }
+ }
+
+ /// <summary>
+ /// The length in bytes of the stream
+ /// </summary>
+ public override long Length
+ {
+ get { return inputStream.Length; }
+ }
+
+ /// <summary>
+ /// Gets or sets the position within the stream.
+ /// Setting the Position is not supported and throws a NotSupportedExceptionNotSupportedException
+ /// </summary>
+ /// <exception cref="NotSupportedException">Any attempt to set position</exception>
+ public override long Position
+ {
+ get { return inputStream.Position; }
+ set { throw new NotSupportedException("TarInputStream Seek not supported"); }
+ }
+
+ /// <summary>
+ /// Flushes the baseInputStream
+ /// </summary>
+ public override void Flush()
+ {
+ inputStream.Flush();
+ }
+
+ /// <summary>
+ /// Set the streams position. This operation is not supported and will throw a NotSupportedException
+ /// </summary>
+ /// <param name="offset">The offset relative to the origin to seek to.</param>
+ /// <param name="origin">The <see cref="SeekOrigin"/> to start seeking from.</param>
+ /// <returns>The new position in the stream.</returns>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new NotSupportedException("TarInputStream Seek not supported");
+ }
+
+ /// <summary>
+ /// Sets the length of the stream
+ /// This operation is not supported and will throw a NotSupportedException
+ /// </summary>
+ /// <param name="value">The new stream length.</param>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override void SetLength(long value)
+ {
+ throw new NotSupportedException("TarInputStream SetLength not supported");
+ }
+
+ /// <summary>
+ /// Writes a block of bytes to this stream using data from a buffer.
+ /// This operation is not supported and will throw a NotSupportedException
+ /// </summary>
+ /// <param name="buffer">The buffer containing bytes to write.</param>
+ /// <param name="offset">The offset in the buffer of the frist byte to write.</param>
+ /// <param name="count">The number of bytes to write.</param>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ throw new NotSupportedException("TarInputStream Write not supported");
+ }
+
+ /// <summary>
+ /// Writes a byte to the current position in the file stream.
+ /// This operation is not supported and will throw a NotSupportedException
+ /// </summary>
+ /// <param name="value">The byte value to write.</param>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override void WriteByte(byte value)
+ {
+ throw new NotSupportedException("TarInputStream WriteByte not supported");
+ }
+
+ /// <summary>
+ /// Reads a byte from the current tar archive entry.
+ /// </summary>
+ /// <returns>A byte cast to an int; -1 if the at the end of the stream.</returns>
+ public override int ReadByte()
+ {
+ var oneByteBuffer = new byte[1];
+ var num = Read(oneByteBuffer, 0, 1);
+ if (num <= 0)
+ {
+ // return -1 to indicate that no byte was read.
+ return -1;
+ }
+ return oneByteBuffer[0];
+ }
+
+ /// <summary>
+ /// Reads bytes from the current tar archive entry.
+ ///
+ /// This method is aware of the boundaries of the current
+ /// entry in the archive and will deal with them appropriately
+ /// </summary>
+ /// <param name="buffer">
+ /// The buffer into which to place bytes read.
+ /// </param>
+ /// <param name="offset">
+ /// The offset at which to place bytes read.
+ /// </param>
+ /// <param name="count">
+ /// The number of bytes to read.
+ /// </param>
+ /// <returns>
+ /// The number of bytes read, or 0 at end of stream/EOF.
+ /// </returns>
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ if (buffer == null)
+ {
+ throw new ArgumentNullException("buffer");
+ }
+
+ var totalRead = 0;
+
+ if (entryOffset >= entrySize)
+ {
+ return 0;
+ }
+
+ long numToRead = count;
+
+ if ((numToRead + entryOffset) > entrySize)
+ {
+ numToRead = entrySize - entryOffset;
+ }
+
+ if (readBuffer != null)
+ {
+ var sz = (numToRead > readBuffer.Length) ? readBuffer.Length : (int) numToRead;
+
+ Array.Copy(readBuffer, 0, buffer, offset, sz);
+
+ if (sz >= readBuffer.Length)
+ {
+ readBuffer = null;
+ }
+ else
+ {
+ var newLen = readBuffer.Length - sz;
+ var newBuf = new byte[newLen];
+ Array.Copy(readBuffer, sz, newBuf, 0, newLen);
+ readBuffer = newBuf;
+ }
+
+ totalRead += sz;
+ numToRead -= sz;
+ offset += sz;
+ }
+
+ while (numToRead > 0)
+ {
+ var rec = _buffer.ReadBlock();
+ if (rec == null)
+ {
+ // Unexpected EOF!
+ throw new TarException("unexpected EOF with " + numToRead + " bytes unread");
+ }
+
+ var sz = (int) numToRead;
+ var recLen = rec.Length;
+
+ if (recLen > sz)
+ {
+ Array.Copy(rec, 0, buffer, offset, sz);
+ readBuffer = new byte[recLen - sz];
+ Array.Copy(rec, sz, readBuffer, 0, recLen - sz);
+ }
+ else
+ {
+ sz = recLen;
+ Array.Copy(rec, 0, buffer, offset, recLen);
+ }
+
+ totalRead += sz;
+ numToRead -= sz;
+ offset += sz;
+ }
+
+ entryOffset += totalRead;
+
+ return totalRead;
+ }
+
+ /// <summary>
+ /// Closes this stream. Calls the TarBuffer's close() method.
+ /// The underlying stream is closed by the TarBuffer.
+ /// </summary>
+ public override void Close()
+ {
+ _buffer.Close();
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Get the record size being used by this stream's TarBuffer.
+ /// </summary>
+ public int RecordSize
+ {
+ get { return _buffer.RecordSize; }
+ }
+
+ /// <summary>
+ /// Get the available data that can be read from the current
+ /// entry in the archive. This does not indicate how much data
+ /// is left in the entire archive, only in the current entry.
+ /// This value is determined from the entry's size header field
+ /// and the amount of data already read from the current entry.
+ /// </summary>
+ /// <returns>
+ /// The number of available bytes for the current entry.
+ /// </returns>
+ public long Available
+ {
+ get { return entrySize - entryOffset; }
+ }
+
+ /// <summary>
+ /// Return a value of true if marking is supported; false otherwise.
+ /// </summary>
+ /// <remarks>Currently marking is not supported, the return value is always false.</remarks>
+ public bool IsMarkSupported
+ {
+ get { return false; }
+ }
+
+ /// <summary>
+ /// Set the entry factory for this instance.
+ /// </summary>
+ /// <param name="factory">The factory for creating new entries</param>
+ public void SetEntryFactory(IEntryFactory factory)
+ {
+ entryFactory = factory;
+ }
+
+ /// <summary>
+ /// Get the record size being used by this stream's TarBuffer.
+ /// </summary>
+ /// <returns>
+ /// TarBuffer record size.
+ /// </returns>
+ [Obsolete("Use RecordSize property instead")]
+ public int GetRecordSize()
+ {
+ return _buffer.RecordSize;
+ }
+
+ /// <summary>
+ /// Skip bytes in the input buffer. This skips bytes in the
+ /// current entry's data, not the entire archive, and will
+ /// stop at the end of the current entry's data if the number
+ /// to skip extends beyond that point.
+ /// </summary>
+ /// <param name="skipCount">
+ /// The number of bytes to skip.
+ /// </param>
+ public void Skip(long skipCount)
+ {
+ // TODO: REVIEW efficiency of TarInputStream.Skip
+ // This is horribly inefficient, but it ensures that we
+ // properly skip over bytes via the TarBuffer...
+ //
+ var skipBuf = new byte[8*1024];
+
+ for (var num = skipCount; num > 0;)
+ {
+ var toRead = num > skipBuf.Length ? skipBuf.Length : (int) num;
+ var numRead = Read(skipBuf, 0, toRead);
+
+ if (numRead == -1)
+ {
+ break;
+ }
+
+ num -= numRead;
+ }
+ }
+
+ /// <summary>
+ /// Since we do not support marking just yet, we do nothing.
+ /// </summary>
+ /// <param name ="markLimit">
+ /// The limit to mark.
+ /// </param>
+ public void Mark(int markLimit)
+ {
+ }
+
+ /// <summary>
+ /// Since we do not support marking just yet, we do nothing.
+ /// </summary>
+ public void Reset()
+ {
+ }
+
+ /// <summary>
+ /// Get the next entry in this tar archive. This will skip
+ /// over any remaining data in the current entry, if there
+ /// is one, and place the input stream at the header of the
+ /// next entry, and read the header and instantiate a new
+ /// TarEntry from the header bytes and return that entry.
+ /// If there are no more entries in the archive, null will
+ /// be returned to indicate that the end of the archive has
+ /// been reached.
+ /// </summary>
+ /// <returns>
+ /// The next TarEntry in the archive, or null.
+ /// </returns>
+ public TarEntry GetNextEntry()
+ {
+ if (hasHitEOF)
+ {
+ return null;
+ }
+
+ if (currentEntry != null)
+ {
+ SkipToNextEntry();
+ }
+
+ var headerBuf = _buffer.ReadBlock();
+
+ if (headerBuf == null)
+ {
+ hasHitEOF = true;
+ }
+ else if (_buffer.IsEOFBlock(headerBuf))
+ {
+ hasHitEOF = true;
+ }
+
+ if (hasHitEOF)
+ {
+ currentEntry = null;
+ }
+ else
+ {
+ try
+ {
+ var header = new TarHeader();
+ header.ParseBuffer(headerBuf);
+ if (!header.IsChecksumValid)
+ {
+ throw new TarException("Header checksum is invalid");
+ }
+ entryOffset = 0;
+ entrySize = header.Size;
+
+ StringBuilder longName = null;
+
+ if (header.TypeFlag == TarHeader.LF_GNU_LONGNAME)
+ {
+ var nameBuffer = new byte[TarBuffer.BlockSize];
+ var numToRead = entrySize;
+
+ longName = new StringBuilder();
+
+ while (numToRead > 0)
+ {
+ var numRead = Read(nameBuffer, 0,
+ (numToRead > nameBuffer.Length ? nameBuffer.Length : (int) numToRead));
+
+ if (numRead == -1)
+ {
+ throw new InvalidHeaderException("Failed to read long name entry");
+ }
+
+ longName.Append(TarHeader.ParseName(nameBuffer, 0, numRead).ToString());
+ numToRead -= numRead;
+ }
+
+ SkipToNextEntry();
+ headerBuf = _buffer.ReadBlock();
+ }
+ else if (header.TypeFlag == TarHeader.LF_GHDR)
+ {
+ // POSIX global extended header
+ // Ignore things we dont understand completely for now
+ SkipToNextEntry();
+ headerBuf = _buffer.ReadBlock();
+ }
+ else if (header.TypeFlag == TarHeader.LF_XHDR)
+ {
+ // POSIX extended header
+ // Ignore things we dont understand completely for now
+ SkipToNextEntry();
+ headerBuf = _buffer.ReadBlock();
+ }
+ else if (header.TypeFlag == TarHeader.LF_GNU_VOLHDR)
+ {
+ // TODO: could show volume name when verbose
+ SkipToNextEntry();
+ headerBuf = _buffer.ReadBlock();
+ }
+ else if (header.TypeFlag != TarHeader.LF_NORMAL &&
+ header.TypeFlag != TarHeader.LF_OLDNORM &&
+ header.TypeFlag != TarHeader.LF_DIR)
+ {
+ // Ignore things we dont understand completely for now
+ SkipToNextEntry();
+ headerBuf = _buffer.ReadBlock();
+ }
+
+ if (entryFactory == null)
+ {
+ currentEntry = new TarEntry(headerBuf);
+ if (longName != null)
+ {
+ currentEntry.Name = longName.ToString();
+ }
+ }
+ else
+ {
+ currentEntry = entryFactory.CreateEntry(headerBuf);
+ }
+
+ // Magic was checked here for 'ustar' but there are multiple valid possibilities
+ // so this is not done anymore.
+
+ entryOffset = 0;
+
+ // TODO: Review How do we resolve this discrepancy?!
+ entrySize = currentEntry.Size;
+ }
+ catch (InvalidHeaderException ex)
+ {
+ entrySize = 0;
+ entryOffset = 0;
+ currentEntry = null;
+ var errorText = string.Format("Bad header in record {0} block {1} {2}",
+ _buffer.CurrentRecord, _buffer.CurrentBlock, ex.Message);
+ throw new InvalidHeaderException(errorText);
+ }
+ }
+ return currentEntry;
+ }
+
+ /// <summary>
+ /// Copies the contents of the current tar archive entry directly into
+ /// an output stream.
+ /// </summary>
+ /// <param name="outputStream">
+ /// The OutputStream into which to write the entry's data.
+ /// </param>
+ public void CopyEntryContents(Stream outputStream)
+ {
+ var tempBuffer = new byte[32*1024];
+
+ while (true)
+ {
+ var numRead = Read(tempBuffer, 0, tempBuffer.Length);
+ if (numRead <= 0)
+ {
+ break;
+ }
+ outputStream.Write(tempBuffer, 0, numRead);
+ }
+ }
+
+ private void SkipToNextEntry()
+ {
+ var numToSkip = entrySize - entryOffset;
+
+ if (numToSkip > 0)
+ {
+ Skip(numToSkip);
+ }
+
+ readBuffer = null;
+ }
+
+ #region Nested type: EntryFactoryAdapter
+
+ /// <summary>
+ /// Standard entry factory class creating instances of the class TarEntry
+ /// </summary>
+ public class EntryFactoryAdapter : IEntryFactory
+ {
+ #region IEntryFactory Members
+
+ /// <summary>
+ /// Create a <see cref="TarEntry"/> based on named
+ /// </summary>
+ /// <param name="name">The name to use for the entry</param>
+ /// <returns>A new <see cref="TarEntry"/></returns>
+ public TarEntry CreateEntry(string name)
+ {
+ return TarEntry.CreateTarEntry(name);
+ }
+
+ /// <summary>
+ /// Create a tar entry with details obtained from <paramref name="fileName">file</paramref>
+ /// </summary>
+ /// <param name="fileName">The name of the file to retrieve details from.</param>
+ /// <returns>A new <see cref="TarEntry"/></returns>
+ public TarEntry CreateEntryFromFile(string fileName)
+ {
+ return TarEntry.CreateEntryFromFile(fileName);
+ }
+
+ /// <summary>
+ /// Create an entry based on details in <paramref name="headerBuffer">header</paramref>
+ /// </summary>
+ /// <param name="headerBuffer">The buffer containing entry details.</param>
+ /// <returns>A new <see cref="TarEntry"/></returns>
+ public TarEntry CreateEntry(byte[] headerBuffer)
+ {
+ return new TarEntry(headerBuffer);
+ }
+
+ #endregion
+ }
+
+ #endregion
+
+ #region Instance Fields
+
+ /// <summary>
+ /// Stream used as the source of input data.
+ /// </summary>
+ private readonly Stream inputStream;
+
+ /// <summary>
+ /// Working buffer
+ /// </summary>
+ protected TarBuffer _buffer;
+
+ /// <summary>
+ /// Current entry being read
+ /// </summary>
+ private TarEntry currentEntry;
+
+ /// <summary>
+ /// Factory used to create TarEntry or descendant class instance
+ /// </summary>
+ protected IEntryFactory entryFactory;
+
+ /// <summary>
+ /// Number of bytes read for this entry so far
+ /// </summary>
+ protected long entryOffset;
+
+ /// <summary>
+ /// Size of this entry as recorded in header
+ /// </summary>
+ protected long entrySize;
+
+ /// <summary>
+ /// Flag set when last block has been read
+ /// </summary>
+ protected bool hasHitEOF;
+
+ /// <summary>
+ /// Buffer used with calls to <code>Read()</code>
+ /// </summary>
+ protected byte[] readBuffer;
+
+ #endregion
+
+ #region Nested type: IEntryFactory
+
+ /// <summary>
+ /// This interface is provided, along with the method <see cref="SetEntryFactory"/>, to allow
+ /// the programmer to have their own <see cref="TarEntry"/> subclass instantiated for the
+ /// entries return from <see cref="GetNextEntry"/>.
+ /// </summary>
+ public interface IEntryFactory
+ {
+ /// <summary>
+ /// Create an entry based on name alone
+ /// </summary>
+ /// <param name="name">
+ /// Name of the new EntryPointNotFoundException to create
+ /// </param>
+ /// <returns>created TarEntry or descendant class</returns>
+ TarEntry CreateEntry(string name);
+
+ /// <summary>
+ /// Create an instance based on an actual file
+ /// </summary>
+ /// <param name="fileName">
+ /// Name of file to represent in the entry
+ /// </param>
+ /// <returns>
+ /// Created TarEntry or descendant class
+ /// </returns>
+ TarEntry CreateEntryFromFile(string fileName);
+
+ /// <summary>
+ /// Create a tar entry based on the header information passed
+ /// </summary>
+ /// <param name="headerBuf">
+ /// Buffer containing header information to base entry on
+ /// </param>
+ /// <returns>
+ /// Created TarEntry or descendant class
+ /// </returns>
+ TarEntry CreateEntry(byte[] headerBuf);
+ }
+
+ #endregion
+ }
+}
+
+/* The original Java file had this header:
+ ** Authored by Timothy Gerard Endres
+ ** <mailto:time@gjt.org> <http://www.trustice.com>
+ **
+ ** This work has been placed into the public domain.
+ ** You may use this work in any way and for any purpose you wish.
+ **
+ ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
+ ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
+ ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
+ ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
+ ** REDISTRIBUTION OF THIS SOFTWARE.
+ **
+ */
\ No newline at end of file
--- /dev/null
+// TarOutputStream.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright 2005 John Reilly
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Tar
+{
+ /// <summary>
+ /// The TarOutputStream writes a UNIX tar archive as an OutputStream.
+ /// Methods are provided to put entries, and then write their contents
+ /// by writing to this stream using write().
+ /// </summary>
+ /// public
+ public class TarOutputStream : Stream
+ {
+ #region Constructors
+
+ /// <summary>
+ /// Construct TarOutputStream using default block factor
+ /// </summary>
+ /// <param name="outputStream">stream to write to</param>
+ public TarOutputStream(Stream outputStream)
+ : this(outputStream, TarBuffer.DefaultBlockFactor)
+ {
+ }
+
+ /// <summary>
+ /// Construct TarOutputStream with user specified block factor
+ /// </summary>
+ /// <param name="outputStream">stream to write to</param>
+ /// <param name="blockFactor">blocking factor</param>
+ public TarOutputStream(Stream outputStream, int blockFactor)
+ {
+ if (outputStream == null)
+ {
+ throw new ArgumentNullException("outputStream");
+ }
+
+ this.outputStream = outputStream;
+ _buffer = TarBuffer.CreateOutputTarBuffer(outputStream, blockFactor);
+
+ assemblyBuffer = new byte[TarBuffer.BlockSize];
+ blockBuffer = new byte[TarBuffer.BlockSize];
+ }
+
+ #endregion
+
+ /// <summary>
+ /// true if the stream supports reading; otherwise, false.
+ /// </summary>
+ public override bool CanRead
+ {
+ get { return outputStream.CanRead; }
+ }
+
+ /// <summary>
+ /// true if the stream supports seeking; otherwise, false.
+ /// </summary>
+ public override bool CanSeek
+ {
+ get { return outputStream.CanSeek; }
+ }
+
+ /// <summary>
+ /// true if stream supports writing; otherwise, false.
+ /// </summary>
+ public override bool CanWrite
+ {
+ get { return outputStream.CanWrite; }
+ }
+
+ /// <summary>
+ /// length of stream in bytes
+ /// </summary>
+ public override long Length
+ {
+ get { return outputStream.Length; }
+ }
+
+ /// <summary>
+ /// gets or sets the position within the current stream.
+ /// </summary>
+ public override long Position
+ {
+ get { return outputStream.Position; }
+ set { outputStream.Position = value; }
+ }
+
+ /// <summary>
+ /// Get the record size being used by this stream's TarBuffer.
+ /// </summary>
+ public int RecordSize
+ {
+ get { return _buffer.RecordSize; }
+ }
+
+ /// <summary>
+ /// Get a value indicating wether an entry is open, requiring more data to be written.
+ /// </summary>
+ private bool IsEntryOpen
+ {
+ get { return (currBytes < currSize); }
+ }
+
+ /// <summary>
+ /// set the position within the current stream
+ /// </summary>
+ /// <param name="offset">The offset relative to the <paramref name="origin"/> to seek to</param>
+ /// <param name="origin">The <see cref="SeekOrigin"/> to seek from.</param>
+ /// <returns>The new position in the stream.</returns>
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ return outputStream.Seek(offset, origin);
+ }
+
+ /// <summary>
+ /// Set the length of the current stream
+ /// </summary>
+ /// <param name="value">The new stream length.</param>
+ public override void SetLength(long value)
+ {
+ outputStream.SetLength(value);
+ }
+
+ /// <summary>
+ /// Read a byte from the stream and advance the position within the stream
+ /// by one byte or returns -1 if at the end of the stream.
+ /// </summary>
+ /// <returns>The byte value or -1 if at end of stream</returns>
+ public override int ReadByte()
+ {
+ return outputStream.ReadByte();
+ }
+
+ /// <summary>
+ /// read bytes from the current stream and advance the position within the
+ /// stream by the number of bytes read.
+ /// </summary>
+ /// <param name="buffer">The buffer to store read bytes in.</param>
+ /// <param name="offset">The index into the buffer to being storing bytes at.</param>
+ /// <param name="count">The desired number of bytes to read.</param>
+ /// <returns>The total number of bytes read, or zero if at the end of the stream.
+ /// The number of bytes may be less than the <paramref name="count">count</paramref>
+ /// requested if data is not avialable.</returns>
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ return outputStream.Read(buffer, offset, count);
+ }
+
+ /// <summary>
+ /// All buffered data is written to destination
+ /// </summary>
+ public override void Flush()
+ {
+ outputStream.Flush();
+ }
+
+ /// <summary>
+ /// Ends the TAR archive without closing the underlying OutputStream.
+ /// The result is that the EOF block of nulls is written.
+ /// </summary>
+ public void Finish()
+ {
+ if (IsEntryOpen)
+ {
+ CloseEntry();
+ }
+ WriteEofBlock();
+ }
+
+ /// <summary>
+ /// Ends the TAR archive and closes the underlying OutputStream.
+ /// </summary>
+ /// <remarks>This means that Finish() is called followed by calling the
+ /// TarBuffer's Close().</remarks>
+ public override void Close()
+ {
+ if (!isClosed)
+ {
+ isClosed = true;
+ Finish();
+ _buffer.Close();
+ }
+ }
+
+ /// <summary>
+ /// Get the record size being used by this stream's TarBuffer.
+ /// </summary>
+ /// <returns>
+ /// The TarBuffer record size.
+ /// </returns>
+ [Obsolete("Use RecordSize property instead")]
+ public int GetRecordSize()
+ {
+ return _buffer.RecordSize;
+ }
+
+ /// <summary>
+ /// Put an entry on the output stream. This writes the entry's
+ /// header and positions the output stream for writing
+ /// the contents of the entry. Once this method is called, the
+ /// stream is ready for calls to write() to write the entry's
+ /// contents. Once the contents are written, closeEntry()
+ /// <B>MUST</B> be called to ensure that all buffered data
+ /// is completely written to the output stream.
+ /// </summary>
+ /// <param name="entry">
+ /// The TarEntry to be written to the archive.
+ /// </param>
+ public void PutNextEntry(TarEntry entry)
+ {
+ if (entry == null)
+ {
+ throw new ArgumentNullException("entry");
+ }
+
+ if (entry.TarHeader.Name.Length >= TarHeader.NAMELEN)
+ {
+ var longHeader = new TarHeader{TypeFlag = TarHeader.LF_GNU_LONGNAME};
+ longHeader.Name = longHeader.Name + "././@LongLink";
+ longHeader.UserId = 0;
+ longHeader.GroupId = 0;
+ longHeader.GroupName = String.Empty;
+ longHeader.UserName = String.Empty;
+ longHeader.LinkName = String.Empty;
+
+ longHeader.Size = entry.TarHeader.Name.Length;
+
+ longHeader.WriteHeader(blockBuffer);
+ _buffer.WriteBlock(blockBuffer); // Add special long filename header block
+
+ var nameCharIndex = 0;
+
+ while (nameCharIndex < entry.TarHeader.Name.Length)
+ {
+ Array.Clear(blockBuffer, 0, blockBuffer.Length);
+ TarHeader.GetAsciiBytes(entry.TarHeader.Name, nameCharIndex, blockBuffer, 0, TarBuffer.BlockSize);
+ nameCharIndex += TarBuffer.BlockSize;
+ _buffer.WriteBlock(blockBuffer);
+ }
+ }
+
+ entry.WriteEntryHeader(blockBuffer);
+ _buffer.WriteBlock(blockBuffer);
+
+ currBytes = 0;
+
+ currSize = entry.IsDirectory ? 0 : entry.Size;
+ }
+
+ /// <summary>
+ /// Close an entry. This method MUST be called for all file
+ /// entries that contain data. The reason is that we must
+ /// buffer data written to the stream in order to satisfy
+ /// the buffer's block based writes. Thus, there may be
+ /// data fragments still being assembled that must be written
+ /// to the output stream before this entry is closed and the
+ /// next entry written.
+ /// </summary>
+ public void CloseEntry()
+ {
+ if (assemblyBufferLength > 0)
+ {
+ Array.Clear(assemblyBuffer, assemblyBufferLength, assemblyBuffer.Length - assemblyBufferLength);
+
+ _buffer.WriteBlock(assemblyBuffer);
+
+ currBytes += assemblyBufferLength;
+ assemblyBufferLength = 0;
+ }
+
+ if (currBytes < currSize)
+ {
+ var errorText = string.Format(
+ "Entry closed at '{0}' before the '{1}' bytes specified in the header were written",
+ currBytes, currSize);
+ throw new TarException(errorText);
+ }
+ }
+
+ /// <summary>
+ /// Writes a byte to the current tar archive entry.
+ /// This method simply calls Write(byte[], int, int).
+ /// </summary>
+ /// <param name="value">
+ /// The byte to be written.
+ /// </param>
+ public override void WriteByte(byte value)
+ {
+ Write(new[]{value}, 0, 1);
+ }
+
+ /// <summary>
+ /// Writes bytes to the current tar archive entry. This method
+ /// is aware of the current entry and will throw an exception if
+ /// you attempt to write bytes past the length specified for the
+ /// current entry. The method is also (painfully) aware of the
+ /// record buffering required by TarBuffer, and manages buffers
+ /// that are not a multiple of recordsize in length, including
+ /// assembling records from small buffers.
+ /// </summary>
+ /// <param name = "buffer">
+ /// The buffer to write to the archive.
+ /// </param>
+ /// <param name = "offset">
+ /// The offset in the buffer from which to get bytes.
+ /// </param>
+ /// <param name = "count">
+ /// The number of bytes to write.
+ /// </param>
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ if (buffer == null)
+ {
+ throw new ArgumentNullException("buffer");
+ }
+
+ if (offset < 0)
+ {
+ throw new ArgumentOutOfRangeException("offset", "Cannot be negative");
+ }
+
+ if (buffer.Length - offset < count)
+ {
+ throw new ArgumentException("offset and count combination is invalid");
+ }
+
+ if (count < 0)
+ {
+ throw new ArgumentOutOfRangeException("count", "Cannot be negative");
+ }
+
+ if ((currBytes + count) > currSize)
+ {
+ var errorText = string.Format("request to write '{0}' bytes exceeds size in header of '{1}' bytes",
+ count, currSize);
+ throw new ArgumentOutOfRangeException("count", errorText);
+ }
+
+ //
+ // We have to deal with assembly!!!
+ // The programmer can be writing little 32 byte chunks for all
+ // we know, and we must assemble complete blocks for writing.
+ // TODO REVIEW Maybe this should be in TarBuffer? Could that help to
+ // eliminate some of the buffer copying.
+ //
+ if (assemblyBufferLength > 0)
+ {
+ if ((assemblyBufferLength + count) >= blockBuffer.Length)
+ {
+ var aLen = blockBuffer.Length - assemblyBufferLength;
+
+ Array.Copy(assemblyBuffer, 0, blockBuffer, 0, assemblyBufferLength);
+ Array.Copy(buffer, offset, blockBuffer, assemblyBufferLength, aLen);
+
+ _buffer.WriteBlock(blockBuffer);
+
+ currBytes += blockBuffer.Length;
+
+ offset += aLen;
+ count -= aLen;
+
+ assemblyBufferLength = 0;
+ }
+ else
+ {
+ Array.Copy(buffer, offset, assemblyBuffer, assemblyBufferLength, count);
+ offset += count;
+ assemblyBufferLength += count;
+ count -= count;
+ }
+ }
+
+ //
+ // When we get here we have EITHER:
+ // o An empty "assembly" buffer.
+ // o No bytes to write (count == 0)
+ //
+ while (count > 0)
+ {
+ if (count < blockBuffer.Length)
+ {
+ Array.Copy(buffer, offset, assemblyBuffer, assemblyBufferLength, count);
+ assemblyBufferLength += count;
+ break;
+ }
+
+ _buffer.WriteBlock(buffer, offset);
+
+ var bufferLength = blockBuffer.Length;
+ currBytes += bufferLength;
+ count -= bufferLength;
+ offset += bufferLength;
+ }
+ }
+
+ /// <summary>
+ /// Write an EOF (end of archive) block to the tar archive.
+ /// An EOF block consists of all zeros.
+ /// </summary>
+ private void WriteEofBlock()
+ {
+ Array.Clear(blockBuffer, 0, blockBuffer.Length);
+ _buffer.WriteBlock(blockBuffer);
+ }
+
+ #region Instance Fields
+
+ /// <summary>
+ /// 'Assembly' buffer used to assemble data before writing
+ /// </summary>
+ protected byte[] assemblyBuffer;
+
+ /// <summary>
+ /// current 'Assembly' buffer length
+ /// </summary>
+ private int assemblyBufferLength;
+
+ /// <summary>
+ /// single block working buffer
+ /// </summary>
+ protected byte[] blockBuffer;
+
+ /// <summary>
+ /// TarBuffer used to provide correct blocking factor
+ /// </summary>
+ protected TarBuffer _buffer;
+
+ /// <summary>
+ /// bytes written for this entry so far
+ /// </summary>
+ private long currBytes;
+
+ /// <summary>
+ /// Size for the current entry
+ /// </summary>
+ protected long currSize;
+
+ /// <summary>
+ /// Flag indicating wether this instance has been closed or not.
+ /// </summary>
+ private bool isClosed;
+
+ /// <summary>
+ /// the destination stream for the archive contents
+ /// </summary>
+ protected Stream outputStream;
+
+ #endregion
+ }
+}
+
+/* The original Java file had this header:
+ ** Authored by Timothy Gerard Endres
+ ** <mailto:time@gjt.org> <http://www.trustice.com>
+ **
+ ** This work has been placed into the public domain.
+ ** You may use this work in any way and for any purpose you wish.
+ **
+ ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
+ ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
+ ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
+ ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
+ ** REDISTRIBUTION OF THIS SOFTWARE.
+ **
+ */
\ No newline at end of file
--- /dev/null
+// Deflater.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip.Compression
+{
+ /// <summary>
+ /// This is the Deflater class. The deflater class compresses input
+ /// with the deflate algorithm described in RFC 1951. It has several
+ /// compression levels and three different strategies described below.
+ ///
+ /// This class is <i>not</i> thread safe. This is inherent in the API, due
+ /// to the split of deflate and setInput.
+ ///
+ /// author of the original java version : Jochen Hoenicke
+ /// </summary>
+ public class Deflater
+ {
+ #region Deflater Documentation
+ /*
+ * The Deflater can do the following state transitions:
+ *
+ * (1) -> INIT_STATE ----> INIT_FINISHING_STATE ---.
+ * / | (2) (5) |
+ * / v (5) |
+ * (3)| SETDICT_STATE ---> SETDICT_FINISHING_STATE |(3)
+ * \ | (3) | ,--------'
+ * | | | (3) /
+ * v v (5) v v
+ * (1) -> BUSY_STATE ----> FINISHING_STATE
+ * | (6)
+ * v
+ * FINISHED_STATE
+ * \_____________________________________/
+ * | (7)
+ * v
+ * CLOSED_STATE
+ *
+ * (1) If we should produce a header we start in INIT_STATE, otherwise
+ * we start in BUSY_STATE.
+ * (2) A dictionary may be set only when we are in INIT_STATE, then
+ * we change the state as indicated.
+ * (3) Whether a dictionary is set or not, on the first call of deflate
+ * we change to BUSY_STATE.
+ * (4) -- intentionally left blank -- :)
+ * (5) FINISHING_STATE is entered, when flush() is called to indicate that
+ * there is no more INPUT. There are also states indicating, that
+ * the header wasn't written yet.
+ * (6) FINISHED_STATE is entered, when everything has been flushed to the
+ * internal pending output buffer.
+ * (7) At any time (7)
+ *
+ */
+ #endregion
+ #region Public Constants
+ /// <summary>
+ /// The best and slowest compression level. This tries to find very
+ /// long and distant string repetitions.
+ /// </summary>
+ public const int BEST_COMPRESSION = 9;
+
+ /// <summary>
+ /// The worst but fastest compression level.
+ /// </summary>
+ public const int BEST_SPEED = 1;
+
+ /// <summary>
+ /// The default compression level.
+ /// </summary>
+ public const int DEFAULT_COMPRESSION = -1;
+
+ /// <summary>
+ /// This level won't compress at all but output uncompressed blocks.
+ /// </summary>
+ public const int NO_COMPRESSION = 0;
+
+ /// <summary>
+ /// The compression method. This is the only method supported so far.
+ /// There is no need to use this constant at all.
+ /// </summary>
+ public const int DEFLATED = 8;
+ #endregion
+ #region Local Constants
+ private const int IS_SETDICT = 0x01;
+ private const int IS_FLUSHING = 0x04;
+ private const int IS_FINISHING = 0x08;
+
+ private const int INIT_STATE = 0x00;
+ private const int SETDICT_STATE = 0x01;
+ // private static int INIT_FINISHING_STATE = 0x08;
+ // private static int SETDICT_FINISHING_STATE = 0x09;
+ private const int BUSY_STATE = 0x10;
+ private const int FLUSHING_STATE = 0x14;
+ private const int FINISHING_STATE = 0x1c;
+ private const int FINISHED_STATE = 0x1e;
+ private const int CLOSED_STATE = 0x7f;
+ #endregion
+ #region Constructors
+ /// <summary>
+ /// Creates a new deflater with default compression level.
+ /// </summary>
+ public Deflater() : this(DEFAULT_COMPRESSION, false)
+ {
+
+ }
+
+ /// <summary>
+ /// Creates a new deflater with given compression level.
+ /// </summary>
+ /// <param name="level">
+ /// the compression level, a value between NO_COMPRESSION
+ /// and BEST_COMPRESSION, or DEFAULT_COMPRESSION.
+ /// </param>
+ /// <exception cref="System.ArgumentOutOfRangeException">if lvl is out of range.</exception>
+ public Deflater(int level) : this(level, false)
+ {
+
+ }
+
+ /// <summary>
+ /// Creates a new deflater with given compression level.
+ /// </summary>
+ /// <param name="level">
+ /// the compression level, a value between NO_COMPRESSION
+ /// and BEST_COMPRESSION.
+ /// </param>
+ /// <param name="noZlibHeaderOrFooter">
+ /// true, if we should suppress the Zlib/RFC1950 header at the
+ /// beginning and the adler checksum at the end of the output. This is
+ /// useful for the GZIP/PKZIP formats.
+ /// </param>
+ /// <exception cref="System.ArgumentOutOfRangeException">if lvl is out of range.</exception>
+ public Deflater(int level, bool noZlibHeaderOrFooter)
+ {
+ if (level == DEFAULT_COMPRESSION) {
+ level = 6;
+ } else if (level < NO_COMPRESSION || level > BEST_COMPRESSION) {
+ throw new ArgumentOutOfRangeException("level");
+ }
+
+ pending = new DeflaterPending();
+ engine = new DeflaterEngine(pending);
+ this.noZlibHeaderOrFooter = noZlibHeaderOrFooter;
+ SetStrategy(DeflateStrategy.Default);
+ SetLevel(level);
+ Reset();
+ }
+ #endregion
+
+ /// <summary>
+ /// Resets the deflater. The deflater acts afterwards as if it was
+ /// just created with the same compression level and strategy as it
+ /// had before.
+ /// </summary>
+ public void Reset()
+ {
+ state = (noZlibHeaderOrFooter ? BUSY_STATE : INIT_STATE);
+ totalOut = 0;
+ pending.Reset();
+ engine.Reset();
+ }
+
+ /// <summary>
+ /// Gets the current adler checksum of the data that was processed so far.
+ /// </summary>
+ public int Adler {
+ get {
+ return engine.Adler;
+ }
+ }
+
+ /// <summary>
+ /// Gets the number of input bytes processed so far.
+ /// </summary>
+ public int TotalIn {
+ get {
+ return engine.TotalIn;
+ }
+ }
+
+ /// <summary>
+ /// Gets the number of output bytes so far.
+ /// </summary>
+ public long TotalOut {
+ get {
+ return totalOut;
+ }
+ }
+
+ /// <summary>
+ /// Flushes the current input block. Further calls to deflate() will
+ /// produce enough output to inflate everything in the current input
+ /// block. This is not part of Sun's JDK so I have made it package
+ /// private. It is used by DeflaterOutputStream to implement
+ /// flush().
+ /// </summary>
+ public void Flush()
+ {
+ state |= IS_FLUSHING;
+ }
+
+ /// <summary>
+ /// Finishes the deflater with the current input block. It is an error
+ /// to give more input after this method was called. This method must
+ /// be called to force all bytes to be flushed.
+ /// </summary>
+ public void Finish()
+ {
+ state |= (IS_FLUSHING | IS_FINISHING);
+ }
+
+ /// <summary>
+ /// Returns true if the stream was finished and no more output bytes
+ /// are available.
+ /// </summary>
+ public bool IsFinished {
+ get {
+ return (state == FINISHED_STATE) && pending.IsFlushed;
+ }
+ }
+
+ /// <summary>
+ /// Returns true, if the input buffer is empty.
+ /// You should then call setInput().
+ /// NOTE: This method can also return true when the stream
+ /// was finished.
+ /// </summary>
+ public bool IsNeedingInput {
+ get {
+ return engine.NeedsInput();
+ }
+ }
+
+ /// <summary>
+ /// Sets the data which should be compressed next. This should be only
+ /// called when needsInput indicates that more input is needed.
+ /// If you call setInput when needsInput() returns false, the
+ /// previous input that is still pending will be thrown away.
+ /// The given byte array should not be changed, before needsInput() returns
+ /// true again.
+ /// This call is equivalent to <code>setInput(input, 0, input.length)</code>.
+ /// </summary>
+ /// <param name="input">
+ /// the buffer containing the input data.
+ /// </param>
+ /// <exception cref="System.InvalidOperationException">
+ /// if the buffer was finished() or ended().
+ /// </exception>
+ public void SetInput(byte[] input)
+ {
+ SetInput(input, 0, input.Length);
+ }
+
+ /// <summary>
+ /// Sets the data which should be compressed next. This should be
+ /// only called when needsInput indicates that more input is needed.
+ /// The given byte array should not be changed, before needsInput() returns
+ /// true again.
+ /// </summary>
+ /// <param name="input">
+ /// the buffer containing the input data.
+ /// </param>
+ /// <param name="offset">
+ /// the start of the data.
+ /// </param>
+ /// <param name="count">
+ /// the number of data bytes of input.
+ /// </param>
+ /// <exception cref="System.InvalidOperationException">
+ /// if the buffer was Finish()ed or if previous input is still pending.
+ /// </exception>
+ public void SetInput(byte[] input, int offset, int count)
+ {
+ if ((state & IS_FINISHING) != 0) {
+ throw new InvalidOperationException("Finish() already called");
+ }
+ engine.SetInput(input, offset, count);
+ }
+
+ /// <summary>
+ /// Sets the compression level. There is no guarantee of the exact
+ /// position of the change, but if you call this when needsInput is
+ /// true the change of compression level will occur somewhere near
+ /// before the end of the so far given input.
+ /// </summary>
+ /// <param name="level">
+ /// the new compression level.
+ /// </param>
+ public void SetLevel(int level)
+ {
+ if (level == DEFAULT_COMPRESSION) {
+ level = 6;
+ } else if (level < NO_COMPRESSION || level > BEST_COMPRESSION) {
+ throw new ArgumentOutOfRangeException("level");
+ }
+
+ if (this.level != level) {
+ this.level = level;
+ engine.SetLevel(level);
+ }
+ }
+
+ /// <summary>
+ /// Get current compression level
+ /// </summary>
+ /// <returns>Returns the current compression level</returns>
+ public int GetLevel() {
+ return level;
+ }
+
+ /// <summary>
+ /// Sets the compression strategy. Strategy is one of
+ /// DEFAULT_STRATEGY, HUFFMAN_ONLY and FILTERED. For the exact
+ /// position where the strategy is changed, the same as for
+ /// SetLevel() applies.
+ /// </summary>
+ /// <param name="strategy">
+ /// The new compression strategy.
+ /// </param>
+ public void SetStrategy(DeflateStrategy strategy)
+ {
+ engine.Strategy = strategy;
+ }
+
+ /// <summary>
+ /// Deflates the current input block with to the given array.
+ /// </summary>
+ /// <param name="output">
+ /// The buffer where compressed data is stored
+ /// </param>
+ /// <returns>
+ /// The number of compressed bytes added to the output, or 0 if either
+ /// IsNeedingInput() or IsFinished returns true or length is zero.
+ /// </returns>
+ public int Deflate(byte[] output)
+ {
+ return Deflate(output, 0, output.Length);
+ }
+
+ /// <summary>
+ /// Deflates the current input block to the given array.
+ /// </summary>
+ /// <param name="output">
+ /// Buffer to store the compressed data.
+ /// </param>
+ /// <param name="offset">
+ /// Offset into the output array.
+ /// </param>
+ /// <param name="length">
+ /// The maximum number of bytes that may be stored.
+ /// </param>
+ /// <returns>
+ /// The number of compressed bytes added to the output, or 0 if either
+ /// needsInput() or finished() returns true or length is zero.
+ /// </returns>
+ /// <exception cref="System.InvalidOperationException">
+ /// If Finish() was previously called.
+ /// </exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// If offset or length don't match the array length.
+ /// </exception>
+ public int Deflate(byte[] output, int offset, int length)
+ {
+ int origLength = length;
+
+ if (state == CLOSED_STATE) {
+ throw new InvalidOperationException("Deflater closed");
+ }
+
+ if (state < BUSY_STATE) {
+ // output header
+ int header = (DEFLATED +
+ ((DeflaterConstants.MAX_WBITS - 8) << 4)) << 8;
+ int level_flags = (level - 1) >> 1;
+ if (level_flags < 0 || level_flags > 3) {
+ level_flags = 3;
+ }
+ header |= level_flags << 6;
+ if ((state & IS_SETDICT) != 0) {
+ // Dictionary was set
+ header |= DeflaterConstants.PRESET_DICT;
+ }
+ header += 31 - (header % 31);
+
+ pending.WriteShortMSB(header);
+ if ((state & IS_SETDICT) != 0) {
+ int chksum = engine.Adler;
+ engine.ResetAdler();
+ pending.WriteShortMSB(chksum >> 16);
+ pending.WriteShortMSB(chksum & 0xffff);
+ }
+
+ state = BUSY_STATE | (state & (IS_FLUSHING | IS_FINISHING));
+ }
+
+ for (;;) {
+ int count = pending.Flush(output, offset, length);
+ offset += count;
+ totalOut += count;
+ length -= count;
+
+ if (length == 0 || state == FINISHED_STATE) {
+ break;
+ }
+
+ if (!engine.Deflate((state & IS_FLUSHING) != 0, (state & IS_FINISHING) != 0)) {
+ if (state == BUSY_STATE) {
+ // We need more input now
+ return origLength - length;
+ } else if (state == FLUSHING_STATE) {
+ if (level != NO_COMPRESSION) {
+ /* We have to supply some lookahead. 8 bit lookahead
+ * is needed by the zlib inflater, and we must fill
+ * the next byte, so that all bits are flushed.
+ */
+ int neededbits = 8 + ((-pending.BitCount) & 7);
+ while (neededbits > 0) {
+ /* write a static tree block consisting solely of
+ * an EOF:
+ */
+ pending.WriteBits(2, 10);
+ neededbits -= 10;
+ }
+ }
+ state = BUSY_STATE;
+ } else if (state == FINISHING_STATE) {
+ pending.AlignToByte();
+
+ // Compressed data is complete. Write footer information if required.
+ if (!noZlibHeaderOrFooter) {
+ int adler = engine.Adler;
+ pending.WriteShortMSB(adler >> 16);
+ pending.WriteShortMSB(adler & 0xffff);
+ }
+ state = FINISHED_STATE;
+ }
+ }
+ }
+ return origLength - length;
+ }
+
+ /// <summary>
+ /// Sets the dictionary which should be used in the deflate process.
+ /// This call is equivalent to <code>setDictionary(dict, 0, dict.Length)</code>.
+ /// </summary>
+ /// <param name="dictionary">
+ /// the dictionary.
+ /// </param>
+ /// <exception cref="System.InvalidOperationException">
+ /// if SetInput () or Deflate () were already called or another dictionary was already set.
+ /// </exception>
+ public void SetDictionary(byte[] dictionary)
+ {
+ SetDictionary(dictionary, 0, dictionary.Length);
+ }
+
+ /// <summary>
+ /// Sets the dictionary which should be used in the deflate process.
+ /// The dictionary is a byte array containing strings that are
+ /// likely to occur in the data which should be compressed. The
+ /// dictionary is not stored in the compressed output, only a
+ /// checksum. To decompress the output you need to supply the same
+ /// dictionary again.
+ /// </summary>
+ /// <param name="dictionary">
+ /// The dictionary data
+ /// </param>
+ /// <param name="index">
+ /// The index where dictionary information commences.
+ /// </param>
+ /// <param name="count">
+ /// The number of bytes in the dictionary.
+ /// </param>
+ /// <exception cref="System.InvalidOperationException">
+ /// If SetInput () or Deflate() were already called or another dictionary was already set.
+ /// </exception>
+ public void SetDictionary(byte[] dictionary, int index, int count)
+ {
+ if (state != INIT_STATE) {
+ throw new InvalidOperationException();
+ }
+
+ state = SETDICT_STATE;
+ engine.SetDictionary(dictionary, index, count);
+ }
+ #region Instance Fields
+ /// <summary>
+ /// Compression level.
+ /// </summary>
+ int level;
+
+ /// <summary>
+ /// If true no Zlib/RFC1950 headers or footers are generated
+ /// </summary>
+ bool noZlibHeaderOrFooter;
+
+ /// <summary>
+ /// The current state.
+ /// </summary>
+ int state;
+
+ /// <summary>
+ /// The total bytes of output written.
+ /// </summary>
+ long totalOut;
+
+ /// <summary>
+ /// The pending output.
+ /// </summary>
+ DeflaterPending pending;
+
+ /// <summary>
+ /// The deflater engine.
+ /// </summary>
+ DeflaterEngine engine;
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+// DeflaterConstants.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip.Compression
+{
+ /// <summary>
+ /// This class contains constants used for deflation.
+ /// </summary>
+ public class DeflaterConstants
+ {
+ /// <summary>
+ /// Set to true to enable debugging
+ /// </summary>
+ public const bool DEBUGGING = false;
+
+ /// <summary>
+ /// Written to Zip file to identify a stored block
+ /// </summary>
+ public const int STORED_BLOCK = 0;
+
+ /// <summary>
+ /// Identifies static tree in Zip file
+ /// </summary>
+ public const int STATIC_TREES = 1;
+
+ /// <summary>
+ /// Identifies dynamic tree in Zip file
+ /// </summary>
+ public const int DYN_TREES = 2;
+
+ /// <summary>
+ /// Header flag indicating a preset dictionary for deflation
+ /// </summary>
+ public const int PRESET_DICT = 0x20;
+
+ /// <summary>
+ /// Sets internal buffer sizes for Huffman encoding
+ /// </summary>
+ public const int DEFAULT_MEM_LEVEL = 8;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int MAX_MATCH = 258;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int MIN_MATCH = 3;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int MAX_WBITS = 15;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int WSIZE = 1 << MAX_WBITS;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int WMASK = WSIZE - 1;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int HASH_BITS = DEFAULT_MEM_LEVEL + 7;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int HASH_SIZE = 1 << HASH_BITS;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int HASH_MASK = HASH_SIZE - 1;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int HASH_SHIFT = (HASH_BITS + MIN_MATCH - 1) / MIN_MATCH;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int MAX_DIST = WSIZE - MIN_LOOKAHEAD;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int PENDING_BUF_SIZE = 1 << (DEFAULT_MEM_LEVEL + 8);
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public static int MAX_BLOCK_SIZE = Math.Min(65535, PENDING_BUF_SIZE - 5);
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int DEFLATE_STORED = 0;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int DEFLATE_FAST = 1;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public const int DEFLATE_SLOW = 2;
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public static int[] GOOD_LENGTH = { 0, 4, 4, 4, 4, 8, 8, 8, 32, 32 };
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public static int[] MAX_LAZY = { 0, 4, 5, 6, 4, 16, 16, 32, 128, 258 };
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public static int[] NICE_LENGTH = { 0, 8, 16, 32, 16, 32, 128, 128, 258, 258 };
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public static int[] MAX_CHAIN = { 0, 4, 8, 32, 16, 32, 128, 256, 1024, 4096 };
+
+ /// <summary>
+ /// Internal compression engine constant
+ /// </summary>
+ public static int[] COMPR_FUNC = { 0, 1, 1, 1, 1, 2, 2, 2, 2, 2 };
+
+ }
+}
\ No newline at end of file
--- /dev/null
+// DeflaterEngine.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using ICSharpCode.SharpZipLib.Silverlight.Checksums;
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip.Compression
+{
+ /// <summary>
+ /// Strategies for deflater
+ /// </summary>
+ public enum DeflateStrategy
+ {
+ /// <summary>
+ /// The default strategy
+ /// </summary>
+ Default = 0,
+
+ /// <summary>
+ /// This strategy will only allow longer string repetitions. It is
+ /// useful for random data with a small character set.
+ /// </summary>
+ Filtered = 1,
+
+
+ /// <summary>
+ /// This strategy will not look for string repetitions at all. It
+ /// only encodes with Huffman trees (which means, that more common
+ /// characters get a smaller encoding.
+ /// </summary>
+ HuffmanOnly = 2
+ }
+
+ /// <summary>
+ /// Low level compression engine for deflate algorithm which uses a 32K sliding window
+ /// with secondary compression from Huffman/Shannon-Fano codes.
+ /// </summary>
+ public class DeflaterEngine : DeflaterConstants
+ {
+ #region Constants
+ const int TooFar = 4096;
+ #endregion
+
+ #region Constructors
+ /// <summary>
+ /// Construct instance with pending buffer
+ /// </summary>
+ /// <param name="pending">
+ /// Pending buffer to use
+ /// </param>>
+ public DeflaterEngine(DeflaterPending pending)
+ {
+ this.pending = pending;
+ huffman = new DeflaterHuffman(pending);
+ adler = new Adler32();
+
+ window = new byte[2 * WSIZE];
+ head = new short[HASH_SIZE];
+ prev = new short[WSIZE];
+
+ // We start at index 1, to avoid an implementation deficiency, that
+ // we cannot build a repeat pattern at index 0.
+ blockStart = strstart = 1;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Deflate drives actual compression of data
+ /// </summary>
+ /// <param name="flush">True to flush input buffers</param>
+ /// <param name="finish">Finish deflation with the current input.</param>
+ /// <returns>Returns true if progress has been made.</returns>
+ public bool Deflate(bool flush, bool finish)
+ {
+ bool progress;
+ do
+ {
+ FillWindow();
+ var canFlush = flush && (inputOff == inputEnd);
+ switch (compressionFunction)
+ {
+ case DEFLATE_STORED:
+ progress = DeflateStored(canFlush, finish);
+ break;
+ case DEFLATE_FAST:
+ progress = DeflateFast(canFlush, finish);
+ break;
+ case DEFLATE_SLOW:
+ progress = DeflateSlow(canFlush, finish);
+ break;
+ default:
+ throw new InvalidOperationException("unknown compressionFunction");
+ }
+ } while (pending.IsFlushed && progress); // repeat while we have no pending output and progress was made
+ return progress;
+ }
+
+ /// <summary>
+ /// Sets input data to be deflated. Should only be called when <code>NeedsInput()</code>
+ /// returns true
+ /// </summary>
+ /// <param name="buffer">The buffer containing input data.</param>
+ /// <param name="offset">The offset of the first byte of data.</param>
+ /// <param name="count">The number of bytes of data to use as input.</param>
+ public void SetInput(byte[] buffer, int offset, int count)
+ {
+ if ( buffer == null )
+ {
+ throw new ArgumentNullException("buffer");
+ }
+
+ if ( offset < 0 )
+ {
+ throw new ArgumentOutOfRangeException("offset");
+ }
+
+ if ( count < 0 )
+ {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ if (inputOff < inputEnd)
+ {
+ throw new InvalidOperationException("Old input was not completely processed");
+ }
+
+ int end = offset + count;
+
+ /* We want to throw an ArrayIndexOutOfBoundsException early. The
+ * check is very tricky: it also handles integer wrap around.
+ */
+ if ((offset > end) || (end > buffer.Length) )
+ {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ inputBuf = buffer;
+ inputOff = offset;
+ inputEnd = end;
+ }
+
+ /// <summary>
+ /// Determines if more <see cref="SetInput">input</see> is needed.
+ /// </summary>
+ /// <returns>Return true if input is needed via <see cref="SetInput">SetInput</see></returns>
+ public bool NeedsInput()
+ {
+ return (inputEnd == inputOff);
+ }
+
+ /// <summary>
+ /// Set compression dictionary
+ /// </summary>
+ /// <param name="buffer">The buffer containing the dictionary data</param>
+ /// <param name="offset">The offset in the buffer for the first byte of data</param>
+ /// <param name="length">The length of the dictionary data.</param>
+ public void SetDictionary(byte[] buffer, int offset, int length)
+ {
+ adler.Update(buffer, offset, length);
+ if (length < MIN_MATCH)
+ {
+ return;
+ }
+
+ if (length > MAX_DIST)
+ {
+ offset += length - MAX_DIST;
+ length = MAX_DIST;
+ }
+
+ Array.Copy(buffer, offset, window, strstart, length);
+
+ UpdateHash();
+ --length;
+ while (--length > 0)
+ {
+ InsertString();
+ strstart++;
+ }
+ strstart += 2;
+ blockStart = strstart;
+ }
+
+ /// <summary>
+ /// Reset internal state
+ /// </summary>
+ public void Reset()
+ {
+ huffman.Reset();
+ adler.Reset();
+ blockStart = strstart = 1;
+ lookahead = 0;
+ totalIn = 0;
+ prevAvailable = false;
+ matchLen = MIN_MATCH - 1;
+
+ for (int i = 0; i < HASH_SIZE; i++) {
+ head[i] = 0;
+ }
+
+ for (int i = 0; i < WSIZE; i++) {
+ prev[i] = 0;
+ }
+ }
+
+ /// <summary>
+ /// Reset Adler checksum
+ /// </summary>
+ public void ResetAdler()
+ {
+ adler.Reset();
+ }
+
+ /// <summary>
+ /// Get current value of Adler checksum
+ /// </summary>
+ public int Adler {
+ get {
+ return unchecked((int)adler.Value);
+ }
+ }
+
+ /// <summary>
+ /// Total data processed
+ /// </summary>
+ public int TotalIn {
+ get {
+ return totalIn;
+ }
+ }
+
+ /// <summary>
+ /// Get/set the <see cref="DeflateStrategy">deflate strategy</see>
+ /// </summary>
+ public DeflateStrategy Strategy {
+ get {
+ return strategy;
+ }
+ set {
+ strategy = value;
+ }
+ }
+
+ /// <summary>
+ /// Set the deflate level (0-9)
+ /// </summary>
+ /// <param name="level">The value to set the level to.</param>
+ public void SetLevel(int level)
+ {
+ if ( (level < 0) || (level > 9) )
+ {
+ throw new ArgumentOutOfRangeException("level");
+ }
+
+ goodLength = GOOD_LENGTH[level];
+ max_lazy = MAX_LAZY[level];
+ niceLength = NICE_LENGTH[level];
+ max_chain = MAX_CHAIN[level];
+
+ if (COMPR_FUNC[level] == compressionFunction)
+ {
+ return;
+ }
+
+ switch (compressionFunction) {
+ case DEFLATE_STORED:
+ if (strstart > blockStart) {
+ huffman.FlushStoredBlock(window, blockStart,
+ strstart - blockStart, false);
+ blockStart = strstart;
+ }
+ UpdateHash();
+ break;
+
+ case DEFLATE_FAST:
+ if (strstart > blockStart) {
+ huffman.FlushBlock(window, blockStart, strstart - blockStart,
+ false);
+ blockStart = strstart;
+ }
+ break;
+
+ case DEFLATE_SLOW:
+ if (prevAvailable) {
+ huffman.TallyLit(window[strstart-1] & 0xff);
+ }
+ if (strstart > blockStart) {
+ huffman.FlushBlock(window, blockStart, strstart - blockStart, false);
+ blockStart = strstart;
+ }
+ prevAvailable = false;
+ matchLen = MIN_MATCH - 1;
+ break;
+ }
+ compressionFunction = COMPR_FUNC[level];
+ }
+
+ /// <summary>
+ /// Fill the window
+ /// </summary>
+ public void FillWindow()
+ {
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ if (strstart >= WSIZE + MAX_DIST)
+ {
+ SlideWindow();
+ }
+
+ /* If there is not enough lookahead, but still some input left,
+ * read in the input
+ */
+ while (lookahead < MIN_LOOKAHEAD && inputOff < inputEnd)
+ {
+ int more = 2 * WSIZE - lookahead - strstart;
+
+ if (more > inputEnd - inputOff)
+ {
+ more = inputEnd - inputOff;
+ }
+
+ Array.Copy(inputBuf, inputOff, window, strstart + lookahead, more);
+ adler.Update(inputBuf, inputOff, more);
+
+ inputOff += more;
+ totalIn += more;
+ lookahead += more;
+ }
+
+ if (lookahead >= MIN_MATCH)
+ {
+ UpdateHash();
+ }
+ }
+
+ void UpdateHash()
+ {
+/*
+ if (DEBUGGING) {
+ Console.WriteLine("updateHash: "+strstart);
+ }
+*/
+ ins_h = (window[strstart] << HASH_SHIFT) ^ window[strstart + 1];
+ }
+
+ /// <summary>
+ /// Inserts the current string in the head hash and returns the previous
+ /// value for this hash.
+ /// </summary>
+ /// <returns>The previous hash value</returns>
+ int InsertString()
+ {
+ short match;
+ var hash = ((ins_h << HASH_SHIFT) ^ window[strstart + (MIN_MATCH -1)]) & HASH_MASK;
+ prev[strstart & WMASK] = match = head[hash];
+ head[hash] = unchecked((short)strstart);
+ ins_h = hash;
+ return match & 0xffff;
+ }
+
+ void SlideWindow()
+ {
+ Array.Copy(window, WSIZE, window, 0, WSIZE);
+ matchStart -= WSIZE;
+ strstart -= WSIZE;
+ blockStart -= WSIZE;
+
+ // Slide the hash table (could be avoided with 32 bit values
+ // at the expense of memory usage).
+ for (int i = 0; i < HASH_SIZE; ++i) {
+ int m = head[i] & 0xffff;
+ head[i] = (short)(m >= WSIZE ? (m - WSIZE) : 0);
+ }
+
+ // Slide the prev table.
+ for (int i = 0; i < WSIZE; i++) {
+ int m = prev[i] & 0xffff;
+ prev[i] = (short)(m >= WSIZE ? (m - WSIZE) : 0);
+ }
+ }
+
+ /// <summary>
+ /// Find the best (longest) string in the window matching the
+ /// string starting at strstart.
+ ///
+ /// Preconditions:
+ /// <code>
+ /// strstart + MAX_MATCH <= window.length.</code>
+ /// </summary>
+ /// <param name="curMatch"></param>
+ /// <returns>True if a match greater than the minimum length is found</returns>
+ bool FindLongestMatch(int curMatch)
+ {
+ var chainLength = max_chain;
+ var niceLength = this.niceLength;
+ var prev = this.prev;
+ var scan = strstart;
+ var best_end = strstart + matchLen;
+ var best_len = Math.Max(matchLen, MIN_MATCH - 1);
+
+ int limit = Math.Max(strstart - MAX_DIST, 0);
+
+ int strend = strstart + MAX_MATCH - 1;
+ byte scan_end1 = window[best_end - 1];
+ byte scan_end = window[best_end];
+
+ // Do not waste too much time if we already have a good match:
+ if (best_len >= goodLength) {
+ chainLength >>= 2;
+ }
+
+ /* Do not look for matches beyond the end of the input. This is necessary
+ * to make deflate deterministic.
+ */
+ if (niceLength > lookahead) {
+ niceLength = lookahead;
+ }
+
+ do {
+ if (window[curMatch + best_len] != scan_end ||
+ window[curMatch + best_len - 1] != scan_end1 ||
+ window[curMatch] != window[scan] ||
+ window[curMatch + 1] != window[scan + 1]) {
+ continue;
+ }
+
+ int match = curMatch + 2;
+ scan += 2;
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart + 258.
+ */
+ while (
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ (scan < strend))
+ {
+ // Do nothing
+ }
+
+ if (scan > best_end) {
+ matchStart = curMatch;
+ best_end = scan;
+ best_len = scan - strstart;
+
+ if (best_len >= niceLength) {
+ break;
+ }
+
+ scan_end1 = window[best_end - 1];
+ scan_end = window[best_end];
+ }
+ scan = strstart;
+ } while ((curMatch = (prev[curMatch & WMASK] & 0xffff)) > limit && --chainLength != 0);
+
+ matchLen = Math.Min(best_len, lookahead);
+ return matchLen >= MIN_MATCH;
+ }
+
+ bool DeflateStored(bool flush, bool finish)
+ {
+ if (!flush && (lookahead == 0)) {
+ return false;
+ }
+
+ strstart += lookahead;
+ lookahead = 0;
+
+ int storedLength = strstart - blockStart;
+
+ if ((storedLength >= MAX_BLOCK_SIZE) || // Block is full
+ (blockStart < WSIZE && storedLength >= MAX_DIST) || // Block may move out of window
+ flush) {
+ bool lastBlock = finish;
+ if (storedLength > MAX_BLOCK_SIZE) {
+ storedLength = MAX_BLOCK_SIZE;
+ lastBlock = false;
+ }
+
+ huffman.FlushStoredBlock(window, blockStart, storedLength, lastBlock);
+ blockStart += storedLength;
+ return !lastBlock;
+ }
+ return true;
+ }
+
+ bool DeflateFast(bool flush, bool finish)
+ {
+ if (lookahead < MIN_LOOKAHEAD && !flush) {
+ return false;
+ }
+
+ while (lookahead >= MIN_LOOKAHEAD || flush) {
+ if (lookahead == 0) {
+ // We are flushing everything
+ huffman.FlushBlock(window, blockStart, strstart - blockStart, finish);
+ blockStart = strstart;
+ return false;
+ }
+
+ if (strstart > 2 * WSIZE - MIN_LOOKAHEAD) {
+ /* slide window, as FindLongestMatch needs this.
+ * This should only happen when flushing and the window
+ * is almost full.
+ */
+ SlideWindow();
+ }
+
+ int hashHead;
+ if (lookahead >= MIN_MATCH &&
+ (hashHead = InsertString()) != 0 &&
+ strategy != DeflateStrategy.HuffmanOnly &&
+ strstart - hashHead <= MAX_DIST &&
+ FindLongestMatch(hashHead)) {
+ // longestMatch sets matchStart and matchLen
+ var full = huffman.TallyDist(strstart - matchStart, matchLen);
+
+ lookahead -= matchLen;
+ if (matchLen <= max_lazy && lookahead >= MIN_MATCH) {
+ while (--matchLen > 0) {
+ ++strstart;
+ InsertString();
+ }
+ ++strstart;
+ } else {
+ strstart += matchLen;
+ if (lookahead >= MIN_MATCH - 1) {
+ UpdateHash();
+ }
+ }
+ matchLen = MIN_MATCH - 1;
+ if (!full) {
+ continue;
+ }
+ } else {
+ // No match found
+ huffman.TallyLit(window[strstart] & 0xff);
+ ++strstart;
+ --lookahead;
+ }
+
+ if (huffman.IsFull()) {
+ bool lastBlock = finish && (lookahead == 0);
+ huffman.FlushBlock(window, blockStart, strstart - blockStart, lastBlock);
+ blockStart = strstart;
+ return !lastBlock;
+ }
+ }
+ return true;
+ }
+
+ bool DeflateSlow(bool flush, bool finish)
+ {
+ if (lookahead < MIN_LOOKAHEAD && !flush) {
+ return false;
+ }
+
+ while (lookahead >= MIN_LOOKAHEAD || flush) {
+ if (lookahead == 0) {
+ if (prevAvailable) {
+ huffman.TallyLit(window[strstart-1] & 0xff);
+ }
+ prevAvailable = false;
+
+ // We are flushing everything
+ huffman.FlushBlock(window, blockStart, strstart - blockStart,
+ finish);
+ blockStart = strstart;
+ return false;
+ }
+
+ if (strstart >= 2 * WSIZE - MIN_LOOKAHEAD) {
+ /* slide window, as FindLongestMatch needs this.
+ * This should only happen when flushing and the window
+ * is almost full.
+ */
+ SlideWindow();
+ }
+
+ int prevMatch = matchStart;
+ int prevLen = matchLen;
+ if (lookahead >= MIN_MATCH) {
+
+ int hashHead = InsertString();
+
+ if (strategy != DeflateStrategy.HuffmanOnly &&
+ hashHead != 0 &&
+ strstart - hashHead <= MAX_DIST &&
+ FindLongestMatch(hashHead)) {
+
+ // longestMatch sets matchStart and matchLen
+
+ // Discard match if too small and too far away
+ if (matchLen <= 5 && (strategy == DeflateStrategy.Filtered || (matchLen == MIN_MATCH && strstart - matchStart > TooFar))) {
+ matchLen = MIN_MATCH - 1;
+ }
+ }
+ }
+
+ // previous match was better
+ if ((prevLen >= MIN_MATCH) && (matchLen <= prevLen) ) {
+ huffman.TallyDist(strstart - 1 - prevMatch, prevLen);
+ prevLen -= 2;
+ do {
+ strstart++;
+ lookahead--;
+ if (lookahead >= MIN_MATCH) {
+ InsertString();
+ }
+ } while (--prevLen > 0);
+
+ strstart ++;
+ lookahead--;
+ prevAvailable = false;
+ matchLen = MIN_MATCH - 1;
+ } else {
+ if (prevAvailable) {
+ huffman.TallyLit(window[strstart-1] & 0xff);
+ }
+ prevAvailable = true;
+ strstart++;
+ lookahead--;
+ }
+
+ if (huffman.IsFull()) {
+ int len = strstart - blockStart;
+ if (prevAvailable) {
+ len--;
+ }
+ bool lastBlock = (finish && (lookahead == 0) && !prevAvailable);
+ huffman.FlushBlock(window, blockStart, len, lastBlock);
+ blockStart += len;
+ return !lastBlock;
+ }
+ }
+ return true;
+ }
+
+ #region Instance Fields
+
+ // Hash index of string to be inserted
+ int ins_h;
+
+ /// <summary>
+ /// Hashtable, hashing three characters to an index for window, so
+ /// that window[index]..window[index+2] have this hash code.
+ /// Note that the array should really be unsigned short, so you need
+ /// to and the values with 0xffff.
+ /// </summary>
+ readonly short[] head;
+
+ /// <summary>
+ /// <code>prev[index & WMASK]</code> points to the previous index that has the
+ /// same hash code as the string starting at index. This way
+ /// entries with the same hash code are in a linked list.
+ /// Note that the array should really be unsigned short, so you need
+ /// to and the values with 0xffff.
+ /// </summary>
+ readonly short[] prev;
+
+ int matchStart;
+ // Length of best match
+ int matchLen;
+ // Set if previous match exists
+ bool prevAvailable;
+ int blockStart;
+
+ /// <summary>
+ /// Points to the current character in the window.
+ /// </summary>
+ int strstart;
+
+ /// <summary>
+ /// lookahead is the number of characters starting at strstart in
+ /// window that are valid.
+ /// So window[strstart] until window[strstart+lookahead-1] are valid
+ /// characters.
+ /// </summary>
+ int lookahead;
+
+ /// <summary>
+ /// This array contains the part of the uncompressed stream that
+ /// is of relevance. The current character is indexed by strstart.
+ /// </summary>
+ readonly byte[] window;
+
+ DeflateStrategy strategy;
+ int max_chain, max_lazy, niceLength, goodLength;
+
+ /// <summary>
+ /// The current compression function.
+ /// </summary>
+ int compressionFunction;
+
+ /// <summary>
+ /// The input data for compression.
+ /// </summary>
+ byte[] inputBuf;
+
+ /// <summary>
+ /// The total bytes of input read.
+ /// </summary>
+ int totalIn;
+
+ /// <summary>
+ /// The offset into inputBuf, where input data starts.
+ /// </summary>
+ int inputOff;
+
+ /// <summary>
+ /// The end offset of the input data.
+ /// </summary>
+ int inputEnd;
+
+ readonly DeflaterPending pending;
+ readonly DeflaterHuffman huffman;
+
+ /// <summary>
+ /// The adler checksum
+ /// </summary>
+ readonly Adler32 adler;
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+// DeflaterHuffman.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip.Compression
+{
+ /// <summary>
+ /// This is the DeflaterHuffman class.
+ ///
+ /// This class is <i>not</i> thread safe. This is inherent in the API, due
+ /// to the split of Deflate and SetInput.
+ ///
+ /// author of the original java version : Jochen Hoenicke
+ /// </summary>
+ public class DeflaterHuffman
+ {
+ const int BUFSIZE = 1 << (DeflaterConstants.DEFAULT_MEM_LEVEL + 6);
+ const int LITERAL_NUM = 286;
+
+ // Number of distance codes
+ const int DIST_NUM = 30;
+ // Number of codes used to transfer bit lengths
+ const int BITLEN_NUM = 19;
+
+ // repeat previous bit length 3-6 times (2 bits of repeat count)
+ const int REP_3_6 = 16;
+ // repeat a zero length 3-10 times (3 bits of repeat count)
+ const int REP_3_10 = 17;
+ // repeat a zero length 11-138 times (7 bits of repeat count)
+ const int REP_11_138 = 18;
+
+ const int EOF_SYMBOL = 256;
+
+ // The lengths of the bit length codes are sent in order of decreasing
+ // probability, to avoid transmitting the lengths for unused bit length codes.
+ static readonly int[] BL_ORDER = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
+
+ static readonly byte[] bit4Reverse = {
+ 0,
+ 8,
+ 4,
+ 12,
+ 2,
+ 10,
+ 6,
+ 14,
+ 1,
+ 9,
+ 5,
+ 13,
+ 3,
+ 11,
+ 7,
+ 15
+ };
+
+ static readonly short[] staticLCodes;
+ static readonly byte[] staticLLength;
+ static readonly short[] staticDCodes;
+ static readonly byte[] staticDLength;
+
+ class Tree
+ {
+ #region Instance Fields
+ public readonly short[] freqs;
+
+ public byte[] length;
+
+ public readonly int minNumCodes;
+
+ public int numCodes;
+
+ short[] codes;
+ readonly int[] bl_counts;
+ readonly int maxLength;
+ readonly DeflaterHuffman dh;
+ #endregion
+
+ #region Constructors
+ public Tree(DeflaterHuffman dh, int elems, int minCodes, int maxLength)
+ {
+ this.dh = dh;
+ minNumCodes = minCodes;
+ this.maxLength = maxLength;
+ freqs = new short[elems];
+ bl_counts = new int[maxLength];
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Resets the internal state of the tree
+ /// </summary>
+ public void Reset()
+ {
+ for (int i = 0; i < freqs.Length; i++) {
+ freqs[i] = 0;
+ }
+ codes = null;
+ length = null;
+ }
+
+ public void WriteSymbol(int code)
+ {
+ // if (DeflaterConstants.DEBUGGING) {
+ // freqs[code]--;
+ // // Console.Write("writeSymbol("+freqs.length+","+code+"): ");
+ // }
+ dh.pending.WriteBits(codes[code] & 0xffff, length[code]);
+ }
+
+ /// <summary>
+ /// Set static codes and length
+ /// </summary>
+ /// <param name="staticCodes">new codes</param>
+ /// <param name="staticLengths">length for new codes</param>
+ public void SetStaticCodes(short[] staticCodes, byte[] staticLengths)
+ {
+ codes = staticCodes;
+ length = staticLengths;
+ }
+
+ /// <summary>
+ /// Build dynamic codes and lengths
+ /// </summary>
+ public void BuildCodes()
+ {
+ var nextCode = new int[maxLength];
+ var code = 0;
+
+ codes = new short[freqs.Length];
+
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("buildCodes: "+freqs.Length);
+ // }
+
+ for (int bits = 0; bits < maxLength; bits++) {
+ nextCode[bits] = code;
+ code += bl_counts[bits] << (15 - bits);
+
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("bits: " + ( bits + 1) + " count: " + bl_counts[bits]
+ // +" nextCode: "+code);
+ // }
+ }
+ for (int i=0; i < numCodes; i++) {
+ int bits = length[i];
+ if (bits > 0) {
+
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("codes["+i+"] = rev(" + nextCode[bits-1]+"),
+ // +bits);
+ // }
+
+ codes[i] = BitReverse(nextCode[bits-1]);
+ nextCode[bits-1] += 1 << (16 - bits);
+ }
+ }
+ }
+
+ public void BuildTree()
+ {
+ int numSymbols = freqs.Length;
+
+ /* heap is a priority queue, sorted by frequency, least frequent
+ * nodes first. The heap is a binary tree, with the property, that
+ * the parent node is smaller than both child nodes. This assures
+ * that the smallest node is the first parent.
+ *
+ * The binary tree is encoded in an array: 0 is root node and
+ * the nodes 2*n+1, 2*n+2 are the child nodes of node n.
+ */
+ var heap = new int[numSymbols];
+ var heapLen = 0;
+ var maxCode = 0;
+ for (var n = 0; n < numSymbols; n++) {
+ int freq = freqs[n];
+ if (freq == 0)
+ {
+ continue;
+ }
+
+ // Insert n into heap
+ var pos = heapLen++;
+ int ppos;
+ while (pos > 0 && freqs[heap[ppos = (pos - 1) / 2]] > freq) {
+ heap[pos] = heap[ppos];
+ pos = ppos;
+ }
+ heap[pos] = n;
+
+ maxCode = n;
+ }
+
+ /* We could encode a single literal with 0 bits but then we
+ * don't see the literals. Therefore we force at least two
+ * literals to avoid this case. We don't care about order in
+ * this case, both literals get a 1 bit code.
+ */
+ while (heapLen < 2) {
+ int node = maxCode < 2 ? ++maxCode : 0;
+ heap[heapLen++] = node;
+ }
+
+ numCodes = Math.Max(maxCode + 1, minNumCodes);
+
+ var numLeafs = heapLen;
+ var childs = new int[4 * heapLen - 2];
+ var values = new int[2 * heapLen - 1];
+ var numNodes = numLeafs;
+ for (var i = 0; i < heapLen; i++) {
+ var node = heap[i];
+ childs[2 * i] = node;
+ childs[2 * i + 1] = -1;
+ values[i] = freqs[node] << 8;
+ heap[i] = i;
+ }
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ do {
+ int first = heap[0];
+ int last = heap[--heapLen];
+
+ // Propagate the hole to the leafs of the heap
+ int ppos = 0;
+ int path = 1;
+
+ while (path < heapLen) {
+ if (path + 1 < heapLen && values[heap[path]] > values[heap[path+1]]) {
+ path++;
+ }
+
+ heap[ppos] = heap[path];
+ ppos = path;
+ path = path * 2 + 1;
+ }
+
+ /* Now propagate the last element down along path. Normally
+ * it shouldn't go too deep.
+ */
+ int lastVal = values[last];
+ while ((path = ppos) > 0 && values[heap[ppos = (path - 1)/2]] > lastVal) {
+ heap[path] = heap[ppos];
+ }
+ heap[path] = last;
+
+
+ int second = heap[0];
+
+ // Create a new node father of first and second
+ last = numNodes++;
+ childs[2 * last] = first;
+ childs[2 * last + 1] = second;
+ int mindepth = Math.Min(values[first] & 0xff, values[second] & 0xff);
+ values[last] = lastVal = values[first] + values[second] - mindepth + 1;
+
+ // Again, propagate the hole to the leafs
+ ppos = 0;
+ path = 1;
+
+ while (path < heapLen) {
+ if (path + 1 < heapLen && values[heap[path]] > values[heap[path+1]]) {
+ path++;
+ }
+
+ heap[ppos] = heap[path];
+ ppos = path;
+ path = ppos * 2 + 1;
+ }
+
+ // Now propagate the new element down along path
+ while ((path = ppos) > 0 && values[heap[ppos = (path - 1)/2]] > lastVal) {
+ heap[path] = heap[ppos];
+ }
+ heap[path] = last;
+ } while (heapLen > 1);
+
+ if (heap[0] != childs.Length / 2 - 1) {
+ throw new SharpZipBaseException("Heap invariant violated");
+ }
+
+ BuildLength(childs);
+ }
+
+ /// <summary>
+ /// Get encoded length
+ /// </summary>
+ /// <returns>Encoded length, the sum of frequencies * lengths</returns>
+ public int GetEncodedLength()
+ {
+ int len = 0;
+ for (int i = 0; i < freqs.Length; i++) {
+ len += freqs[i] * length[i];
+ }
+ return len;
+ }
+
+ /// <summary>
+ /// Scan a literal or distance tree to determine the frequencies of the codes
+ /// in the bit length tree.
+ /// </summary>
+ public void CalcBLFreq(Tree blTree)
+ {
+ var curlen = -1; /* length of current code */
+ var i = 0;
+
+ while (i < numCodes) {
+ var count = 1; /* repeat count of the current code */
+ int nextlen = length[i];
+ int max_count; /* max repeat count */
+ int min_count; /* min repeat count */
+ if (nextlen == 0) {
+ max_count = 138;
+ min_count = 3;
+ } else {
+ max_count = 6;
+ min_count = 3;
+ if (curlen != nextlen) {
+ blTree.freqs[nextlen]++;
+ count = 0;
+ }
+ }
+ curlen = nextlen;
+ i++;
+
+ while (i < numCodes && curlen == length[i]) {
+ i++;
+ if (++count >= max_count) {
+ break;
+ }
+ }
+
+ if (count < min_count) {
+ blTree.freqs[curlen] += (short)count;
+ } else if (curlen != 0) {
+ blTree.freqs[REP_3_6]++;
+ } else if (count <= 10) {
+ blTree.freqs[REP_3_10]++;
+ } else {
+ blTree.freqs[REP_11_138]++;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Write tree values
+ /// </summary>
+ /// <param name="blTree">Tree to write</param>
+ public void WriteTree(Tree blTree)
+ {
+ var curlen = -1; // length of current code
+
+ var i = 0;
+ while (i < numCodes) {
+ var count = 1; // repeat count of the current code
+ int nextlen = length[i];
+ int max_count; // max repeat count
+ int min_count; // min repeat count
+ if (nextlen == 0) {
+ max_count = 138;
+ min_count = 3;
+ } else {
+ max_count = 6;
+ min_count = 3;
+ if (curlen != nextlen) {
+ blTree.WriteSymbol(nextlen);
+ count = 0;
+ }
+ }
+ curlen = nextlen;
+ i++;
+
+ while (i < numCodes && curlen == length[i]) {
+ i++;
+ if (++count >= max_count) {
+ break;
+ }
+ }
+
+ if (count < min_count) {
+ while (count-- > 0) {
+ blTree.WriteSymbol(curlen);
+ }
+ } else if (curlen != 0) {
+ blTree.WriteSymbol(REP_3_6);
+ dh.pending.WriteBits(count - 3, 2);
+ } else if (count <= 10) {
+ blTree.WriteSymbol(REP_3_10);
+ dh.pending.WriteBits(count - 3, 3);
+ } else {
+ blTree.WriteSymbol(REP_11_138);
+ dh.pending.WriteBits(count - 11, 7);
+ }
+ }
+ }
+
+ void BuildLength(int[] childs)
+ {
+ length = new byte [freqs.Length];
+ var numNodes = childs.Length / 2;
+ var numLeafs = (numNodes + 1) / 2;
+ var overflow = 0;
+
+ for (var i = 0; i < maxLength; i++) {
+ bl_counts[i] = 0;
+ }
+
+ // First calculate optimal bit lengths
+ var lengths = new int[numNodes];
+ lengths[numNodes-1] = 0;
+
+ for (int i = numNodes - 1; i >= 0; i--) {
+ if (childs[2 * i + 1] != -1) {
+ int bitLength = lengths[i] + 1;
+ if (bitLength > maxLength) {
+ bitLength = maxLength;
+ overflow++;
+ }
+ lengths[childs[2 * i]] = lengths[childs[2 * i + 1]] = bitLength;
+ } else {
+ // A leaf node
+ var bitLength = lengths[i];
+ bl_counts[bitLength - 1]++;
+ length[childs[2*i]] = (byte) lengths[i];
+ }
+ }
+
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("Tree "+freqs.Length+" lengths:");
+ // for (int i=0; i < numLeafs; i++) {
+ // //Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]
+ // + " len: "+length[childs[2*i]]);
+ // }
+ // }
+
+ if (overflow == 0) {
+ return;
+ }
+
+ int incrBitLen = maxLength - 1;
+ do {
+ // Find the first bit length which could increase:
+ while (bl_counts[--incrBitLen] == 0)
+ {
+
+ }
+
+ // Move this node one down and remove a corresponding
+ // number of overflow nodes.
+ do {
+ bl_counts[incrBitLen]--;
+ bl_counts[++incrBitLen]++;
+ overflow -= 1 << (maxLength - 1 - incrBitLen);
+ } while (overflow > 0 && incrBitLen < maxLength - 1);
+ } while (overflow > 0);
+
+ /* We may have overshot above. Move some nodes from maxLength to
+ * maxLength-1 in that case.
+ */
+ bl_counts[maxLength-1] += overflow;
+ bl_counts[maxLength-2] -= overflow;
+
+ /* Now recompute all bit lengths, scanning in increasing
+ * frequency. It is simpler to reconstruct all lengths instead of
+ * fixing only the wrong ones. This idea is taken from 'ar'
+ * written by Haruhiko Okumura.
+ *
+ * The nodes were inserted with decreasing frequency into the childs
+ * array.
+ */
+ int nodePtr = 2 * numLeafs;
+ for (int bits = maxLength; bits != 0; bits--) {
+ int n = bl_counts[bits-1];
+ while (n > 0) {
+ int childPtr = 2*childs[nodePtr++];
+ if (childs[childPtr + 1] == -1) {
+ // We found another leaf
+ length[childs[childPtr]] = (byte) bits;
+ n--;
+ }
+ }
+ }
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("*** After overflow elimination. ***");
+ // for (int i=0; i < numLeafs; i++) {
+ // //Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]
+ // + " len: "+length[childs[2*i]]);
+ // }
+ // }
+ }
+
+ }
+
+ #region Instance Fields
+ /// <summary>
+ /// Pending buffer to use
+ /// </summary>
+ public DeflaterPending pending;
+
+ readonly Tree literalTree;
+ readonly Tree distTree;
+ readonly Tree blTree;
+
+ // Buffer for distances
+ readonly short[] d_buf;
+ readonly byte[] l_buf;
+ int last_lit;
+ int extra_bits;
+ #endregion
+
+ static DeflaterHuffman()
+ {
+ // See RFC 1951 3.2.6
+ // Literal codes
+ staticLCodes = new short[LITERAL_NUM];
+ staticLLength = new byte[LITERAL_NUM];
+
+ int i = 0;
+ while (i < 144) {
+ staticLCodes[i] = BitReverse((0x030 + i) << 8);
+ staticLLength[i++] = 8;
+ }
+
+ while (i < 256) {
+ staticLCodes[i] = BitReverse((0x190 - 144 + i) << 7);
+ staticLLength[i++] = 9;
+ }
+
+ while (i < 280) {
+ staticLCodes[i] = BitReverse((0x000 - 256 + i) << 9);
+ staticLLength[i++] = 7;
+ }
+
+ while (i < LITERAL_NUM) {
+ staticLCodes[i] = BitReverse((0x0c0 - 280 + i) << 8);
+ staticLLength[i++] = 8;
+ }
+
+ // Distance codes
+ staticDCodes = new short[DIST_NUM];
+ staticDLength = new byte[DIST_NUM];
+ for (i = 0; i < DIST_NUM; i++) {
+ staticDCodes[i] = BitReverse(i << 11);
+ staticDLength[i] = 5;
+ }
+ }
+
+ /// <summary>
+ /// Construct instance with pending buffer
+ /// </summary>
+ /// <param name="pending">Pending buffer to use</param>
+ public DeflaterHuffman(DeflaterPending pending)
+ {
+ this.pending = pending;
+
+ literalTree = new Tree(this, LITERAL_NUM, 257, 15);
+ distTree = new Tree(this, DIST_NUM, 1, 15);
+ blTree = new Tree(this, BITLEN_NUM, 4, 7);
+
+ d_buf = new short[BUFSIZE];
+ l_buf = new byte [BUFSIZE];
+ }
+
+ /// <summary>
+ /// Reset internal state
+ /// </summary>
+ public void Reset()
+ {
+ last_lit = 0;
+ extra_bits = 0;
+ literalTree.Reset();
+ distTree.Reset();
+ blTree.Reset();
+ }
+
+ /// <summary>
+ /// Write all trees to pending buffer
+ /// </summary>
+ /// <param name="blTreeCodes">The number/rank of treecodes to send.</param>
+ public void SendAllTrees(int blTreeCodes)
+ {
+ blTree.BuildCodes();
+ literalTree.BuildCodes();
+ distTree.BuildCodes();
+ pending.WriteBits(literalTree.numCodes - 257, 5);
+ pending.WriteBits(distTree.numCodes - 1, 5);
+ pending.WriteBits(blTreeCodes - 4, 4);
+ for (int rank = 0; rank < blTreeCodes; rank++) {
+ pending.WriteBits(blTree.length[BL_ORDER[rank]], 3);
+ }
+ literalTree.WriteTree(blTree);
+ distTree.WriteTree(blTree);
+ }
+
+ /// <summary>
+ /// Compress current buffer writing data to pending buffer
+ /// </summary>
+ public void CompressBlock()
+ {
+ for (int i = 0; i < last_lit; i++) {
+ int litlen = l_buf[i] & 0xff;
+ int dist = d_buf[i];
+ if (dist-- != 0) {
+ // if (DeflaterConstants.DEBUGGING) {
+ // Console.Write("["+(dist+1)+","+(litlen+3)+"]: ");
+ // }
+
+ int lc = Lcode(litlen);
+ literalTree.WriteSymbol(lc);
+
+ int bits = (lc - 261) / 4;
+ if (bits > 0 && bits <= 5) {
+ pending.WriteBits(litlen & ((1 << bits) - 1), bits);
+ }
+
+ int dc = Dcode(dist);
+ distTree.WriteSymbol(dc);
+
+ bits = dc / 2 - 1;
+ if (bits > 0) {
+ pending.WriteBits(dist & ((1 << bits) - 1), bits);
+ }
+ } else {
+ // if (DeflaterConstants.DEBUGGING) {
+ // if (litlen > 32 && litlen < 127) {
+ // Console.Write("("+(char)litlen+"): ");
+ // } else {
+ // Console.Write("{"+litlen+"}: ");
+ // }
+ // }
+ literalTree.WriteSymbol(litlen);
+ }
+ }
+ literalTree.WriteSymbol(EOF_SYMBOL);
+ }
+
+ /// <summary>
+ /// Flush block to output with no compression
+ /// </summary>
+ /// <param name="stored">Data to write</param>
+ /// <param name="storedOffset">Index of first byte to write</param>
+ /// <param name="storedLength">Count of bytes to write</param>
+ /// <param name="lastBlock">True if this is the last block</param>
+ public void FlushStoredBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
+ {
+ pending.WriteBits((DeflaterConstants.STORED_BLOCK << 1) + (lastBlock ? 1 : 0), 3);
+ pending.AlignToByte();
+ pending.WriteShort(storedLength);
+ pending.WriteShort(~storedLength);
+ pending.WriteBlock(stored, storedOffset, storedLength);
+ Reset();
+ }
+
+ /// <summary>
+ /// Flush block to output with compression
+ /// </summary>
+ /// <param name="stored">Data to flush</param>
+ /// <param name="storedOffset">Index of first byte to flush</param>
+ /// <param name="storedLength">Count of bytes to flush</param>
+ /// <param name="lastBlock">True if this is the last block</param>
+ public void FlushBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
+ {
+ literalTree.freqs[EOF_SYMBOL]++;
+
+ // Build trees
+ literalTree.BuildTree();
+ distTree.BuildTree();
+
+ // Calculate bitlen frequency
+ literalTree.CalcBLFreq(blTree);
+ distTree.CalcBLFreq(blTree);
+
+ // Build bitlen tree
+ blTree.BuildTree();
+
+ int blTreeCodes = 4;
+ for (int i = 18; i > blTreeCodes; i--) {
+ if (blTree.length[BL_ORDER[i]] > 0) {
+ blTreeCodes = i+1;
+ }
+ }
+ int opt_len = 14 + blTreeCodes * 3 + blTree.GetEncodedLength() +
+ literalTree.GetEncodedLength() + distTree.GetEncodedLength() +
+ extra_bits;
+
+ int static_len = extra_bits;
+ for (int i = 0; i < LITERAL_NUM; i++) {
+ static_len += literalTree.freqs[i] * staticLLength[i];
+ }
+ for (int i = 0; i < DIST_NUM; i++) {
+ static_len += distTree.freqs[i] * staticDLength[i];
+ }
+ if (opt_len >= static_len) {
+ // Force static trees
+ opt_len = static_len;
+ }
+
+ if (storedOffset >= 0 && storedLength + 4 < opt_len >> 3) {
+ // Store Block
+
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("Storing, since " + storedLength + " < " + opt_len
+ // + " <= " + static_len);
+ // }
+ FlushStoredBlock(stored, storedOffset, storedLength, lastBlock);
+ } else if (opt_len == static_len) {
+ // Encode with static tree
+ pending.WriteBits((DeflaterConstants.STATIC_TREES << 1) + (lastBlock ? 1 : 0), 3);
+ literalTree.SetStaticCodes(staticLCodes, staticLLength);
+ distTree.SetStaticCodes(staticDCodes, staticDLength);
+ CompressBlock();
+ Reset();
+ } else {
+ // Encode with dynamic tree
+ pending.WriteBits((DeflaterConstants.DYN_TREES << 1) + (lastBlock ? 1 : 0), 3);
+ SendAllTrees(blTreeCodes);
+ CompressBlock();
+ Reset();
+ }
+ }
+
+ /// <summary>
+ /// Get value indicating if internal buffer is full
+ /// </summary>
+ /// <returns>true if buffer is full</returns>
+ public bool IsFull()
+ {
+ return last_lit >= BUFSIZE;
+ }
+
+ /// <summary>
+ /// Add literal to buffer
+ /// </summary>
+ /// <param name="literal">Literal value to add to buffer.</param>
+ /// <returns>Value indicating internal buffer is full</returns>
+ public bool TallyLit(int literal)
+ {
+ // if (DeflaterConstants.DEBUGGING) {
+ // if (lit > 32 && lit < 127) {
+ // //Console.WriteLine("("+(char)lit+")");
+ // } else {
+ // //Console.WriteLine("{"+lit+"}");
+ // }
+ // }
+ d_buf[last_lit] = 0;
+ l_buf[last_lit++] = (byte)literal;
+ literalTree.freqs[literal]++;
+ return IsFull();
+ }
+
+ /// <summary>
+ /// Add distance code and length to literal and distance trees
+ /// </summary>
+ /// <param name="distance">Distance code</param>
+ /// <param name="length">Length</param>
+ /// <returns>Value indicating if internal buffer is full</returns>
+ public bool TallyDist(int distance, int length)
+ {
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("[" + distance + "," + length + "]");
+ // }
+
+ d_buf[last_lit] = (short)distance;
+ l_buf[last_lit++] = (byte)(length - 3);
+
+ int lc = Lcode(length - 3);
+ literalTree.freqs[lc]++;
+ if (lc >= 265 && lc < 285) {
+ extra_bits += (lc - 261) / 4;
+ }
+
+ int dc = Dcode(distance - 1);
+ distTree.freqs[dc]++;
+ if (dc >= 4) {
+ extra_bits += dc / 2 - 1;
+ }
+ return IsFull();
+ }
+
+
+ /// <summary>
+ /// Reverse the bits of a 16 bit value.
+ /// </summary>
+ /// <param name="toReverse">Value to reverse bits</param>
+ /// <returns>Value with bits reversed</returns>
+ public static short BitReverse(int toReverse)
+ {
+ return (short) (bit4Reverse[toReverse & 0xF] << 12 |
+ bit4Reverse[(toReverse >> 4) & 0xF] << 8 |
+ bit4Reverse[(toReverse >> 8) & 0xF] << 4 |
+ bit4Reverse[toReverse >> 12]);
+ }
+
+ static int Lcode(int length)
+ {
+ if (length == 255) {
+ return 285;
+ }
+
+ int code = 257;
+ while (length >= 8) {
+ code += 4;
+ length >>= 1;
+ }
+ return code + length;
+ }
+
+ static int Dcode(int distance)
+ {
+ int code = 0;
+ while (distance >= 4) {
+ code += 2;
+ distance >>= 1;
+ }
+ return code + distance;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// DeflaterPending.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip.Compression
+{
+ /// <summary>
+ /// This class stores the pending output of the Deflater.
+ ///
+ /// author of the original java version : Jochen Hoenicke
+ /// </summary>
+ public class DeflaterPending : PendingBuffer
+ {
+ /// <summary>
+ /// Construct instance with default buffer size
+ /// </summary>
+ public DeflaterPending() : base(DeflaterConstants.PENDING_BUF_SIZE)
+ {
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// Inflater.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using ICSharpCode.SharpZipLib.Silverlight.Checksums;
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression;
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression.Streams;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip.Compression
+{
+ /// <summary>
+ /// Inflater is used to decompress data that has been compressed according
+ /// to the "deflate" standard described in rfc1951.
+ ///
+ /// By default Zlib (rfc1950) headers and footers are expected in the input.
+ /// You can use constructor <code> public Inflater(bool noHeader)</code> passing true
+ /// if there is no Zlib header information
+ ///
+ /// The usage is as following. First you have to set some input with
+ /// <code>SetInput()</code>, then Inflate() it. If inflate doesn't
+ /// inflate any bytes there may be three reasons:
+ /// <ul>
+ /// <li>IsNeedingInput() returns true because the input buffer is empty.
+ /// You have to provide more input with <code>SetInput()</code>.
+ /// NOTE: IsNeedingInput() also returns true when, the stream is finished.
+ /// </li>
+ /// <li>IsNeedingDictionary() returns true, you have to provide a preset
+ /// dictionary with <code>SetDictionary()</code>.</li>
+ /// <li>IsFinished returns true, the inflater has finished.</li>
+ /// </ul>
+ /// Once the first output byte is produced, a dictionary will not be
+ /// needed at a later stage.
+ ///
+ /// author of the original java version : John Leuner, Jochen Hoenicke
+ /// </summary>
+ public class Inflater
+ {
+ #region Constants/Readonly
+ /// <summary>
+ /// Copy lengths for literal codes 257..285
+ /// </summary>
+ static readonly int[] CPLENS = {
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
+ };
+
+ /// <summary>
+ /// Extra bits for literal codes 257..285
+ /// </summary>
+ static readonly int[] CPLEXT = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
+ };
+
+ /// <summary>
+ /// Copy offsets for distance codes 0..29
+ /// </summary>
+ static readonly int[] CPDIST = {
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577
+ };
+
+ /// <summary>
+ /// Extra bits for distance codes
+ /// </summary>
+ static readonly int[] CPDEXT = {
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13
+ };
+
+ /// <summary>
+ /// These are the possible states for an inflater
+ /// </summary>
+ const int DECODE_HEADER = 0;
+ const int DECODE_DICT = 1;
+ const int DECODE_BLOCKS = 2;
+ const int DECODE_STORED_LEN1 = 3;
+ const int DECODE_STORED_LEN2 = 4;
+ const int DECODE_STORED = 5;
+ const int DECODE_DYN_HEADER = 6;
+ const int DECODE_HUFFMAN = 7;
+ const int DECODE_HUFFMAN_LENBITS = 8;
+ const int DECODE_HUFFMAN_DIST = 9;
+ const int DECODE_HUFFMAN_DISTBITS = 10;
+ const int DECODE_CHKSUM = 11;
+ const int FINISHED = 12;
+ #endregion
+
+ #region Instance Fields
+ /// <summary>
+ /// This variable contains the current state.
+ /// </summary>
+ int mode;
+
+ /// <summary>
+ /// The adler checksum of the dictionary or of the decompressed
+ /// stream, as it is written in the header resp. footer of the
+ /// compressed stream.
+ /// Only valid if mode is DECODE_DICT or DECODE_CHKSUM.
+ /// </summary>
+ int readAdler;
+
+ /// <summary>
+ /// The number of bits needed to complete the current state. This
+ /// is valid, if mode is DECODE_DICT, DECODE_CHKSUM,
+ /// DECODE_HUFFMAN_LENBITS or DECODE_HUFFMAN_DISTBITS.
+ /// </summary>
+ int neededBits;
+ int repLength;
+ int repDist;
+ int uncomprLen;
+
+ /// <summary>
+ /// True, if the last block flag was set in the last block of the
+ /// inflated stream. This means that the stream ends after the
+ /// current block.
+ /// </summary>
+ bool isLastBlock;
+
+ /// <summary>
+ /// The total number of inflated bytes.
+ /// </summary>
+ long totalOut;
+
+ /// <summary>
+ /// The total number of bytes set with setInput(). This is not the
+ /// value returned by the TotalIn property, since this also includes the
+ /// unprocessed input.
+ /// </summary>
+ long totalIn;
+
+ /// <summary>
+ /// This variable stores the noHeader flag that was given to the constructor.
+ /// True means, that the inflated stream doesn't contain a Zlib header or
+ /// footer.
+ /// </summary>
+ bool noHeader;
+
+ StreamManipulator input;
+ OutputWindow outputWindow;
+ InflaterDynHeader dynHeader;
+ InflaterHuffmanTree litlenTree, distTree;
+ Adler32 adler;
+ #endregion
+
+ #region Constructors
+ /// <summary>
+ /// Creates a new inflater or RFC1951 decompressor
+ /// RFC1950/Zlib headers and footers will be expected in the input data
+ /// </summary>
+ public Inflater() : this(false)
+ {
+ }
+
+ /// <summary>
+ /// Creates a new inflater.
+ /// </summary>
+ /// <param name="noHeader">
+ /// True if no RFC1950/Zlib header and footer fields are expected in the input data
+ ///
+ /// This is used for GZIPed/Zipped input.
+ ///
+ /// For compatibility with
+ /// Sun JDK you should provide one byte of input more than needed in
+ /// this case.
+ /// </param>
+ public Inflater(bool noHeader)
+ {
+ this.noHeader = noHeader;
+ this.adler = new Adler32();
+ input = new StreamManipulator();
+ outputWindow = new OutputWindow();
+ mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER;
+ }
+ #endregion
+
+ /// <summary>
+ /// Resets the inflater so that a new stream can be decompressed. All
+ /// pending input and output will be discarded.
+ /// </summary>
+ public void Reset()
+ {
+ mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER;
+ totalIn = 0;
+ totalOut = 0;
+ input.Reset();
+ outputWindow.Reset();
+ dynHeader = null;
+ litlenTree = null;
+ distTree = null;
+ isLastBlock = false;
+ adler.Reset();
+ }
+
+ /// <summary>
+ /// Decodes a zlib/RFC1950 header.
+ /// </summary>
+ /// <returns>
+ /// False if more input is needed.
+ /// </returns>
+ /// <exception cref="SharpZipBaseException">
+ /// The header is invalid.
+ /// </exception>
+ private bool DecodeHeader()
+ {
+ int header = input.PeekBits(16);
+ if (header < 0) {
+ return false;
+ }
+ input.DropBits(16);
+
+ // The header is written in "wrong" byte order
+ header = ((header << 8) | (header >> 8)) & 0xffff;
+ if (header % 31 != 0) {
+ throw new SharpZipBaseException("Header checksum illegal");
+ }
+
+ if ((header & 0x0f00) != (Deflater.DEFLATED << 8)) {
+ throw new SharpZipBaseException("Compression Method unknown");
+ }
+
+ /* Maximum size of the backwards window in bits.
+ * We currently ignore this, but we could use it to make the
+ * inflater window more space efficient. On the other hand the
+ * full window (15 bits) is needed most times, anyway.
+ int max_wbits = ((header & 0x7000) >> 12) + 8;
+ */
+
+ if ((header & 0x0020) == 0) { // Dictionary flag?
+ mode = DECODE_BLOCKS;
+ } else {
+ mode = DECODE_DICT;
+ neededBits = 32;
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// Decodes the dictionary checksum after the deflate header.
+ /// </summary>
+ /// <returns>
+ /// False if more input is needed.
+ /// </returns>
+ private bool DecodeDict()
+ {
+ while (neededBits > 0) {
+ int dictByte = input.PeekBits(8);
+ if (dictByte < 0) {
+ return false;
+ }
+ input.DropBits(8);
+ readAdler = (readAdler << 8) | dictByte;
+ neededBits -= 8;
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Decodes the huffman encoded symbols in the input stream.
+ /// </summary>
+ /// <returns>
+ /// false if more input is needed, true if output window is
+ /// full or the current block ends.
+ /// </returns>
+ /// <exception cref="SharpZipBaseException">
+ /// if deflated stream is invalid.
+ /// </exception>
+ private bool DecodeHuffman()
+ {
+ int free = outputWindow.GetFreeSpace();
+ while (free >= 258)
+ {
+ int symbol;
+ switch (mode)
+ {
+ case DECODE_HUFFMAN:
+ // This is the inner loop so it is optimized a bit
+ while (((symbol = litlenTree.GetSymbol(input)) & ~0xff) == 0)
+ {
+ outputWindow.Write(symbol);
+ if (--free < 258)
+ {
+ return true;
+ }
+ }
+
+ if (symbol < 257)
+ {
+ if (symbol < 0)
+ {
+ return false;
+ }
+ else
+ {
+ // symbol == 256: end of block
+ distTree = null;
+ litlenTree = null;
+ mode = DECODE_BLOCKS;
+ return true;
+ }
+ }
+
+ try
+ {
+ repLength = CPLENS[symbol - 257];
+ neededBits = CPLEXT[symbol - 257];
+ }
+ catch (Exception)
+ {
+ throw new SharpZipBaseException("Illegal rep length code");
+ }
+ goto case DECODE_HUFFMAN_LENBITS; // fall through
+
+ case DECODE_HUFFMAN_LENBITS:
+ if (neededBits > 0)
+ {
+ mode = DECODE_HUFFMAN_LENBITS;
+ int i = input.PeekBits(neededBits);
+ if (i < 0)
+ {
+ return false;
+ }
+ input.DropBits(neededBits);
+ repLength += i;
+ }
+ mode = DECODE_HUFFMAN_DIST;
+ goto case DECODE_HUFFMAN_DIST; // fall through
+
+ case DECODE_HUFFMAN_DIST:
+ symbol = distTree.GetSymbol(input);
+ if (symbol < 0)
+ {
+ return false;
+ }
+
+ try
+ {
+ repDist = CPDIST[symbol];
+ neededBits = CPDEXT[symbol];
+ }
+ catch (Exception)
+ {
+ throw new SharpZipBaseException("Illegal rep dist code");
+ }
+
+ goto case DECODE_HUFFMAN_DISTBITS; // fall through
+
+ case DECODE_HUFFMAN_DISTBITS:
+ if (neededBits > 0)
+ {
+ mode = DECODE_HUFFMAN_DISTBITS;
+ int i = input.PeekBits(neededBits);
+ if (i < 0)
+ {
+ return false;
+ }
+ input.DropBits(neededBits);
+ repDist += i;
+ }
+
+ outputWindow.Repeat(repLength, repDist);
+ free -= repLength;
+ mode = DECODE_HUFFMAN;
+ break;
+
+ default:
+ throw new SharpZipBaseException("Inflater unknown mode");
+ }
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// Decodes the adler checksum after the deflate stream.
+ /// </summary>
+ /// <returns>
+ /// false if more input is needed.
+ /// </returns>
+ /// <exception cref="SharpZipBaseException">
+ /// If checksum doesn't match.
+ /// </exception>
+ private bool DecodeChksum()
+ {
+ while (neededBits > 0) {
+ int chkByte = input.PeekBits(8);
+ if (chkByte < 0) {
+ return false;
+ }
+ input.DropBits(8);
+ readAdler = (readAdler << 8) | chkByte;
+ neededBits -= 8;
+ }
+
+ if ((int) adler.Value != readAdler) {
+ throw new SharpZipBaseException("Adler chksum doesn't match: " + (int)adler.Value + " vs. " + readAdler);
+ }
+
+ mode = FINISHED;
+ return false;
+ }
+
+ /// <summary>
+ /// Decodes the deflated stream.
+ /// </summary>
+ /// <returns>
+ /// false if more input is needed, or if finished.
+ /// </returns>
+ /// <exception cref="SharpZipBaseException">
+ /// if deflated stream is invalid.
+ /// </exception>
+ private bool Decode()
+ {
+ switch (mode) {
+ case DECODE_HEADER:
+ return DecodeHeader();
+
+ case DECODE_DICT:
+ return DecodeDict();
+
+ case DECODE_CHKSUM:
+ return DecodeChksum();
+
+ case DECODE_BLOCKS:
+ if (isLastBlock) {
+ if (noHeader) {
+ mode = FINISHED;
+ return false;
+ } else {
+ input.SkipToByteBoundary();
+ neededBits = 32;
+ mode = DECODE_CHKSUM;
+ return true;
+ }
+ }
+
+ int type = input.PeekBits(3);
+ if (type < 0) {
+ return false;
+ }
+ input.DropBits(3);
+
+ if ((type & 1) != 0) {
+ isLastBlock = true;
+ }
+ switch (type >> 1){
+ case DeflaterConstants.STORED_BLOCK:
+ input.SkipToByteBoundary();
+ mode = DECODE_STORED_LEN1;
+ break;
+ case DeflaterConstants.STATIC_TREES:
+ litlenTree = InflaterHuffmanTree.defLitLenTree;
+ distTree = InflaterHuffmanTree.defDistTree;
+ mode = DECODE_HUFFMAN;
+ break;
+ case DeflaterConstants.DYN_TREES:
+ dynHeader = new InflaterDynHeader();
+ mode = DECODE_DYN_HEADER;
+ break;
+ default:
+ throw new SharpZipBaseException("Unknown block type " + type);
+ }
+ return true;
+
+ case DECODE_STORED_LEN1:
+ {
+ if ((uncomprLen = input.PeekBits(16)) < 0) {
+ return false;
+ }
+ input.DropBits(16);
+ mode = DECODE_STORED_LEN2;
+ }
+ goto case DECODE_STORED_LEN2; // fall through
+
+ case DECODE_STORED_LEN2:
+ {
+ int nlen = input.PeekBits(16);
+ if (nlen < 0) {
+ return false;
+ }
+ input.DropBits(16);
+ if (nlen != (uncomprLen ^ 0xffff)) {
+ throw new SharpZipBaseException("broken uncompressed block");
+ }
+ mode = DECODE_STORED;
+ }
+ goto case DECODE_STORED; // fall through
+
+ case DECODE_STORED:
+ {
+ int more = outputWindow.CopyStored(input, uncomprLen);
+ uncomprLen -= more;
+ if (uncomprLen == 0) {
+ mode = DECODE_BLOCKS;
+ return true;
+ }
+ return !input.IsNeedingInput;
+ }
+
+ case DECODE_DYN_HEADER:
+ if (!dynHeader.Decode(input)) {
+ return false;
+ }
+
+ litlenTree = dynHeader.BuildLitLenTree();
+ distTree = dynHeader.BuildDistTree();
+ mode = DECODE_HUFFMAN;
+ goto case DECODE_HUFFMAN; // fall through
+
+ case DECODE_HUFFMAN:
+ case DECODE_HUFFMAN_LENBITS:
+ case DECODE_HUFFMAN_DIST:
+ case DECODE_HUFFMAN_DISTBITS:
+ return DecodeHuffman();
+
+ case FINISHED:
+ return false;
+
+ default:
+ throw new SharpZipBaseException("Inflater.Decode unknown mode");
+ }
+ }
+
+ /// <summary>
+ /// Sets the preset dictionary. This should only be called, if
+ /// needsDictionary() returns true and it should set the same
+ /// dictionary, that was used for deflating. The getAdler()
+ /// function returns the checksum of the dictionary needed.
+ /// </summary>
+ /// <param name="buffer">
+ /// The dictionary.
+ /// </param>
+ public void SetDictionary(byte[] buffer)
+ {
+ SetDictionary(buffer, 0, buffer.Length);
+ }
+
+ /// <summary>
+ /// Sets the preset dictionary. This should only be called, if
+ /// needsDictionary() returns true and it should set the same
+ /// dictionary, that was used for deflating. The getAdler()
+ /// function returns the checksum of the dictionary needed.
+ /// </summary>
+ /// <param name="buffer">
+ /// The dictionary.
+ /// </param>
+ /// <param name="index">
+ /// The index into buffer where the dictionary starts.
+ /// </param>
+ /// <param name="count">
+ /// The number of bytes in the dictionary.
+ /// </param>
+ /// <exception cref="System.InvalidOperationException">
+ /// No dictionary is needed.
+ /// </exception>
+ /// <exception cref="SharpZipBaseException">
+ /// The adler checksum for the buffer is invalid
+ /// </exception>
+ public void SetDictionary(byte[] buffer, int index, int count)
+ {
+ if ( buffer == null ) {
+ throw new ArgumentNullException("buffer");
+ }
+
+ if ( index < 0 ) {
+ throw new ArgumentOutOfRangeException("index");
+ }
+
+ if ( count < 0 ) {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ if (!IsNeedingDictionary) {
+ throw new InvalidOperationException("Dictionary is not needed");
+ }
+
+ adler.Update(buffer, index, count);
+
+ if ((int)adler.Value != readAdler) {
+ throw new SharpZipBaseException("Wrong adler checksum");
+ }
+ adler.Reset();
+ outputWindow.CopyDict(buffer, index, count);
+ mode = DECODE_BLOCKS;
+ }
+
+ /// <summary>
+ /// Sets the input. This should only be called, if needsInput()
+ /// returns true.
+ /// </summary>
+ /// <param name="buffer">
+ /// the input.
+ /// </param>
+ public void SetInput(byte[] buffer)
+ {
+ SetInput(buffer, 0, buffer.Length);
+ }
+
+ /// <summary>
+ /// Sets the input. This should only be called, if needsInput()
+ /// returns true.
+ /// </summary>
+ /// <param name="buffer">
+ /// The source of input data
+ /// </param>
+ /// <param name="index">
+ /// The index into buffer where the input starts.
+ /// </param>
+ /// <param name="count">
+ /// The number of bytes of input to use.
+ /// </param>
+ /// <exception cref="System.InvalidOperationException">
+ /// No input is needed.
+ /// </exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// The index and/or count are wrong.
+ /// </exception>
+ public void SetInput(byte[] buffer, int index, int count)
+ {
+ input.SetInput(buffer, index, count);
+ totalIn += (long)count;
+ }
+
+ /// <summary>
+ /// Inflates the compressed stream to the output buffer. If this
+ /// returns 0, you should check, whether IsNeedingDictionary(),
+ /// IsNeedingInput() or IsFinished() returns true, to determine why no
+ /// further output is produced.
+ /// </summary>
+ /// <param name="buffer">
+ /// the output buffer.
+ /// </param>
+ /// <returns>
+ /// The number of bytes written to the buffer, 0 if no further
+ /// output can be produced.
+ /// </returns>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// if buffer has length 0.
+ /// </exception>
+ /// <exception cref="System.FormatException">
+ /// if deflated stream is invalid.
+ /// </exception>
+ public int Inflate(byte[] buffer)
+ {
+ if ( buffer == null )
+ {
+ throw new ArgumentNullException("buffer");
+ }
+
+ return Inflate(buffer, 0, buffer.Length);
+ }
+
+ /// <summary>
+ /// Inflates the compressed stream to the output buffer. If this
+ /// returns 0, you should check, whether needsDictionary(),
+ /// needsInput() or finished() returns true, to determine why no
+ /// further output is produced.
+ /// </summary>
+ /// <param name="buffer">
+ /// the output buffer.
+ /// </param>
+ /// <param name="offset">
+ /// the offset in buffer where storing starts.
+ /// </param>
+ /// <param name="count">
+ /// the maximum number of bytes to output.
+ /// </param>
+ /// <returns>
+ /// the number of bytes written to the buffer, 0 if no further output can be produced.
+ /// </returns>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// if count is less than 0.
+ /// </exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// if the index and / or count are wrong.
+ /// </exception>
+ /// <exception cref="System.FormatException">
+ /// if deflated stream is invalid.
+ /// </exception>
+ public int Inflate(byte[] buffer, int offset, int count)
+ {
+ if ( buffer == null )
+ {
+ throw new ArgumentNullException("buffer");
+ }
+
+ if ( count < 0 ) {
+ throw new ArgumentOutOfRangeException("count", "count cannot be negative");
+ }
+
+ if ( offset < 0 ) {
+ throw new ArgumentOutOfRangeException("offset", "offset cannot be negative");
+ }
+
+ if ( offset + count > buffer.Length ) {
+ throw new ArgumentException("count exceeds buffer bounds");
+ }
+
+ // Special case: count may be zero
+ if (count == 0)
+ {
+ if (!IsFinished) { // -jr- 08-Nov-2003 INFLATE_BUG fix..
+ Decode();
+ }
+ return 0;
+ }
+
+ int bytesCopied = 0;
+
+ do {
+ if (mode != DECODE_CHKSUM) {
+ /* Don't give away any output, if we are waiting for the
+ * checksum in the input stream.
+ *
+ * With this trick we have always:
+ * IsNeedingInput() and not IsFinished()
+ * implies more output can be produced.
+ */
+ int more = outputWindow.CopyOutput(buffer, offset, count);
+ if ( more > 0 ) {
+ adler.Update(buffer, offset, more);
+ offset += more;
+ bytesCopied += more;
+ totalOut += (long)more;
+ count -= more;
+ if (count == 0) {
+ return bytesCopied;
+ }
+ }
+ }
+ } while (Decode() || ((outputWindow.GetAvailable() > 0) && (mode != DECODE_CHKSUM)));
+ return bytesCopied;
+ }
+
+ /// <summary>
+ /// Returns true, if the input buffer is empty.
+ /// You should then call setInput().
+ /// NOTE: This method also returns true when the stream is finished.
+ /// </summary>
+ public bool IsNeedingInput {
+ get {
+ return input.IsNeedingInput;
+ }
+ }
+
+ /// <summary>
+ /// Returns true, if a preset dictionary is needed to inflate the input.
+ /// </summary>
+ public bool IsNeedingDictionary {
+ get {
+ return mode == DECODE_DICT && neededBits == 0;
+ }
+ }
+
+ /// <summary>
+ /// Returns true, if the inflater has finished. This means, that no
+ /// input is needed and no output can be produced.
+ /// </summary>
+ public bool IsFinished {
+ get {
+ return mode == FINISHED && outputWindow.GetAvailable() == 0;
+ }
+ }
+
+ /// <summary>
+ /// Gets the adler checksum. This is either the checksum of all
+ /// uncompressed bytes returned by inflate(), or if needsDictionary()
+ /// returns true (and thus no output was yet produced) this is the
+ /// adler checksum of the expected dictionary.
+ /// </summary>
+ /// <returns>
+ /// the adler checksum.
+ /// </returns>
+ public int Adler {
+ get {
+ return IsNeedingDictionary ? readAdler : (int) adler.Value;
+ }
+ }
+
+ /// <summary>
+ /// Gets the total number of output bytes returned by Inflate().
+ /// </summary>
+ /// <returns>
+ /// the total number of output bytes.
+ /// </returns>
+ public long TotalOut {
+ get {
+ return totalOut;
+ }
+ }
+
+ /// <summary>
+ /// Gets the total number of processed compressed input bytes.
+ /// </summary>
+ /// <returns>
+ /// The total number of bytes of processed input bytes.
+ /// </returns>
+ public long TotalIn {
+ get {
+ return totalIn - (long)RemainingInput;
+ }
+ }
+
+ /// <summary>
+ /// Gets the number of unprocessed input bytes. Useful, if the end of the
+ /// stream is reached and you want to further process the bytes after
+ /// the deflate stream.
+ /// </summary>
+ /// <returns>
+ /// The number of bytes of the input which have not been processed.
+ /// </returns>
+ public int RemainingInput {
+ // TODO: This should be a long?
+ get {
+ return input.AvailableBytes;
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// InflaterDynHeader.cs
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression.Streams;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip.Compression
+{
+ class InflaterDynHeader
+ {
+ #region Constants
+ const int LNUM = 0;
+ const int DNUM = 1;
+ const int BLNUM = 2;
+ const int BLLENS = 3;
+ const int LENS = 4;
+ const int REPS = 5;
+
+ static readonly int[] repMin = { 3, 3, 11 };
+ static readonly int[] repBits = { 2, 3, 7 };
+
+ static readonly int[] BL_ORDER =
+ { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
+
+ #endregion
+
+ #region Constructors
+ public InflaterDynHeader()
+ {
+ }
+ #endregion
+
+ public bool Decode(StreamManipulator input)
+ {
+ decode_loop:
+ for (;;) {
+ switch (mode) {
+ case LNUM:
+ lnum = input.PeekBits(5);
+ if (lnum < 0) {
+ return false;
+ }
+ lnum += 257;
+ input.DropBits(5);
+ // System.err.println("LNUM: "+lnum);
+ mode = DNUM;
+ goto case DNUM; // fall through
+ case DNUM:
+ dnum = input.PeekBits(5);
+ if (dnum < 0) {
+ return false;
+ }
+ dnum++;
+ input.DropBits(5);
+ // System.err.println("DNUM: "+dnum);
+ num = lnum+dnum;
+ litdistLens = new byte[num];
+ mode = BLNUM;
+ goto case BLNUM; // fall through
+ case BLNUM:
+ blnum = input.PeekBits(4);
+ if (blnum < 0) {
+ return false;
+ }
+ blnum += 4;
+ input.DropBits(4);
+ blLens = new byte[19];
+ ptr = 0;
+ // System.err.println("BLNUM: "+blnum);
+ mode = BLLENS;
+ goto case BLLENS; // fall through
+ case BLLENS:
+ while (ptr < blnum) {
+ int len = input.PeekBits(3);
+ if (len < 0) {
+ return false;
+ }
+ input.DropBits(3);
+ // System.err.println("blLens["+BL_ORDER[ptr]+"]: "+len);
+ blLens[BL_ORDER[ptr]] = (byte) len;
+ ptr++;
+ }
+ blTree = new InflaterHuffmanTree(blLens);
+ blLens = null;
+ ptr = 0;
+ mode = LENS;
+ goto case LENS; // fall through
+ case LENS:
+ {
+ int symbol;
+ while (((symbol = blTree.GetSymbol(input)) & ~15) == 0) {
+ /* Normal case: symbol in [0..15] */
+
+ // System.err.println("litdistLens["+ptr+"]: "+symbol);
+ litdistLens[ptr++] = lastLen = (byte)symbol;
+
+ if (ptr == num) {
+ /* Finished */
+ return true;
+ }
+ }
+
+ /* need more input ? */
+ if (symbol < 0) {
+ return false;
+ }
+
+ /* otherwise repeat code */
+ if (symbol >= 17) {
+ /* repeat zero */
+ // System.err.println("repeating zero");
+ lastLen = 0;
+ } else {
+ if (ptr == 0) {
+ throw new SharpZipBaseException();
+ }
+ }
+ repSymbol = symbol-16;
+ }
+ mode = REPS;
+ goto case REPS; // fall through
+ case REPS:
+ {
+ int bits = repBits[repSymbol];
+ int count = input.PeekBits(bits);
+ if (count < 0) {
+ return false;
+ }
+ input.DropBits(bits);
+ count += repMin[repSymbol];
+ // System.err.println("litdistLens repeated: "+count);
+
+ if (ptr + count > num) {
+ throw new SharpZipBaseException();
+ }
+ while (count-- > 0) {
+ litdistLens[ptr++] = lastLen;
+ }
+
+ if (ptr == num) {
+ /* Finished */
+ return true;
+ }
+ }
+ mode = LENS;
+ goto decode_loop;
+ }
+ }
+ }
+
+ public InflaterHuffmanTree BuildLitLenTree()
+ {
+ byte[] litlenLens = new byte[lnum];
+ Array.Copy(litdistLens, 0, litlenLens, 0, lnum);
+ return new InflaterHuffmanTree(litlenLens);
+ }
+
+ public InflaterHuffmanTree BuildDistTree()
+ {
+ byte[] distLens = new byte[dnum];
+ Array.Copy(litdistLens, lnum, distLens, 0, dnum);
+ return new InflaterHuffmanTree(distLens);
+ }
+
+ #region Instance Fields
+ byte[] blLens;
+ byte[] litdistLens;
+
+ InflaterHuffmanTree blTree;
+
+ int mode;
+ int lnum, dnum, blnum, num;
+ int repSymbol;
+ byte lastLen;
+ int ptr;
+ #endregion
+
+ }
+}
\ No newline at end of file
--- /dev/null
+// InflaterHuffmanTree.cs
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression;
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression.Streams;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip.Compression
+{
+ /// <summary>
+ /// Huffman tree used for inflation
+ /// </summary>
+ public class InflaterHuffmanTree
+ {
+ #region Constants
+ const int MAX_BITLEN = 15;
+ #endregion
+
+ #region Instance Fields
+ short[] tree;
+ #endregion
+
+ /// <summary>
+ /// Literal length tree
+ /// </summary>
+ public static InflaterHuffmanTree defLitLenTree;
+
+ /// <summary>
+ /// Distance tree
+ /// </summary>
+ public static InflaterHuffmanTree defDistTree;
+
+ static InflaterHuffmanTree()
+ {
+ try {
+ byte[] codeLengths = new byte[288];
+ int i = 0;
+ while (i < 144) {
+ codeLengths[i++] = 8;
+ }
+ while (i < 256) {
+ codeLengths[i++] = 9;
+ }
+ while (i < 280) {
+ codeLengths[i++] = 7;
+ }
+ while (i < 288) {
+ codeLengths[i++] = 8;
+ }
+ defLitLenTree = new InflaterHuffmanTree(codeLengths);
+
+ codeLengths = new byte[32];
+ i = 0;
+ while (i < 32) {
+ codeLengths[i++] = 5;
+ }
+ defDistTree = new InflaterHuffmanTree(codeLengths);
+ } catch (Exception) {
+ throw new SharpZipBaseException("InflaterHuffmanTree: static tree length illegal");
+ }
+ }
+
+ #region Constructors
+ /// <summary>
+ /// Constructs a Huffman tree from the array of code lengths.
+ /// </summary>
+ /// <param name = "codeLengths">
+ /// the array of code lengths
+ /// </param>
+ public InflaterHuffmanTree(byte[] codeLengths)
+ {
+ BuildTree(codeLengths);
+ }
+ #endregion
+
+ void BuildTree(byte[] codeLengths)
+ {
+ int[] blCount = new int[MAX_BITLEN + 1];
+ int[] nextCode = new int[MAX_BITLEN + 1];
+
+ for (int i = 0; i < codeLengths.Length; i++) {
+ int bits = codeLengths[i];
+ if (bits > 0) {
+ blCount[bits]++;
+ }
+ }
+
+ int code = 0;
+ int treeSize = 512;
+ for (int bits = 1; bits <= MAX_BITLEN; bits++) {
+ nextCode[bits] = code;
+ code += blCount[bits] << (16 - bits);
+ if (bits >= 10) {
+ /* We need an extra table for bit lengths >= 10. */
+ int start = nextCode[bits] & 0x1ff80;
+ int end = code & 0x1ff80;
+ treeSize += (end - start) >> (16 - bits);
+ }
+ }
+
+/* -jr comment this out! doesnt work for dynamic trees and pkzip 2.04g
+ if (code != 65536)
+ {
+ throw new SharpZipBaseException("Code lengths don't add up properly.");
+ }
+*/
+ /* Now create and fill the extra tables from longest to shortest
+ * bit len. This way the sub trees will be aligned.
+ */
+ tree = new short[treeSize];
+ int treePtr = 512;
+ for (int bits = MAX_BITLEN; bits >= 10; bits--) {
+ int end = code & 0x1ff80;
+ code -= blCount[bits] << (16 - bits);
+ int start = code & 0x1ff80;
+ for (int i = start; i < end; i += 1 << 7) {
+ tree[DeflaterHuffman.BitReverse(i)] = (short) ((-treePtr << 4) | bits);
+ treePtr += 1 << (bits-9);
+ }
+ }
+
+ for (int i = 0; i < codeLengths.Length; i++) {
+ int bits = codeLengths[i];
+ if (bits == 0) {
+ continue;
+ }
+ code = nextCode[bits];
+ int revcode = DeflaterHuffman.BitReverse(code);
+ if (bits <= 9) {
+ do {
+ tree[revcode] = (short) ((i << 4) | bits);
+ revcode += 1 << bits;
+ } while (revcode < 512);
+ } else {
+ int subTree = tree[revcode & 511];
+ int treeLen = 1 << (subTree & 15);
+ subTree = -(subTree >> 4);
+ do {
+ tree[subTree | (revcode >> 9)] = (short) ((i << 4) | bits);
+ revcode += 1 << bits;
+ } while (revcode < treeLen);
+ }
+ nextCode[bits] = code + (1 << (16 - bits));
+ }
+
+ }
+
+ /// <summary>
+ /// Reads the next symbol from input. The symbol is encoded using the
+ /// huffman tree.
+ /// </summary>
+ /// <param name="input">
+ /// input the input source.
+ /// </param>
+ /// <returns>
+ /// the next symbol, or -1 if not enough input is available.
+ /// </returns>
+ public int GetSymbol(StreamManipulator input)
+ {
+ int lookahead, symbol;
+ if ((lookahead = input.PeekBits(9)) >= 0) {
+ if ((symbol = tree[lookahead]) >= 0) {
+ input.DropBits(symbol & 15);
+ return symbol >> 4;
+ }
+ int subtree = -(symbol >> 4);
+ int bitlen = symbol & 15;
+ if ((lookahead = input.PeekBits(bitlen)) >= 0) {
+ symbol = tree[subtree | (lookahead >> 9)];
+ input.DropBits(symbol & 15);
+ return symbol >> 4;
+ } else {
+ int bits = input.AvailableBits;
+ lookahead = input.PeekBits(bits);
+ symbol = tree[subtree | (lookahead >> 9)];
+ if ((symbol & 15) <= bits) {
+ input.DropBits(symbol & 15);
+ return symbol >> 4;
+ } else {
+ return -1;
+ }
+ }
+ } else {
+ int bits = input.AvailableBits;
+ lookahead = input.PeekBits(bits);
+ symbol = tree[lookahead];
+ if (symbol >= 0 && (symbol & 15) <= bits) {
+ input.DropBits(symbol & 15);
+ return symbol >> 4;
+ } else {
+ return -1;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// PendingBuffer.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip.Compression
+{
+ /// <summary>
+ /// This class is general purpose class for writing data to a buffer.
+ ///
+ /// It allows you to write bits as well as bytes
+ /// Based on DeflaterPending.java
+ ///
+ /// author of the original java version : Jochen Hoenicke
+ /// </summary>
+ public class PendingBuffer
+ {
+ #region Instance Fields
+ /// <summary>
+ /// Internal work buffer
+ /// </summary>
+ readonly byte[] buffer_;
+
+ int start;
+ int end;
+
+ uint bits;
+ int bitCount;
+ #endregion
+
+ #region Constructors
+ /// <summary>
+ /// construct instance using default buffer size of 4096
+ /// </summary>
+ public PendingBuffer() : this( 4096 )
+ {
+ }
+
+ /// <summary>
+ /// construct instance using specified buffer size
+ /// </summary>
+ /// <param name="bufferSize">
+ /// size to use for internal buffer
+ /// </param>
+ public PendingBuffer(int bufferSize)
+ {
+ buffer_ = new byte[bufferSize];
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Clear internal state/buffers
+ /// </summary>
+ public void Reset()
+ {
+ start = end = bitCount = 0;
+ }
+
+ /// <summary>
+ /// Write a byte to buffer
+ /// </summary>
+ /// <param name="value">
+ /// The value to write
+ /// </param>
+ public void WriteByte(int value)
+ {
+ buffer_[end++] = unchecked((byte) value);
+ }
+
+ /// <summary>
+ /// Write a short value to buffer LSB first
+ /// </summary>
+ /// <param name="value">
+ /// The value to write.
+ /// </param>
+ public void WriteShort(int value)
+ {
+ buffer_[end++] = unchecked((byte) value);
+ buffer_[end++] = unchecked((byte) (value >> 8));
+ }
+
+ /// <summary>
+ /// write an integer LSB first
+ /// </summary>
+ /// <param name="value">The value to write.</param>
+ public void WriteInt(int value)
+ {
+ buffer_[end++] = unchecked((byte) value);
+ buffer_[end++] = unchecked((byte) (value >> 8));
+ buffer_[end++] = unchecked((byte) (value >> 16));
+ buffer_[end++] = unchecked((byte) (value >> 24));
+ }
+
+ /// <summary>
+ /// Write a block of data to buffer
+ /// </summary>
+ /// <param name="block">data to write</param>
+ /// <param name="offset">offset of first byte to write</param>
+ /// <param name="length">number of bytes to write</param>
+ public void WriteBlock(byte[] block, int offset, int length)
+ {
+ System.Array.Copy(block, offset, buffer_, end, length);
+ end += length;
+ }
+
+ /// <summary>
+ /// The number of bits written to the buffer
+ /// </summary>
+ public int BitCount {
+ get {
+ return bitCount;
+ }
+ }
+
+ /// <summary>
+ /// Align internal buffer on a byte boundary
+ /// </summary>
+ public void AlignToByte()
+ {
+ if (bitCount > 0)
+ {
+ buffer_[end++] = unchecked((byte) bits);
+ if (bitCount > 8) {
+ buffer_[end++] = unchecked((byte) (bits >> 8));
+ }
+ }
+ bits = 0;
+ bitCount = 0;
+ }
+
+ /// <summary>
+ /// Write bits to internal buffer
+ /// </summary>
+ /// <param name="b">source of bits</param>
+ /// <param name="count">number of bits to write</param>
+ public void WriteBits(int b, int count)
+ {
+ bits |= (uint)(b << bitCount);
+ bitCount += count;
+ if (bitCount < 16)
+ {
+ return;
+ }
+ buffer_[end++] = unchecked((byte) bits);
+ buffer_[end++] = unchecked((byte) (bits >> 8));
+ bits >>= 16;
+ bitCount -= 16;
+ }
+
+ /// <summary>
+ /// Write a short value to internal buffer most significant byte first
+ /// </summary>
+ /// <param name="s">value to write</param>
+ public void WriteShortMSB(int s)
+ {
+ buffer_[end++] = unchecked((byte) (s >> 8));
+ buffer_[end++] = unchecked((byte) s);
+ }
+
+ /// <summary>
+ /// Indicates if buffer has been flushed
+ /// </summary>
+ public bool IsFlushed {
+ get {
+ return end == 0;
+ }
+ }
+
+ /// <summary>
+ /// Flushes the pending buffer into the given output array. If the
+ /// output array is to small, only a partial flush is done.
+ /// </summary>
+ /// <param name="output">The output array.</param>
+ /// <param name="offset">The offset into output array.</param>
+ /// <param name="length">The maximum number of bytes to store.</param>
+ /// <returns>The number of bytes flushed.</returns>
+ public int Flush(byte[] output, int offset, int length)
+ {
+ if (bitCount >= 8) {
+ buffer_[end++] = unchecked((byte) bits);
+ bits >>= 8;
+ bitCount -= 8;
+ }
+
+ if (length > end - start) {
+ length = end - start;
+ System.Array.Copy(buffer_, start, output, offset, length);
+ start = 0;
+ end = 0;
+ } else {
+ System.Array.Copy(buffer_, start, output, offset, length);
+ start += length;
+ }
+ return length;
+ }
+
+ /// <summary>
+ /// Convert internal buffer to byte array.
+ /// Buffer is empty on completion
+ /// </summary>
+ /// <returns>
+ /// The internal buffer contents converted to a byte array.
+ /// </returns>
+ public byte[] ToByteArray()
+ {
+ var result = new byte[end - start];
+ System.Array.Copy(buffer_, start, result, 0, result.Length);
+ start = 0;
+ end = 0;
+ return result;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// DeflaterOutputStream.cs
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+using System.Security.Cryptography;
+using ICSharpCode.SharpZipLib.Silverlight.Encryption;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip.Compression.Streams
+{
+ /// <summary>
+ /// A special stream deflating or compressing the bytes that are
+ /// written to it. It uses a Deflater to perform actual deflating.<br/>
+ /// Authors of the original java version : Tom Tromey, Jochen Hoenicke
+ /// </summary>
+ public class DeflaterOutputStream : Stream
+ {
+ #region Constructors
+
+ /// <summary>
+ /// Creates a new DeflaterOutputStream with a default Deflater and default buffer size.
+ /// </summary>
+ /// <param name="baseOutputStream">
+ /// the output stream where deflated output should be written.
+ /// </param>
+ public DeflaterOutputStream(Stream baseOutputStream)
+ : this(baseOutputStream, new Deflater(), 512)
+ {
+ }
+
+ /// <summary>
+ /// Creates a new DeflaterOutputStream with the given Deflater and
+ /// default buffer size.
+ /// </summary>
+ /// <param name="baseOutputStream">
+ /// the output stream where deflated output should be written.
+ /// </param>
+ /// <param name="deflater">
+ /// the underlying deflater.
+ /// </param>
+ public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater)
+ : this(baseOutputStream, deflater, 512)
+ {
+ }
+
+ /// <summary>
+ /// Creates a new DeflaterOutputStream with the given Deflater and
+ /// buffer size.
+ /// </summary>
+ /// <param name="baseOutputStream">
+ /// The output stream where deflated output is written.
+ /// </param>
+ /// <param name="deflater">
+ /// The underlying deflater to use
+ /// </param>
+ /// <param name="bufferSize">
+ /// The buffer size to use when deflating
+ /// </param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// bufsize is less than or equal to zero.
+ /// </exception>
+ /// <exception cref="ArgumentException">
+ /// baseOutputStream does not support writing
+ /// </exception>
+ /// <exception cref="ArgumentNullException">
+ /// deflater instance is null
+ /// </exception>
+ public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater, int bufferSize)
+ {
+ if (baseOutputStream == null)
+ {
+ throw new ArgumentNullException("baseOutputStream");
+ }
+
+ if (baseOutputStream.CanWrite == false)
+ {
+ throw new ArgumentException("Must support writing", "baseOutputStream");
+ }
+
+ if (deflater == null)
+ {
+ throw new ArgumentNullException("deflater");
+ }
+
+ if (bufferSize <= 0)
+ {
+ throw new ArgumentOutOfRangeException("bufferSize");
+ }
+
+ baseOutputStream_ = baseOutputStream;
+ buffer_ = new byte[bufferSize];
+ deflater_ = deflater;
+ }
+
+ #endregion
+
+ #region Public API
+
+ /// <summary>
+ /// Get/set flag indicating ownership of the underlying stream.
+ /// When the flag is true <see cref="Close"></see> will close the underlying stream also.
+ /// </summary>
+ public bool IsStreamOwner
+ {
+ get { return isStreamOwner_; }
+ set { isStreamOwner_ = value; }
+ }
+
+ /// <summary>
+ /// Allows client to determine if an entry can be patched after its added
+ /// </summary>
+ public bool CanPatchEntries
+ {
+ get { return baseOutputStream_.CanSeek; }
+ }
+
+ /// <summary>
+ /// Finishes the stream by calling finish() on the deflater.
+ /// </summary>
+ /// <exception cref="SharpZipBaseException">
+ /// Not all input is deflated
+ /// </exception>
+ public virtual void Finish()
+ {
+ deflater_.Finish();
+ while (!deflater_.IsFinished)
+ {
+ var len = deflater_.Deflate(buffer_, 0, buffer_.Length);
+ if (len <= 0)
+ {
+ break;
+ }
+ if (cryptoTransform_ != null)
+ {
+ EncryptBlock(buffer_, 0, len);
+ }
+
+ baseOutputStream_.Write(buffer_, 0, len);
+ }
+
+ if (!deflater_.IsFinished)
+ {
+ throw new SharpZipBaseException("Can't deflate all input?");
+ }
+
+ baseOutputStream_.Flush();
+
+ if (cryptoTransform_ == null)
+ {
+ return;
+ }
+ cryptoTransform_.Dispose();
+ cryptoTransform_ = null;
+ }
+
+ #endregion
+
+ #region Encryption
+
+ private ICryptoTransform cryptoTransform_;
+ private string _password;
+
+ /// <summary>
+ /// Get/set the password used for encryption.
+ /// </summary>
+ /// <remarks>When set to null or if the password is empty no encryption is performed</remarks>
+ public string Password
+ {
+ get { return _password; }
+ set
+ {
+ if ((value != null) && (value.Length == 0))
+ {
+ _password = null;
+ }
+ else
+ {
+ _password = value;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Encrypt a block of data
+ /// </summary>
+ /// <param name="buffer">
+ /// Data to encrypt. NOTE the original contents of the buffer are lost
+ /// </param>
+ /// <param name="offset">
+ /// Offset of first byte in buffer to encrypt
+ /// </param>
+ /// <param name="length">
+ /// Number of bytes in buffer to encrypt
+ /// </param>
+ protected void EncryptBlock(byte[] buffer, int offset, int length)
+ {
+ cryptoTransform_.TransformBlock(buffer, 0, length, buffer, 0);
+ }
+
+ /// <summary>
+ /// Initializes encryption keys based on given password
+ /// </summary>
+ /// <param name="password">The password.</param>
+ protected void InitializePassword(string password)
+ {
+ var pkManaged = new PkzipClassicManaged();
+ var key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(password));
+ cryptoTransform_ = pkManaged.CreateEncryptor(key, null);
+ }
+
+ #endregion
+
+ #region Deflation Support
+
+ /// <summary>
+ /// Deflates everything in the input buffers. This will call
+ /// <code>def.deflate()</code> until all bytes from the input buffers
+ /// are processed.
+ /// </summary>
+ protected void Deflate()
+ {
+ while (!deflater_.IsNeedingInput)
+ {
+ var deflateCount = deflater_.Deflate(buffer_, 0, buffer_.Length);
+
+ if (deflateCount <= 0)
+ {
+ break;
+ }
+ if (cryptoTransform_ != null)
+ {
+ EncryptBlock(buffer_, 0, deflateCount);
+ }
+
+ baseOutputStream_.Write(buffer_, 0, deflateCount);
+ }
+
+ if (!deflater_.IsNeedingInput)
+ {
+ throw new SharpZipBaseException("DeflaterOutputStream can't deflate all input?");
+ }
+ }
+
+ #endregion
+
+ #region Stream Overrides
+
+ /// <summary>
+ /// Gets value indicating stream can be read from
+ /// </summary>
+ public override bool CanRead
+ {
+ get { return false; }
+ }
+
+ /// <summary>
+ /// Gets a value indicating if seeking is supported for this stream
+ /// This property always returns false
+ /// </summary>
+ public override bool CanSeek
+ {
+ get { return false; }
+ }
+
+ /// <summary>
+ /// Get value indicating if this stream supports writing
+ /// </summary>
+ public override bool CanWrite
+ {
+ get { return baseOutputStream_.CanWrite; }
+ }
+
+ /// <summary>
+ /// Get current length of stream
+ /// </summary>
+ public override long Length
+ {
+ get { return baseOutputStream_.Length; }
+ }
+
+ /// <summary>
+ /// Gets the current position within the stream.
+ /// </summary>
+ /// <exception cref="NotSupportedException">Any attempt to set position</exception>
+ public override long Position
+ {
+ get { return baseOutputStream_.Position; }
+ set { throw new NotSupportedException("Position property not supported"); }
+ }
+
+ /// <summary>
+ /// Sets the current position of this stream to the given value. Not supported by this class!
+ /// </summary>
+ /// <param name="offset">The offset relative to the <paramref name="origin"/> to seek.</param>
+ /// <param name="origin">The <see cref="SeekOrigin"/> to seek from.</param>
+ /// <returns>The new position in the stream.</returns>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new NotSupportedException("DeflaterOutputStream Seek not supported");
+ }
+
+ /// <summary>
+ /// Sets the length of this stream to the given value. Not supported by this class!
+ /// </summary>
+ /// <param name="value">The new stream length.</param>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override void SetLength(long value)
+ {
+ throw new NotSupportedException("DeflaterOutputStream SetLength not supported");
+ }
+
+ /// <summary>
+ /// Read a byte from stream advancing position by one
+ /// </summary>
+ /// <returns>The byte read cast to an int. THe value is -1 if at the end of the stream.</returns>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override int ReadByte()
+ {
+ throw new NotSupportedException("DeflaterOutputStream ReadByte not supported");
+ }
+
+ /// <summary>
+ /// Read a block of bytes from stream
+ /// </summary>
+ /// <param name="buffer">The buffer to store read data in.</param>
+ /// <param name="offset">The offset to start storing at.</param>
+ /// <param name="count">The maximum number of bytes to read.</param>
+ /// <returns>The actual number of bytes read. Zero if end of stream is detected.</returns>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ throw new NotSupportedException("DeflaterOutputStream Read not supported");
+ }
+
+ /// <summary>
+ /// Asynchronous reads are not supported a NotSupportedException is always thrown
+ /// </summary>
+ /// <param name="buffer">The buffer to read into.</param>
+ /// <param name="offset">The offset to start storing data at.</param>
+ /// <param name="count">The number of bytes to read</param>
+ /// <param name="callback">The async callback to use.</param>
+ /// <param name="state">The state to use.</param>
+ /// <returns>Returns an <see cref="IAsyncResult"/></returns>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback,
+ object state)
+ {
+ throw new NotSupportedException("DeflaterOutputStream BeginRead not currently supported");
+ }
+
+ /// <summary>
+ /// Asynchronous writes arent supported, a NotSupportedException is always thrown
+ /// </summary>
+ /// <param name="buffer">The buffer to write.</param>
+ /// <param name="offset">The offset to begin writing at.</param>
+ /// <param name="count">The number of bytes to write.</param>
+ /// <param name="callback">The <see cref="AsyncCallback"/> to use.</param>
+ /// <param name="state">The state object.</param>
+ /// <returns>Returns an IAsyncResult.</returns>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback,
+ object state)
+ {
+ throw new NotSupportedException("BeginWrite is not supported");
+ }
+
+ /// <summary>
+ /// Flushes the stream by calling <see cref="DeflaterOutputStream.Flush">Flush</see> on the deflater and then
+ /// on the underlying stream. This ensures that all bytes are flushed.
+ /// </summary>
+ public override void Flush()
+ {
+ deflater_.Flush();
+ Deflate();
+ baseOutputStream_.Flush();
+ }
+
+ /// <summary>
+ /// Calls <see cref="Finish"/> and closes the underlying
+ /// stream when <see cref="IsStreamOwner"></see> is true.
+ /// </summary>
+ public override void Close()
+ {
+ if (!isClosed_)
+ {
+ isClosed_ = true;
+
+ try
+ {
+ Finish();
+ if (cryptoTransform_ != null)
+ {
+ cryptoTransform_.Dispose();
+ cryptoTransform_ = null;
+ }
+ }
+ finally
+ {
+ if (isStreamOwner_)
+ {
+ baseOutputStream_.Close();
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Writes a single byte to the compressed output stream.
+ /// </summary>
+ /// <param name="value">
+ /// The byte value.
+ /// </param>
+ public override void WriteByte(byte value)
+ {
+ var b = new byte[1];
+ b[0] = value;
+ Write(b, 0, 1);
+ }
+
+ /// <summary>
+ /// Writes bytes from an array to the compressed stream.
+ /// </summary>
+ /// <param name="buffer">
+ /// The byte array
+ /// </param>
+ /// <param name="offset">
+ /// The offset into the byte array where to start.
+ /// </param>
+ /// <param name="count">
+ /// The number of bytes to write.
+ /// </param>
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ deflater_.SetInput(buffer, offset, count);
+ Deflate();
+ }
+
+ #endregion
+
+ #region Instance Fields
+
+ /// <summary>
+ /// This buffer is used temporarily to retrieve the bytes from the
+ /// deflater and write them to the underlying output stream.
+ /// </summary>
+ private readonly byte[] buffer_;
+
+ /// <summary>
+ /// Base stream the deflater depends on.
+ /// </summary>
+ protected Stream baseOutputStream_;
+
+ /// <summary>
+ /// The deflater which is used to deflate the stream.
+ /// </summary>
+ protected Deflater deflater_;
+
+ private bool isClosed_;
+
+ private bool isStreamOwner_ = true;
+
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+// InflaterInputStream.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+using System.Security.Cryptography;
+using ICSharpCode.SharpZipLib.Silverlight.GZip;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip.Compression.Streams
+{
+ /// <summary>
+ /// An input buffer customised for use by <see cref="InflaterInputStream"/>
+ /// </summary>
+ /// <remarks>
+ /// The buffer supports decryption of incoming data.
+ /// </remarks>
+ public class InflaterInputBuffer
+ {
+ #region Constructors
+
+ /// <summary>
+ /// Initialise a new instance of <see cref="InflaterInputBuffer"/> with a default buffer size
+ /// </summary>
+ /// <param name="stream">The stream to buffer.</param>
+ public InflaterInputBuffer(Stream stream) : this(stream, 4096)
+ {
+ }
+
+ /// <summary>
+ /// Initialise a new instance of <see cref="InflaterInputBuffer"/>
+ /// </summary>
+ /// <param name="stream">The stream to buffer.</param>
+ /// <param name="bufferSize">The size to use for the buffer</param>
+ /// <remarks>A minimum buffer size of 1KB is permitted. Lower sizes are treated as 1KB.</remarks>
+ public InflaterInputBuffer(Stream stream, int bufferSize)
+ {
+ inputStream = stream;
+ if (bufferSize < 1024)
+ {
+ bufferSize = 1024;
+ }
+ rawData = new byte[bufferSize];
+ clearText = rawData;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Get the length of bytes bytes in the <see cref="RawData"/>
+ /// </summary>
+ public int RawLength
+ {
+ get { return rawLength; }
+ }
+
+ /// <summary>
+ /// Get the contents of the raw data buffer.
+ /// </summary>
+ /// <remarks>This may contain encrypted data.</remarks>
+ public byte[] RawData
+ {
+ get { return rawData; }
+ }
+
+ /// <summary>
+ /// Get the number of useable bytes in <see cref="ClearText"/>
+ /// </summary>
+ public int ClearTextLength
+ {
+ get { return clearTextLength; }
+ }
+
+ /// <summary>
+ /// Get the contents of the clear text buffer.
+ /// </summary>
+ public byte[] ClearText
+ {
+ get { return clearText; }
+ }
+
+ /// <summary>
+ /// Get/set the number of bytes available
+ /// </summary>
+ public int Available
+ {
+ get { return available; }
+ set { available = value; }
+ }
+
+ /// <summary>
+ /// Get/set the <see cref="ICryptoTransform"/> to apply to any data.
+ /// </summary>
+ /// <remarks>Set this value to null to have no transform applied.</remarks>
+ public ICryptoTransform CryptoTransform
+ {
+ set
+ {
+ cryptoTransform = value;
+ if (cryptoTransform != null)
+ {
+ if (rawData == clearText)
+ {
+ if (internalClearText == null)
+ {
+ internalClearText = new byte[4096];
+ }
+ clearText = internalClearText;
+ }
+ clearTextLength = rawLength;
+ if (available > 0)
+ {
+ cryptoTransform.TransformBlock(rawData, rawLength - available, available, clearText,
+ rawLength - available);
+ }
+ }
+ else
+ {
+ clearText = rawData;
+ clearTextLength = rawLength;
+ }
+ }
+ }
+
+ #region Instance Fields
+
+ private readonly Stream inputStream;
+ private readonly byte[] rawData;
+ private int available;
+ private byte[] clearText;
+ private int clearTextLength;
+ private ICryptoTransform cryptoTransform;
+ private byte[] internalClearText;
+ private int rawLength;
+
+ #endregion
+
+ /// <summary>
+ /// Call <see cref="Inflater.SetInput(byte[], int, int)"/> passing the current clear text buffer contents.
+ /// </summary>
+ /// <param name="inflater">The inflater to set input for.</param>
+ public void SetInflaterInput(Inflater inflater)
+ {
+ if (available > 0)
+ {
+ inflater.SetInput(clearText, clearTextLength - available, available);
+ available = 0;
+ }
+ }
+
+ /// <summary>
+ /// Fill the buffer from the underlying input stream.
+ /// </summary>
+ public void Fill()
+ {
+ rawLength = 0;
+ var toRead = rawData.Length;
+
+ while (toRead > 0)
+ {
+ var count = inputStream.Read(rawData, rawLength, toRead);
+ if (count <= 0)
+ {
+ if (rawLength == 0)
+ {
+ throw new SharpZipBaseException("Unexpected EOF");
+ }
+ break;
+ }
+ rawLength += count;
+ toRead -= count;
+ }
+
+ clearTextLength = cryptoTransform != null ? cryptoTransform.TransformBlock(rawData, 0, rawLength, clearText, 0) : rawLength;
+ available = clearTextLength;
+ }
+
+ /// <summary>
+ /// Read a buffer directly from the input stream
+ /// </summary>
+ /// <param name="buffer">The buffer to fill</param>
+ /// <returns>Returns the number of bytes read.</returns>
+ public int ReadRawBuffer(byte[] buffer)
+ {
+ return ReadRawBuffer(buffer, 0, buffer.Length);
+ }
+
+ /// <summary>
+ /// Read a buffer directly from the input stream
+ /// </summary>
+ /// <param name="outBuffer">The buffer to read into</param>
+ /// <param name="offset">The offset to start reading data into.</param>
+ /// <param name="length">The number of bytes to read.</param>
+ /// <returns>Returns the number of bytes read.</returns>
+ public int ReadRawBuffer(byte[] outBuffer, int offset, int length)
+ {
+ if (length < 0)
+ {
+ throw new ArgumentOutOfRangeException("length");
+ }
+
+ var currentOffset = offset;
+ var currentLength = length;
+
+ while (currentLength > 0)
+ {
+ if (available <= 0)
+ {
+ Fill();
+ if (available <= 0)
+ {
+ return 0;
+ }
+ }
+ var toCopy = Math.Min(currentLength, available);
+ Array.Copy(rawData, rawLength - available, outBuffer, currentOffset, toCopy);
+ currentOffset += toCopy;
+ currentLength -= toCopy;
+ available -= toCopy;
+ }
+ return length;
+ }
+
+ /// <summary>
+ /// Read clear text data from the input stream.
+ /// </summary>
+ /// <param name="outBuffer">The buffer to add data to.</param>
+ /// <param name="offset">The offset to start adding data at.</param>
+ /// <param name="length">The number of bytes to read.</param>
+ /// <returns>Returns the number of bytes actually read.</returns>
+ public int ReadClearTextBuffer(byte[] outBuffer, int offset, int length)
+ {
+ if (length < 0)
+ {
+ throw new ArgumentOutOfRangeException("length");
+ }
+
+ var currentOffset = offset;
+ var currentLength = length;
+
+ while (currentLength > 0)
+ {
+ if (available <= 0)
+ {
+ Fill();
+ if (available <= 0)
+ {
+ return 0;
+ }
+ }
+
+ var toCopy = Math.Min(currentLength, available);
+ Array.Copy(clearText, clearTextLength - available, outBuffer, currentOffset, toCopy);
+ currentOffset += toCopy;
+ currentLength -= toCopy;
+ available -= toCopy;
+ }
+ return length;
+ }
+
+ /// <summary>
+ /// Read a <see cref="byte"/> from the input stream.
+ /// </summary>
+ /// <returns>Returns the byte read.</returns>
+ public int ReadLeByte()
+ {
+ if (available <= 0)
+ {
+ Fill();
+ if (available <= 0)
+ {
+ throw new ZipException("EOF in header");
+ }
+ }
+ var result = (byte) (rawData[rawLength - available] & 0xff);
+ available -= 1;
+ return result;
+ }
+
+ /// <summary>
+ /// Read an <see cref="short"/> in little endian byte order.
+ /// </summary>
+ /// <returns>The short value read case to an int.</returns>
+ public int ReadLeShort()
+ {
+ return ReadLeByte() | (ReadLeByte() << 8);
+ }
+
+ /// <summary>
+ /// Read an <see cref="int"/> in little endian byte order.
+ /// </summary>
+ /// <returns>The int value read.</returns>
+ public int ReadLeInt()
+ {
+ return ReadLeShort() | (ReadLeShort() << 16);
+ }
+
+ /// <summary>
+ /// Read a <see cref="long"/> in little endian byte order.
+ /// </summary>
+ /// <returns>The long value read.</returns>
+ public long ReadLeLong()
+ {
+ return (uint) ReadLeInt() | ((long) ReadLeInt() << 32);
+ }
+ }
+
+ /// <summary>
+ /// This filter stream is used to decompress data compressed using the "deflate"
+ /// format. The "deflate" format is described in RFC 1951.
+ ///
+ /// This stream may form the basis for other decompression filters, such
+ /// as the <see cref="GZipInputStream">GZipInputStream</see>.
+ ///
+ /// Author of the original java version : John Leuner.
+ /// </summary>
+ public class InflaterInputStream : Stream
+ {
+ #region Constructors
+
+ /// <summary>
+ /// Create an InflaterInputStream with the default decompressor
+ /// and a default buffer size of 4KB.
+ /// </summary>
+ /// <param name = "baseInputStream">
+ /// The InputStream to read bytes from
+ /// </param>
+ public InflaterInputStream(Stream baseInputStream)
+ : this(baseInputStream, new Inflater(), 4096)
+ {
+ }
+
+ /// <summary>
+ /// Create an InflaterInputStream with the specified decompressor
+ /// and a default buffer size of 4KB.
+ /// </summary>
+ /// <param name = "baseInputStream">
+ /// The source of input data
+ /// </param>
+ /// <param name = "inf">
+ /// The decompressor used to decompress data read from baseInputStream
+ /// </param>
+ public InflaterInputStream(Stream baseInputStream, Inflater inf)
+ : this(baseInputStream, inf, 4096)
+ {
+ }
+
+ /// <summary>
+ /// Create an InflaterInputStream with the specified decompressor
+ /// and the specified buffer size.
+ /// </summary>
+ /// <param name = "baseInputStream">
+ /// The InputStream to read bytes from
+ /// </param>
+ /// <param name = "inflater">
+ /// The decompressor to use
+ /// </param>
+ /// <param name = "bufferSize">
+ /// Size of the buffer to use
+ /// </param>
+ public InflaterInputStream(Stream baseInputStream, Inflater inflater, int bufferSize)
+ {
+ if (baseInputStream == null)
+ {
+ throw new ArgumentNullException("baseInputStream");
+ }
+
+ if (inflater == null)
+ {
+ throw new ArgumentNullException("inflater");
+ }
+
+ if (bufferSize <= 0)
+ {
+ throw new ArgumentOutOfRangeException("bufferSize");
+ }
+
+ this.baseInputStream = baseInputStream;
+ inf = inflater;
+
+ inputBuffer = new InflaterInputBuffer(baseInputStream, bufferSize);
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Get/set flag indicating ownership of underlying stream.
+ /// When the flag is true <see cref="Close"/> will close the underlying stream also.
+ /// </summary>
+ /// <remarks>
+ /// The default value is true.
+ /// </remarks>
+ public bool IsStreamOwner
+ {
+ get { return isStreamOwner; }
+ set { isStreamOwner = value; }
+ }
+
+ /// <summary>
+ /// Returns 0 once the end of the stream (EOF) has been reached.
+ /// Otherwise returns 1.
+ /// </summary>
+ public virtual int Available
+ {
+ get { return inf.IsFinished ? 0 : 1; }
+ }
+
+ /// <summary>
+ /// Skip specified number of bytes of uncompressed data
+ /// </summary>
+ /// <param name ="count">
+ /// Number of bytes to skip
+ /// </param>
+ /// <returns>
+ /// The number of bytes skipped, zero if the end of
+ /// stream has been reached
+ /// </returns>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Number of bytes to skip is less than zero
+ /// </exception>
+ public long Skip(long count)
+ {
+ if (count < 0)
+ {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ // v0.80 Skip by seeking if underlying stream supports it...
+ if (baseInputStream.CanSeek)
+ {
+ baseInputStream.Seek(count, SeekOrigin.Current);
+ return count;
+ }
+ var len = 2048;
+ if (count < len)
+ {
+ len = (int) count;
+ }
+ var tmp = new byte[len];
+ return baseInputStream.Read(tmp, 0, tmp.Length);
+ }
+
+ /// <summary>
+ /// Clear any cryptographic state.
+ /// </summary>
+ protected void StopDecrypting()
+ {
+ inputBuffer.CryptoTransform = null;
+ }
+
+ /// <summary>
+ /// Fills the buffer with more data to decompress.
+ /// </summary>
+ /// <exception cref="SharpZipBaseException">
+ /// Stream ends early
+ /// </exception>
+ protected void Fill()
+ {
+ inputBuffer.Fill();
+ inputBuffer.SetInflaterInput(inf);
+ }
+
+ #region Stream Overrides
+
+ /// <summary>
+ /// Gets a value indicating whether the current stream supports reading
+ /// </summary>
+ public override bool CanRead
+ {
+ get { return baseInputStream.CanRead; }
+ }
+
+ /// <summary>
+ /// Gets a value of false indicating seeking is not supported for this stream.
+ /// </summary>
+ public override bool CanSeek
+ {
+ get { return false; }
+ }
+
+ /// <summary>
+ /// Gets a value of false indicating that this stream is not writeable.
+ /// </summary>
+ public override bool CanWrite
+ {
+ get { return false; }
+ }
+
+ /// <summary>
+ /// A value representing the length of the stream in bytes.
+ /// </summary>
+ public override long Length
+ {
+ get { return inputBuffer.RawLength; }
+ }
+
+ /// <summary>
+ /// The current position within the stream.
+ /// Throws a NotSupportedException when attempting to set the position
+ /// </summary>
+ /// <exception cref="NotSupportedException">Attempting to set the position</exception>
+ public override long Position
+ {
+ get { return baseInputStream.Position; }
+ set { throw new NotSupportedException("InflaterInputStream Position not supported"); }
+ }
+
+ /// <summary>
+ /// Flushes the baseInputStream
+ /// </summary>
+ public override void Flush()
+ {
+ baseInputStream.Flush();
+ }
+
+ /// <summary>
+ /// Sets the position within the current stream
+ /// Always throws a NotSupportedException
+ /// </summary>
+ /// <param name="offset">The relative offset to seek to.</param>
+ /// <param name="origin">The <see cref="SeekOrigin"/> defining where to seek from.</param>
+ /// <returns>The new position in the stream.</returns>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new NotSupportedException("Seek not supported");
+ }
+
+ /// <summary>
+ /// Set the length of the current stream
+ /// Always throws a NotSupportedException
+ /// </summary>
+ /// <param name="value">The new length value for the stream.</param>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override void SetLength(long value)
+ {
+ throw new NotSupportedException("InflaterInputStream SetLength not supported");
+ }
+
+ /// <summary>
+ /// Writes a sequence of bytes to stream and advances the current position
+ /// This method always throws a NotSupportedException
+ /// </summary>
+ /// <param name="buffer">Thew buffer containing data to write.</param>
+ /// <param name="offset">The offset of the first byte to write.</param>
+ /// <param name="count">The number of bytes to write.</param>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ throw new NotSupportedException("InflaterInputStream Write not supported");
+ }
+
+ /// <summary>
+ /// Writes one byte to the current stream and advances the current position
+ /// Always throws a NotSupportedException
+ /// </summary>
+ /// <param name="value">The byte to write.</param>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override void WriteByte(byte value)
+ {
+ throw new NotSupportedException("InflaterInputStream WriteByte not supported");
+ }
+
+ /// <summary>
+ /// Entry point to begin an asynchronous write. Always throws a NotSupportedException.
+ /// </summary>
+ /// <param name="buffer">The buffer to write data from</param>
+ /// <param name="offset">Offset of first byte to write</param>
+ /// <param name="count">The maximum number of bytes to write</param>
+ /// <param name="callback">The method to be called when the asynchronous write operation is completed</param>
+ /// <param name="state">A user-provided object that distinguishes this particular asynchronous write request from other requests</param>
+ /// <returns>An <see cref="System.IAsyncResult">IAsyncResult</see> that references the asynchronous write</returns>
+ /// <exception cref="NotSupportedException">Any access</exception>
+ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback,
+ object state)
+ {
+ throw new NotSupportedException("InflaterInputStream BeginWrite not supported");
+ }
+
+ /// <summary>
+ /// Closes the input stream. When <see cref="IsStreamOwner"></see>
+ /// is true the underlying stream is also closed.
+ /// </summary>
+ public override void Close()
+ {
+ if (!isClosed)
+ {
+ isClosed = true;
+ if (isStreamOwner)
+ {
+ baseInputStream.Close();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Reads decompressed data into the provided buffer byte array
+ /// </summary>
+ /// <param name ="buffer">
+ /// The array to read and decompress data into
+ /// </param>
+ /// <param name ="offset">
+ /// The offset indicating where the data should be placed
+ /// </param>
+ /// <param name ="count">
+ /// The number of bytes to decompress
+ /// </param>
+ /// <returns>The number of bytes read. Zero signals the end of stream</returns>
+ /// <exception cref="SharpZipBaseException">
+ /// Inflater needs a dictionary
+ /// </exception>
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ if (inf.IsNeedingDictionary)
+ {
+ throw new SharpZipBaseException("Need a dictionary");
+ }
+
+ var remainingBytes = count;
+ while (true)
+ {
+ var bytesRead = inf.Inflate(buffer, offset, remainingBytes);
+ offset += bytesRead;
+ remainingBytes -= bytesRead;
+
+ if (remainingBytes == 0 || inf.IsFinished)
+ {
+ break;
+ }
+
+ if (inf.IsNeedingInput)
+ {
+ Fill();
+ }
+ else if (bytesRead == 0)
+ {
+ throw new ZipException("Dont know what to do");
+ }
+ }
+ return count - remainingBytes;
+ }
+
+ #endregion
+
+ #region Instance Fields
+
+ /// <summary>
+ /// Base stream the inflater reads from.
+ /// </summary>
+ protected Stream baseInputStream;
+
+ /// <summary>
+ /// The compressed size
+ /// </summary>
+ protected long csize;
+
+ /// <summary>
+ /// Decompressor for this stream
+ /// </summary>
+ protected Inflater inf;
+
+ /// <summary>
+ /// <see cref="InflaterInputBuffer">Input buffer</see> for this stream.
+ /// </summary>
+ protected InflaterInputBuffer inputBuffer;
+
+ /// <summary>
+ /// Flag indicating wether this instance has been closed or not.
+ /// </summary>
+ private bool isClosed;
+
+ /// <summary>
+ /// Flag indicating wether this instance is designated the stream owner.
+ /// When closing if this flag is true the underlying stream is closed.
+ /// </summary>
+ private bool isStreamOwner = true;
+
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+// OutputWindow.cs
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip.Compression.Streams
+{
+ /// <summary>
+ /// Contains the output from the Inflation process.
+ /// We need to have a window so that we can refer backwards into the output stream
+ /// to repeat stuff.<br/>
+ /// Author of the original java version : John Leuner
+ /// </summary>
+ public class OutputWindow
+ {
+ #region Constants
+
+ private const int WindowMask = WindowSize - 1;
+ private const int WindowSize = 1 << 15;
+
+ #endregion
+
+ #region Instance Fields
+
+ private readonly byte[] window = new byte[WindowSize]; //The window is 2^15 bytes
+ private int windowEnd;
+ private int windowFilled;
+
+ #endregion
+
+ /// <summary>
+ /// Write a byte to this output window
+ /// </summary>
+ /// <param name="value">value to write</param>
+ /// <exception cref="InvalidOperationException">
+ /// if window is full
+ /// </exception>
+ public void Write(int value)
+ {
+ if (windowFilled++ == WindowSize)
+ {
+ throw new InvalidOperationException("Window full");
+ }
+ window[windowEnd++] = (byte) value;
+ windowEnd &= WindowMask;
+ }
+
+ private void SlowRepeat(int repStart, int length)
+ {
+ while (length-- > 0)
+ {
+ window[windowEnd++] = window[repStart++];
+ windowEnd &= WindowMask;
+ repStart &= WindowMask;
+ }
+ }
+
+ /// <summary>
+ /// Append a byte pattern already in the window itself
+ /// </summary>
+ /// <param name="length">length of pattern to copy</param>
+ /// <param name="distance">distance from end of window pattern occurs</param>
+ /// <exception cref="InvalidOperationException">
+ /// If the repeated data overflows the window
+ /// </exception>
+ public void Repeat(int length, int distance)
+ {
+ if ((windowFilled += length) > WindowSize)
+ {
+ throw new InvalidOperationException("Window full");
+ }
+
+ var repStart = (windowEnd - distance) & WindowMask;
+ var border = WindowSize - length;
+ if ((repStart <= border) && (windowEnd < border))
+ {
+ if (length <= distance)
+ {
+ Array.Copy(window, repStart, window, windowEnd, length);
+ windowEnd += length;
+ }
+ else
+ {
+ // We have to copy manually, since the repeat pattern overlaps.
+ while (length-- > 0)
+ {
+ window[windowEnd++] = window[repStart++];
+ }
+ }
+ }
+ else
+ {
+ SlowRepeat(repStart, length);
+ }
+ }
+
+ /// <summary>
+ /// Copy from input manipulator to internal window
+ /// </summary>
+ /// <param name="input">source of data</param>
+ /// <param name="length">length of data to copy</param>
+ /// <returns>the number of bytes copied</returns>
+ public int CopyStored(StreamManipulator input, int length)
+ {
+ length = Math.Min(Math.Min(length, WindowSize - windowFilled), input.AvailableBytes);
+ int copied;
+
+ var tailLen = WindowSize - windowEnd;
+ if (length > tailLen)
+ {
+ copied = input.CopyBytes(window, windowEnd, tailLen);
+ if (copied == tailLen)
+ {
+ copied += input.CopyBytes(window, 0, length - tailLen);
+ }
+ }
+ else
+ {
+ copied = input.CopyBytes(window, windowEnd, length);
+ }
+
+ windowEnd = (windowEnd + copied) & WindowMask;
+ windowFilled += copied;
+ return copied;
+ }
+
+ /// <summary>
+ /// Copy dictionary to window
+ /// </summary>
+ /// <param name="dictionary">source dictionary</param>
+ /// <param name="offset">offset of start in source dictionary</param>
+ /// <param name="length">length of dictionary</param>
+ /// <exception cref="InvalidOperationException">
+ /// If window isnt empty
+ /// </exception>
+ public void CopyDict(byte[] dictionary, int offset, int length)
+ {
+ if (dictionary == null)
+ {
+ throw new ArgumentNullException("dictionary");
+ }
+
+ if (windowFilled > 0)
+ {
+ throw new InvalidOperationException();
+ }
+
+ if (length > WindowSize)
+ {
+ offset += length - WindowSize;
+ length = WindowSize;
+ }
+ Array.Copy(dictionary, offset, window, 0, length);
+ windowEnd = length & WindowMask;
+ }
+
+ /// <summary>
+ /// Get remaining unfilled space in window
+ /// </summary>
+ /// <returns>Number of bytes left in window</returns>
+ public int GetFreeSpace()
+ {
+ return WindowSize - windowFilled;
+ }
+
+ /// <summary>
+ /// Get bytes available for output in window
+ /// </summary>
+ /// <returns>Number of bytes filled</returns>
+ public int GetAvailable()
+ {
+ return windowFilled;
+ }
+
+ /// <summary>
+ /// Copy contents of window to output
+ /// </summary>
+ /// <param name="output">buffer to copy to</param>
+ /// <param name="offset">offset to start at</param>
+ /// <param name="len">number of bytes to count</param>
+ /// <returns>The number of bytes copied</returns>
+ /// <exception cref="InvalidOperationException">
+ /// If a window underflow occurs
+ /// </exception>
+ public int CopyOutput(byte[] output, int offset, int len)
+ {
+ var copyEnd = windowEnd;
+ if (len > windowFilled)
+ {
+ len = windowFilled;
+ }
+ else
+ {
+ copyEnd = (windowEnd - windowFilled + len) & WindowMask;
+ }
+
+ var copied = len;
+ var tailLen = len - copyEnd;
+
+ if (tailLen > 0)
+ {
+ Array.Copy(window, WindowSize - tailLen, output, offset, tailLen);
+ offset += tailLen;
+ len = copyEnd;
+ }
+ Array.Copy(window, copyEnd - len, output, offset, len);
+ windowFilled -= copied;
+ if (windowFilled < 0)
+ {
+ throw new InvalidOperationException();
+ }
+ return copied;
+ }
+
+ /// <summary>
+ /// Reset by clearing window so <see cref="GetAvailable">GetAvailable</see> returns 0
+ /// </summary>
+ public void Reset()
+ {
+ windowFilled = windowEnd = 0;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// StreamManipulator.cs
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip.Compression.Streams
+{
+ /// <summary>
+ /// This class allows us to retrieve a specified number of bits from
+ /// the input buffer, as well as copy big byte blocks.
+ ///
+ /// It uses an int buffer to store up to 31 bits for direct
+ /// manipulation. This guarantees that we can get at least 16 bits,
+ /// but we only need at most 15, so this is all safe.
+ ///
+ /// There are some optimizations in this class, for example, you must
+ /// never peek more than 8 bits more than needed, and you must first
+ /// peek bits before you may drop them. This is not a general purpose
+ /// class but optimized for the behaviour of the Inflater.
+ ///
+ /// authors of the original java version : John Leuner, Jochen Hoenicke
+ /// </summary>
+ public class StreamManipulator
+ {
+ #region Instance Fields
+ private byte[] window_;
+ private int windowStart_;
+ private int windowEnd_;
+
+ private uint buffer_;
+ private int bitsInBuffer_;
+ #endregion
+
+ /// <summary>
+ /// Get the next sequence of bits but don't increase input pointer. bitCount must be
+ /// less or equal 16 and if this call succeeds, you must drop
+ /// at least n - 8 bits in the next call.
+ /// </summary>
+ /// <param name="bitCount">The number of bits to peek.</param>
+ /// <returns>
+ /// the value of the bits, or -1 if not enough bits available. */
+ /// </returns>
+ public int PeekBits(int bitCount)
+ {
+ if (bitsInBuffer_ < bitCount) {
+ if (windowStart_ == windowEnd_) {
+ return -1; // ok
+ }
+ buffer_ |= (uint)((window_[windowStart_++] & 0xff |
+ (window_[windowStart_++] & 0xff) << 8) << bitsInBuffer_);
+ bitsInBuffer_ += 16;
+ }
+ return (int)(buffer_ & ((1 << bitCount) - 1));
+ }
+
+ /// <summary>
+ /// Drops the next n bits from the input. You should have called PeekBits
+ /// with a bigger or equal n before, to make sure that enough bits are in
+ /// the bit buffer.
+ /// </summary>
+ /// <param name="bitCount">The number of bits to drop.</param>
+ public void DropBits(int bitCount)
+ {
+ buffer_ >>= bitCount;
+ bitsInBuffer_ -= bitCount;
+ }
+
+ /// <summary>
+ /// Gets the next n bits and increases input pointer. This is equivalent
+ /// to <see cref="PeekBits"/> followed by <see cref="DropBits"/>, except for correct error handling.
+ /// </summary>
+ /// <param name="bitCount">The number of bits to retrieve.</param>
+ /// <returns>
+ /// the value of the bits, or -1 if not enough bits available.
+ /// </returns>
+ public int GetBits(int bitCount)
+ {
+ int bits = PeekBits(bitCount);
+ if (bits >= 0) {
+ DropBits(bitCount);
+ }
+ return bits;
+ }
+
+ /// <summary>
+ /// Gets the number of bits available in the bit buffer. This must be
+ /// only called when a previous PeekBits() returned -1.
+ /// </summary>
+ /// <returns>
+ /// the number of bits available.
+ /// </returns>
+ public int AvailableBits {
+ get {
+ return bitsInBuffer_;
+ }
+ }
+
+ /// <summary>
+ /// Gets the number of bytes available.
+ /// </summary>
+ /// <returns>
+ /// The number of bytes available.
+ /// </returns>
+ public int AvailableBytes {
+ get {
+ return windowEnd_ - windowStart_ + (bitsInBuffer_ >> 3);
+ }
+ }
+
+ /// <summary>
+ /// Skips to the next byte boundary.
+ /// </summary>
+ public void SkipToByteBoundary()
+ {
+ buffer_ >>= (bitsInBuffer_ & 7);
+ bitsInBuffer_ &= ~7;
+ }
+
+ /// <summary>
+ /// Returns true when SetInput can be called
+ /// </summary>
+ public bool IsNeedingInput {
+ get {
+ return windowStart_ == windowEnd_;
+ }
+ }
+
+ /// <summary>
+ /// Copies bytes from input buffer to output buffer starting
+ /// at output[offset]. You have to make sure, that the buffer is
+ /// byte aligned. If not enough bytes are available, copies fewer
+ /// bytes.
+ /// </summary>
+ /// <param name="output">
+ /// The buffer to copy bytes to.
+ /// </param>
+ /// <param name="offset">
+ /// The offset in the buffer at which copying starts
+ /// </param>
+ /// <param name="length">
+ /// The length to copy, 0 is allowed.
+ /// </param>
+ /// <returns>
+ /// The number of bytes copied, 0 if no bytes were available.
+ /// </returns>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Length is less than zero
+ /// </exception>
+ /// <exception cref="InvalidOperationException">
+ /// Bit buffer isnt byte aligned
+ /// </exception>
+ public int CopyBytes(byte[] output, int offset, int length)
+ {
+ if (length < 0) {
+ throw new ArgumentOutOfRangeException("length");
+ }
+
+ if ((bitsInBuffer_ & 7) != 0) {
+ // bits_in_buffer may only be 0 or a multiple of 8
+ throw new InvalidOperationException("Bit buffer is not byte aligned!");
+ }
+
+ int count = 0;
+ while ((bitsInBuffer_ > 0) && (length > 0)) {
+ output[offset++] = (byte) buffer_;
+ buffer_ >>= 8;
+ bitsInBuffer_ -= 8;
+ length--;
+ count++;
+ }
+
+ if (length == 0) {
+ return count;
+ }
+
+ int avail = windowEnd_ - windowStart_;
+ if (length > avail) {
+ length = avail;
+ }
+ Array.Copy(window_, windowStart_, output, offset, length);
+ windowStart_ += length;
+
+ if (((windowStart_ - windowEnd_) & 1) != 0) {
+ // We always want an even number of bytes in input, see peekBits
+ buffer_ = (uint)(window_[windowStart_++] & 0xff);
+ bitsInBuffer_ = 8;
+ }
+ return count + length;
+ }
+
+ /// <summary>
+ /// Resets state and empties internal buffers
+ /// </summary>
+ public void Reset()
+ {
+ buffer_ = 0;
+ windowStart_ = windowEnd_ = bitsInBuffer_ = 0;
+ }
+
+ /// <summary>
+ /// Add more input for consumption.
+ /// Only call when IsNeedingInput returns true
+ /// </summary>
+ /// <param name="buffer">data to be input</param>
+ /// <param name="offset">offset of first byte of input</param>
+ /// <param name="count">number of bytes of input to add.</param>
+ public void SetInput(byte[] buffer, int offset, int count)
+ {
+ if ( buffer == null ) {
+ throw new ArgumentNullException("buffer");
+ }
+
+ if ( offset < 0 ) {
+ throw new ArgumentOutOfRangeException("offset", "Cannot be negative");
+ }
+
+ if ( count < 0 ) {
+ throw new ArgumentOutOfRangeException("count", "Cannot be negative");
+ }
+
+ if (windowStart_ < windowEnd_) {
+ throw new InvalidOperationException("Old input was not completely processed");
+ }
+
+ int end = offset + count;
+
+ // We want to throw an ArrayIndexOutOfBoundsException early.
+ // Note the check also handles integer wrap around.
+ if ((offset > end) || (end > buffer.Length) ) {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ if ((count & 1) != 0) {
+ // We always want an even number of bytes in input, see PeekBits
+ buffer_ |= (uint)((buffer[offset++] & 0xff) << bitsInBuffer_);
+ bitsInBuffer_ += 8;
+ }
+
+ window_ = buffer;
+ windowStart_ = offset;
+ windowEnd_ = end;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// FastZip.cs
+//
+// Copyright 2005 John Reilly
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+using ICSharpCode.SharpZipLib.Silverlight.Core;
+using ICSharpCode.SharpZipLib.Silverlight.Zip;
+using ICSharpCode.SharpZipLib.Zip;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip
+{
+ /// <summary>
+ /// FastZipEvents supports all events applicable to <see cref="FastZip">FastZip</see> operations.
+ /// </summary>
+ public class FastZipEvents
+ {
+ /// <summary>
+ /// Delegate to invoke when processing directories.
+ /// </summary>
+ public ProcessDirectoryHandler ProcessDirectory;
+
+ /// <summary>
+ /// Delegate to invoke when processing files.
+ /// </summary>
+ public ProcessFileHandler ProcessFile;
+
+ /// <summary>
+ /// Delegate to invoke during processing of files.
+ /// </summary>
+ public ProgressHandler Progress;
+
+ /// <summary>
+ /// Delegate to invoke when processing for a file has been completed.
+ /// </summary>
+ public CompletedFileHandler CompletedFile;
+
+ /// <summary>
+ /// Delegate to invoke when processing directory failures.
+ /// </summary>
+ public DirectoryFailureHandler DirectoryFailure;
+
+ /// <summary>
+ /// Delegate to invoke when processing file failures.
+ /// </summary>
+ public FileFailureHandler FileFailure;
+
+ /// <summary>
+ /// Raise the <see cref="DirectoryFailure">directory failure</see> event.
+ /// </summary>
+ /// <param name="directory">The directory causing the failure.</param>
+ /// <param name="e">The exception for this event.</param>
+ /// <returns>A boolean indicating if execution should continue or not.</returns>
+ public bool OnDirectoryFailure(string directory, Exception e)
+ {
+ bool result = false;
+ if ( DirectoryFailure != null ) {
+ var args = new ScanFailureEventArgs(directory, e);
+ DirectoryFailure(this, args);
+ result = args.ContinueRunning;
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Raises the <see cref="FileFailure">file failure delegate</see>.
+ /// </summary>
+ /// <param name="file">The file causing the failure.</param>
+ /// <param name="e">The exception for this failure.</param>
+ /// <returns>A boolean indicating if execution should continue or not.</returns>
+ public bool OnFileFailure(string file, Exception e)
+ {
+ bool result = false;
+ if ( FileFailure != null ) {
+ var args = new ScanFailureEventArgs(file, e);
+ FileFailure(this, args);
+ result = args.ContinueRunning;
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Fires the <see cref="ProcessFile">Process File delegate</see>.
+ /// </summary>
+ /// <param name="file">The file being processed.</param>
+ /// <returns>A boolean indicating if execution should continue or not.</returns>
+ public bool OnProcessFile(string file)
+ {
+ bool result = true;
+ if ( ProcessFile != null ) {
+ var args = new ScanEventArgs(file);
+ ProcessFile(this, args);
+ result = args.ContinueRunning;
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Fires the CompletedFile delegate
+ /// </summary>
+ /// <param name="file">The file whose processing has been completed.</param>
+ /// <returns>A boolean indicating if execution should continue or not.</returns>
+ public bool OnCompletedFile(string file)
+ {
+ var result = true;
+ if ( CompletedFile != null ) {
+ var args = new ScanEventArgs(file);
+ CompletedFile(this, args);
+ result = args.ContinueRunning;
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Fires the <see cref="ProcessDirectory">process directory</see> delegate.
+ /// </summary>
+ /// <param name="directory">The directory being processed.</param>
+ /// <param name="hasMatchingFiles">Flag indicating if the directory has matching files as determined by the current filter.</param>
+ /// <returns>A <see cref="bool"/> of true if the operation should continue; false otherwise.</returns>
+ public bool OnProcessDirectory(string directory, bool hasMatchingFiles)
+ {
+ bool result = true;
+ if ( ProcessDirectory != null ) {
+ var args = new DirectoryEventArgs(directory, hasMatchingFiles);
+ ProcessDirectory(this, args);
+ result = args.ContinueRunning;
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// The minimum timespan between <see cref="Progress"/> events.
+ /// </summary>
+ /// <value>The minimum period of time between <see cref="Progress"/> events.</value>
+ /// <seealso cref="Progress"/>
+ public TimeSpan ProgressInterval
+ {
+ get { return progressInterval_; }
+ set { progressInterval_ = value; }
+ }
+
+ #region Instance Fields
+ TimeSpan progressInterval_ = TimeSpan.FromSeconds(3);
+ #endregion
+ }
+
+ /// <summary>
+ /// FastZip provides facilities for creating and extracting zip files.
+ /// </summary>
+ public class FastZip
+ {
+ #region Enumerations
+ /// <summary>
+ /// Defines the desired handling when overwriting files during extraction.
+ /// </summary>
+ public enum Overwrite
+ {
+ /// <summary>
+ /// Prompt the user to confirm overwriting
+ /// </summary>
+ Prompt,
+ /// <summary>
+ /// Never overwrite files.
+ /// </summary>
+ Never,
+ /// <summary>
+ /// Always overwrite files.
+ /// </summary>
+ Always
+ }
+ #endregion
+
+ #region Constructors
+ /// <summary>
+ /// Initialise a default instance of <see cref="FastZip"/>.
+ /// </summary>
+ public FastZip()
+ {
+ }
+
+ /// <summary>
+ /// Initialise a new instance of <see cref="FastZip"/>
+ /// </summary>
+ /// <param name="events">The <see cref="FastZipEvents">events</see> to use during operations.</param>
+ public FastZip(FastZipEvents events)
+ {
+ events_ = events;
+ }
+ #endregion
+
+ #region Properties
+
+ /// <summary>
+ /// Get/set a value indicating wether empty directories should be created.
+ /// </summary>
+ public bool CreateEmptyDirectories { get; set; }
+
+ /// <summary>
+ /// Get / set the password value.
+ /// </summary>
+ public string Password
+ {
+ get { return password_; }
+ set { password_ = value; }
+ }
+
+ /// <summary>
+ /// Get or set the <see cref="INameTransform"></see> active when creating Zip files.
+ /// </summary>
+ /// <seealso cref="EntryFactory"></seealso>
+ public INameTransform NameTransform
+ {
+ get { return entryFactory_.NameTransform; }
+ set {
+ entryFactory_.NameTransform = value;
+ }
+ }
+
+ /// <summary>
+ /// Get or set the <see cref="IEntryFactory"></see> active when creating Zip files.
+ /// </summary>
+ public IEntryFactory EntryFactory
+ {
+ get { return entryFactory_; }
+ set {
+ entryFactory_ = value ?? new ZipEntryFactory();
+ }
+ }
+
+ /// <summary>
+ /// Get/set a value indicating wether file dates and times should
+ /// be restored when extracting files from an archive.
+ /// </summary>
+ /// <remarks>The default value is false.</remarks>
+ public bool RestoreDateTimeOnExtract
+ {
+ get {
+ return restoreDateTimeOnExtract_;
+ }
+ set {
+ restoreDateTimeOnExtract_ = value;
+ }
+ }
+
+ /// <summary>
+ /// Get/set a value indicating wether file attributes should
+ /// be restored during extract operations
+ /// </summary>
+ public bool RestoreAttributesOnExtract { get; set; }
+
+ #endregion
+
+ #region Delegates
+ /// <summary>
+ /// Delegate called when confirming overwriting of files.
+ /// </summary>
+ public delegate bool ConfirmOverwriteDelegate(string fileName);
+ #endregion
+
+ #region CreateZip
+ /// <summary>
+ /// Create a zip file.
+ /// </summary>
+ /// <param name="zipFileName">The name of the zip file to create.</param>
+ /// <param name="sourceDirectory">The directory to source files from.</param>
+ /// <param name="recurse">True to recurse directories, false for no recursion.</param>
+ /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>
+ /// <param name="directoryFilter">The <see cref="PathFilter">directory filter</see> to apply.</param>
+ public void CreateZip(string zipFileName, string sourceDirectory,
+ bool recurse, string fileFilter, string directoryFilter)
+ {
+ CreateZip(File.Create(zipFileName), sourceDirectory, recurse, fileFilter, directoryFilter);
+ }
+
+ /// <summary>
+ /// Create a zip file/archive.
+ /// </summary>
+ /// <param name="zipFileName">The name of the zip file to create.</param>
+ /// <param name="sourceDirectory">The directory to obtain files and directories from.</param>
+ /// <param name="recurse">True to recurse directories, false for no recursion.</param>
+ /// <param name="fileFilter">The file filter to apply.</param>
+ public void CreateZip(string zipFileName, string sourceDirectory, bool recurse, string fileFilter)
+ {
+ CreateZip(File.Create(zipFileName), sourceDirectory, recurse, fileFilter, null);
+ }
+
+ /// <summary>
+ /// Create a zip archive sending output to the <paramref name="outputStream"/> passed.
+ /// </summary>
+ /// <param name="outputStream">The stream to write archive data to.</param>
+ /// <param name="sourceDirectory">The directory to source files from.</param>
+ /// <param name="recurse">True to recurse directories, false for no recursion.</param>
+ /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>
+ /// <param name="directoryFilter">The <see cref="PathFilter">directory filter</see> to apply.</param>
+ public void CreateZip(Stream outputStream, string sourceDirectory, bool recurse, string fileFilter, string directoryFilter)
+ {
+ NameTransform = new ZipNameTransform(sourceDirectory);
+ sourceDirectory_ = sourceDirectory;
+
+ using ( outputStream_ = new ZipOutputStream(outputStream) ) {
+
+ if (password_ != null)
+ {
+ outputStream_.Password = password_;
+ }
+
+ var scanner = new FileSystemScanner(fileFilter, directoryFilter);
+ scanner.ProcessFile += ProcessFile;
+ if ( CreateEmptyDirectories ) {
+ scanner.ProcessDirectory += ProcessDirectory;
+ }
+
+ if (events_ != null) {
+ if ( events_.FileFailure != null ) {
+ scanner.FileFailure += events_.FileFailure;
+ }
+
+ if ( events_.DirectoryFailure != null ) {
+ scanner.DirectoryFailure += events_.DirectoryFailure;
+ }
+ }
+
+ scanner.Scan(sourceDirectory, recurse);
+ }
+ }
+
+ #endregion
+
+ #region ExtractZip
+ /// <summary>
+ /// Extract the contents of a zip file.
+ /// </summary>
+ /// <param name="zipFileName">The zip file to extract from.</param>
+ /// <param name="targetDirectory">The directory to save extracted information in.</param>
+ /// <param name="fileFilter">A filter to apply to files.</param>
+ public void ExtractZip(string zipFileName, string targetDirectory, string fileFilter)
+ {
+ ExtractZip(zipFileName, targetDirectory, Overwrite.Always, null, fileFilter, null, restoreDateTimeOnExtract_);
+ }
+
+ /// <summary>
+ /// Extract the contents of a zip file.
+ /// </summary>
+ /// <param name="zipFileName">The zip file to extract from.</param>
+ /// <param name="targetDirectory">The directory to save extracted information in.</param>
+ /// <param name="overwrite">The style of <see cref="Overwrite">overwriting</see> to apply.</param>
+ /// <param name="confirmDelegate">A delegate to invoke when confirming overwriting.</param>
+ /// <param name="fileFilter">A filter to apply to files.</param>
+ /// <param name="directoryFilter">A filter to apply to directories.</param>
+ /// <param name="restoreDateTime">Flag indicating wether to restore the date and time for extracted files.</param>
+ public void ExtractZip(string zipFileName, string targetDirectory,
+ Overwrite overwrite, ConfirmOverwriteDelegate confirmDelegate,
+ string fileFilter, string directoryFilter, bool restoreDateTime)
+ {
+ if ( (overwrite == Overwrite.Prompt) && (confirmDelegate == null) ) {
+ throw new ArgumentNullException("confirmDelegate");
+ }
+
+ continueRunning_ = true;
+ overwrite_ = overwrite;
+ confirmDelegate_ = confirmDelegate;
+ targetDirectory_ = targetDirectory;
+ fileFilter_ = new NameFilter(fileFilter);
+ directoryFilter_ = new NameFilter(directoryFilter);
+ restoreDateTimeOnExtract_ = restoreDateTime;
+
+ using ( zipFile_ = new ZipFile(zipFileName) ) {
+
+#if !NETCF_1_0
+ if (password_ != null) {
+ zipFile_.Password = password_;
+ }
+#endif
+
+ System.Collections.IEnumerator enumerator = zipFile_.GetEnumerator();
+ while ( continueRunning_ && enumerator.MoveNext()) {
+ var entry = (ZipEntry) enumerator.Current;
+ if ( entry.IsFile )
+ {
+ if ( directoryFilter_.IsMatch(Path.GetDirectoryName(entry.Name)) && fileFilter_.IsMatch(entry.Name) ) {
+ ExtractEntry(entry);
+ }
+ }
+ else if ( entry.IsDirectory ) {
+ if ( directoryFilter_.IsMatch(entry.Name) && CreateEmptyDirectories ) {
+ ExtractEntry(entry);
+ }
+ }
+ }
+ }
+ }
+ #endregion
+
+ #region Internal Processing
+ void ProcessDirectory(object sender, DirectoryEventArgs e)
+ {
+ if ( !e.HasMatchingFiles && CreateEmptyDirectories ) {
+ if ( events_ != null ) {
+ events_.OnProcessDirectory(e.Name, e.HasMatchingFiles);
+ }
+
+ if ( e.ContinueRunning ) {
+ if (e.Name != sourceDirectory_) {
+ ZipEntry entry = entryFactory_.MakeDirectoryEntry(e.Name);
+ outputStream_.PutNextEntry(entry);
+ }
+ }
+ }
+ }
+
+ void ProcessFile(object sender, ScanEventArgs e)
+ {
+ if ( (events_ != null) && (events_.ProcessFile != null) ) {
+ events_.ProcessFile(sender, e);
+ }
+
+ if ( e.ContinueRunning ) {
+ ZipEntry entry = entryFactory_.MakeFileEntry(e.Name);
+ outputStream_.PutNextEntry(entry);
+ AddFileContents(e.Name);
+ }
+ }
+
+ void AddFileContents(string name)
+ {
+ if ( buffer_ == null ) {
+ buffer_ = new byte[4096];
+ }
+
+ using (FileStream stream = File.OpenRead(name)) {
+ if ((events_ != null) && (events_.Progress != null)) {
+ StreamUtils.Copy(stream, outputStream_, buffer_,
+ events_.Progress, events_.ProgressInterval, this, name);
+ }
+ else {
+ StreamUtils.Copy(stream, outputStream_, buffer_);
+ }
+ }
+
+ if (events_ != null) {
+ continueRunning_ = events_.OnCompletedFile(name);
+ }
+ }
+
+ void ExtractFileEntry(ZipEntry entry, string targetName)
+ {
+ bool proceed = true;
+ if ( overwrite_ != Overwrite.Always ) {
+ if ( File.Exists(targetName) ) {
+ if ( (overwrite_ == Overwrite.Prompt) && (confirmDelegate_ != null) ) {
+ proceed = confirmDelegate_(targetName);
+ }
+ else {
+ proceed = false;
+ }
+ }
+ }
+
+ if ( proceed ) {
+ if ( events_ != null ) {
+ continueRunning_ = events_.OnProcessFile(entry.Name);
+ }
+
+ if ( continueRunning_ ) {
+ try {
+ using ( FileStream outputStream = File.Create(targetName) ) {
+ if ( buffer_ == null ) {
+ buffer_ = new byte[4096];
+ }
+ if ((events_ != null) && (events_.Progress != null))
+ {
+ StreamUtils.Copy(zipFile_.GetInputStream(entry), outputStream, buffer_,
+ events_.Progress, events_.ProgressInterval, this, entry.Name);
+ }
+ else
+ {
+ StreamUtils.Copy(zipFile_.GetInputStream(entry), outputStream, buffer_);
+ }
+
+ if (events_ != null) {
+ continueRunning_ = events_.OnCompletedFile(entry.Name);
+ }
+ }
+
+ //if ( restoreDateTimeOnExtract_ ) {
+ //File.SetLastWriteTime(targetName, entry.DateTime);
+ //}
+
+ if ( RestoreAttributesOnExtract && entry.IsDOSEntry && (entry.ExternalFileAttributes != -1)) {
+ var fileAttributes = (FileAttributes) entry.ExternalFileAttributes;
+ // TODO: FastZip - Setting of other file attributes on extraction is a little trickier.
+ fileAttributes &= (FileAttributes.Archive | FileAttributes.Normal | FileAttributes.ReadOnly | FileAttributes.Hidden);
+ File.SetAttributes(targetName, fileAttributes);
+ }
+ }
+ catch(Exception ex) {
+ continueRunning_ = events_ != null && events_.OnFileFailure(targetName, ex);
+ }
+ }
+ }
+ }
+
+ void ExtractEntry(ZipEntry entry)
+ {
+ bool doExtraction = false;
+
+ string nameText = entry.Name;
+
+ if ( entry.IsFile ) {
+ // TODO: Translate invalid names allowing extraction still.
+ doExtraction = NameIsValid(nameText) && entry.IsCompressionMethodSupported();
+ }
+ else if ( entry.IsDirectory ) {
+ doExtraction = NameIsValid(nameText);
+ }
+
+ // TODO: Fire delegate were compression method not supported, or name is invalid?
+
+ string dirName = null;
+ string targetName = null;
+
+ if ( doExtraction ) {
+ // Handle invalid entry names by chopping of path root.
+ if (Path.IsPathRooted(nameText)) {
+ string workName = Path.GetPathRoot(nameText);
+ nameText = nameText.Substring(workName.Length);
+ }
+
+ if ( nameText.Length > 0 )
+ {
+ targetName = Path.Combine(targetDirectory_, nameText);
+ dirName = entry.IsDirectory ? targetName : Path.GetDirectoryName(Path.GetFullPath(targetName));
+ }
+ else {
+ doExtraction = false;
+ }
+ }
+
+ if ( doExtraction && !Directory.Exists(dirName) ) {
+ if ( !entry.IsDirectory || CreateEmptyDirectories ) {
+ try {
+ Directory.CreateDirectory(dirName);
+ }
+ catch (Exception ex) {
+ doExtraction = false;
+ if ( events_ != null ) {
+ continueRunning_ = entry.IsDirectory ? events_.OnDirectoryFailure(targetName, ex) : events_.OnFileFailure(targetName, ex);
+ }
+ else {
+ continueRunning_ = false;
+ }
+ }
+ }
+ }
+
+ if ( doExtraction && entry.IsFile ) {
+ ExtractFileEntry(entry, targetName);
+ }
+ }
+
+ static int MakeExternalAttributes(FileSystemInfo info)
+ {
+ return (int)info.Attributes;
+ }
+
+ static bool NameIsValid(string name)
+ {
+ return !string.IsNullOrEmpty(name) &&
+ (name.IndexOfAny(Path.GetInvalidPathChars()) < 0);
+ }
+ #endregion
+
+ #region Instance Fields
+ bool continueRunning_;
+ byte[] buffer_;
+ ZipOutputStream outputStream_;
+ ZipFile zipFile_;
+ string targetDirectory_;
+ string sourceDirectory_;
+ NameFilter fileFilter_;
+ NameFilter directoryFilter_;
+ Overwrite overwrite_;
+ ConfirmOverwriteDelegate confirmDelegate_;
+
+ bool restoreDateTimeOnExtract_;
+ readonly FastZipEvents events_;
+ IEntryFactory entryFactory_ = new ZipEntryFactory();
+
+ string password_;
+
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+// IEntryFactory.cs
+//
+// Copyright 2006 John Reilly
+//
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using ICSharpCode.SharpZipLib.Silverlight.Core;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip
+{
+ /// <summary>
+ /// Defines factory methods for creating new <see cref="ZipEntry"></see> values.
+ /// </summary>
+ public interface IEntryFactory
+ {
+ /// <summary>
+ /// Create a <see cref="ZipEntry"/> for a file given its name
+ /// </summary>
+ /// <param name="fileName">The name of the file to create an entry for.</param>
+ /// <returns>Returns a <see cref="ZipEntry">file entry</see> based on the <paramref name="fileName"/> passed.</returns>
+ ZipEntry MakeFileEntry(string fileName);
+
+ /// <summary>
+ /// Create a <see cref="ZipEntry"/> for a file given its name
+ /// </summary>
+ /// <param name="fileName">The name of the file to create an entry for.</param>
+ /// <param name="useFileSystem">If true get details from the file system if the file exists.</param>
+ /// <returns>Returns a <see cref="ZipEntry">file entry</see> based on the <paramref name="fileName"/> passed.</returns>
+ ZipEntry MakeFileEntry(string fileName, bool useFileSystem);
+
+ /// <summary>
+ /// Create a <see cref="ZipEntry"/> for a directory given its name
+ /// </summary>
+ /// <param name="directoryName">The name of the directory to create an entry for.</param>
+ /// <returns>Returns a <see cref="ZipEntry">directory entry</see> based on the <paramref name="directoryName"/> passed.</returns>
+ ZipEntry MakeDirectoryEntry(string directoryName);
+
+ /// <summary>
+ /// Create a <see cref="ZipEntry"/> for a directory given its name
+ /// </summary>
+ /// <param name="directoryName">The name of the directory to create an entry for.</param>
+ /// <param name="useFileSystem">If true get details from the file system for this directory if it exists.</param>
+ /// <returns>Returns a <see cref="ZipEntry">directory entry</see> based on the <paramref name="directoryName"/> passed.</returns>
+ ZipEntry MakeDirectoryEntry(string directoryName, bool useFileSystem);
+
+ /// <summary>
+ /// Get/set the <see cref="INameTransform"></see> applicable.
+ /// </summary>
+ INameTransform NameTransform { get; set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+// ZipConstants.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.Text;
+using ICSharpCode.SharpZipLib.Silverlight.Zip;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip
+{
+ /// <summary>
+ /// Determines how entries are tested to see if they should use Zip64 extensions or not.
+ /// </summary>
+ public enum UseZip64
+ {
+ /// <summary>
+ /// Zip64 will not be forced on entries during processing.
+ /// </summary>
+ /// <remarks>An entry can have this overridden if required <see cref="ZipEntry.ForceZip64"></see></remarks>
+ Off,
+ /// <summary>
+ /// Zip64 should always be used.
+ /// </summary>
+ On,
+ /// <summary>
+ /// #ZipLib will determine use based on entry values when added to archive.
+ /// </summary>
+ Dynamic,
+ }
+
+ /// <summary>
+ /// The kind of compression used for an entry in an archive
+ /// </summary>
+ public enum CompressionMethod
+ {
+ /// <summary>
+ /// A direct copy of the file contents is held in the archive
+ /// </summary>
+ Stored = 0,
+
+ /// <summary>
+ /// Common Zip compression method using a sliding dictionary
+ /// of up to 32KB and secondary compression from Huffman/Shannon-Fano trees
+ /// </summary>
+ Deflated = 8,
+
+ /// <summary>
+ /// An extension to deflate with a 64KB window. Not supported by #Zip currently
+ /// </summary>
+ Deflate64 = 9,
+
+ /// <summary>
+ /// Not supported by #Zip currently
+ /// </summary>
+ BZip2 = 11,
+
+ /// <summary>
+ /// WinZip special for AES encryption, Not supported by #Zip
+ /// </summary>
+ WinZipAES = 99,
+
+ }
+
+ /// <summary>
+ /// Identifies the encryption algorithm used for an entry
+ /// </summary>
+ public enum EncryptionAlgorithm
+ {
+ /// <summary>
+ /// No encryption has been used.
+ /// </summary>
+ None = 0,
+ /// <summary>
+ /// Encrypted using PKZIP 2.0 or 'classic' encryption.
+ /// </summary>
+ PkzipClassic = 1,
+ /// <summary>
+ /// DES encryption has been used.
+ /// </summary>
+ Des = 0x6601,
+ /// <summary>
+ /// RCS encryption has been used for encryption.
+ /// </summary>
+ RC2 = 0x6602,
+ /// <summary>
+ /// Triple DES encryption with 168 bit keys has been used for this entry.
+ /// </summary>
+ TripleDes168 = 0x6603,
+ /// <summary>
+ /// Triple DES with 112 bit keys has been used for this entry.
+ /// </summary>
+ TripleDes112 = 0x6609,
+ /// <summary>
+ /// AES 128 has been used for encryption.
+ /// </summary>
+ Aes128 = 0x660e,
+ /// <summary>
+ /// AES 192 has been used for encryption.
+ /// </summary>
+ Aes192 = 0x660f,
+ /// <summary>
+ /// AES 256 has been used for encryption.
+ /// </summary>
+ Aes256 = 0x6610,
+ /// <summary>
+ /// RC2 corrected has been used for encryption.
+ /// </summary>
+ RC2Corrected = 0x6702,
+ /// <summary>
+ /// Blowfish has been used for encryption.
+ /// </summary>
+ Blowfish = 0x6720,
+ /// <summary>
+ /// Twofish has been used for encryption.
+ /// </summary>
+ Twofish = 0x6721,
+ /// <summary>
+ /// RCS has been used for encryption.
+ /// </summary>
+ RC4 = 0x6801,
+ /// <summary>
+ /// An unknown algorithm has been used for encryption.
+ /// </summary>
+ Unknown = 0xffff
+ }
+
+ /// <summary>
+ /// Defines the contents of the general bit flags field for an archive entry.
+ /// </summary>
+ [Flags]
+ public enum GeneralBitFlags
+ {
+ /// <summary>
+ /// Bit 0 if set indicates that the file is encrypted
+ /// </summary>
+ Encrypted = 0x0001,
+ /// <summary>
+ /// Bits 1 and 2 - Two bits defining the compression method (only for Method 6 Imploding and 8,9 Deflating)
+ /// </summary>
+ Method = 0x0006,
+ /// <summary>
+ /// Bit 3 if set indicates a trailing data desciptor is appended to the entry data
+ /// </summary>
+ Descriptor = 0x0008,
+ /// <summary>
+ /// Bit 4 is reserved for use with method 8 for enhanced deflation
+ /// </summary>
+ ReservedPKware4 = 0x0010,
+ /// <summary>
+ /// Bit 5 if set indicates the file contains Pkzip compressed patched data.
+ /// Requires version 2.7 or greater.
+ /// </summary>
+ Patched = 0x0020,
+ /// <summary>
+ /// Bit 6 if set strong encryption has been used for this entry.
+ /// </summary>
+ StrongEncryption = 0x0040,
+ /// <summary>
+ /// Bit 7 is currently unused
+ /// </summary>
+ Unused7 = 0x0080,
+ /// <summary>
+ /// Bit 8 is currently unused
+ /// </summary>
+ Unused8 = 0x0100,
+ /// <summary>
+ /// Bit 9 is currently unused
+ /// </summary>
+ Unused9 = 0x0200,
+ /// <summary>
+ /// Bit 10 is currently unused
+ /// </summary>
+ Unused10 = 0x0400,
+ /// <summary>
+ /// Bit 11 if set indicates the filename and
+ /// comment fields for this file must be encoded using UTF-8.
+ /// </summary>
+ UnicodeText = 0x0800,
+ /// <summary>
+ /// Bit 12 is documented as being reserved by PKware for enhanced compression.
+ /// </summary>
+ EnhancedCompress = 0x1000,
+ /// <summary>
+ /// Bit 13 if set indicates that values in the local header are masked to hide
+ /// their actual values, and the central directory is encrypted.
+ /// </summary>
+ /// <remarks>
+ /// Used when encrypting the central directory contents.
+ /// </remarks>
+ HeaderMasked = 0x2000,
+ /// <summary>
+ /// Bit 14 is documented as being reserved for use by PKware
+ /// </summary>
+ ReservedPkware14 = 0x4000,
+ /// <summary>
+ /// Bit 15 is documented as being reserved for use by PKware
+ /// </summary>
+ ReservedPkware15 = 0x8000
+ }
+
+ /// <summary>
+ /// This class contains constants used for Zip format files
+ /// </summary>
+ public static class ZipConstants
+ {
+ #region Versions
+ /// <summary>
+ /// The version made by field for entries in the central header when created by this library
+ /// </summary>
+ /// <remarks>
+ /// This is also the Zip version for the library when comparing against the version required to extract
+ /// for an entry. See <see cref="ZipEntry.CanDecompress"/>.
+ /// </remarks>
+ public const int VersionMadeBy = 45;
+
+ /// <summary>
+ /// The version made by field for entries in the central header when created by this library
+ /// </summary>
+ /// <remarks>
+ /// This is also the Zip version for the library when comparing against the version required to extract
+ /// for an entry. See <see cref="ZipInputStream.CanDecompressEntry">ZipInputStream.CanDecompressEntry</see>.
+ /// </remarks>
+ [Obsolete("Use VersionMadeBy instead")]
+ public const int VERSION_MADE_BY = 45;
+
+ /// <summary>
+ /// The minimum version required to support strong encryption
+ /// </summary>
+ public const int VersionStrongEncryption = 50;
+
+ /// <summary>
+ /// The minimum version required to support strong encryption
+ /// </summary>
+ [Obsolete("Use VersionStrongEncryption instead")]
+ public const int VERSION_STRONG_ENCRYPTION = 50;
+
+ /// <summary>
+ /// The version required for Zip64 extensions
+ /// </summary>
+ public const int VersionZip64 = 45;
+ #endregion
+
+ #region Header Sizes
+ /// <summary>
+ /// Size of local entry header (excluding variable length fields at end)
+ /// </summary>
+ public const int LocalHeaderBaseSize = 30;
+
+ /// <summary>
+ /// Size of local entry header (excluding variable length fields at end)
+ /// </summary>
+ [Obsolete("Use LocalHeaderBaseSize instead")]
+ public const int LOCHDR = 30;
+
+ /// <summary>
+ /// Size of Zip64 data descriptor
+ /// </summary>
+ public const int Zip64DataDescriptorSize = 24;
+
+ /// <summary>
+ /// Size of data descriptor
+ /// </summary>
+ public const int DataDescriptorSize = 16;
+
+ /// <summary>
+ /// Size of data descriptor
+ /// </summary>
+ [Obsolete("Use DataDescriptorSize instead")]
+ public const int EXTHDR = 16;
+
+ /// <summary>
+ /// Size of central header entry (excluding variable fields)
+ /// </summary>
+ public const int CentralHeaderBaseSize = 46;
+
+ /// <summary>
+ /// Size of central header entry
+ /// </summary>
+ [Obsolete("Use CentralHeaderBaseSize instead")]
+ public const int CENHDR = 46;
+
+ /// <summary>
+ /// Size of end of central record (excluding variable fields)
+ /// </summary>
+ public const int EndOfCentralRecordBaseSize = 22;
+
+ /// <summary>
+ /// Size of end of central record (excluding variable fields)
+ /// </summary>
+ [Obsolete("Use EndOfCentralRecordBaseSize instead")]
+ public const int ENDHDR = 22;
+
+ /// <summary>
+ /// Size of 'classic' cryptographic header stored before any entry data
+ /// </summary>
+ public const int CryptoHeaderSize = 12;
+
+ /// <summary>
+ /// Size of cryptographic header stored before entry data
+ /// </summary>
+ [Obsolete("Use CryptoHeaderSize instead")]
+ public const int CRYPTO_HEADER_SIZE = 12;
+ #endregion
+
+ #region Header Signatures
+
+ /// <summary>
+ /// Signature for local entry header
+ /// </summary>
+ public const int LocalHeaderSignature = 'P' | ('K' << 8) | (3 << 16) | (4 << 24);
+
+ /// <summary>
+ /// Signature for local entry header
+ /// </summary>
+ [Obsolete("Use LocalHeaderSignature instead")]
+ public const int LOCSIG = 'P' | ('K' << 8) | (3 << 16) | (4 << 24);
+
+ /// <summary>
+ /// Signature for spanning entry
+ /// </summary>
+ public const int SpanningSignature = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);
+
+ /// <summary>
+ /// Signature for spanning entry
+ /// </summary>
+ [Obsolete("Use SpanningSignature instead")]
+ public const int SPANNINGSIG = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);
+
+ /// <summary>
+ /// Signature for temporary spanning entry
+ /// </summary>
+ public const int SpanningTempSignature = 'P' | ('K' << 8) | ('0' << 16) | ('0' << 24);
+
+ /// <summary>
+ /// Signature for temporary spanning entry
+ /// </summary>
+ [Obsolete("Use SpanningTempSignature instead")]
+ public const int SPANTEMPSIG = 'P' | ('K' << 8) | ('0' << 16) | ('0' << 24);
+
+ /// <summary>
+ /// Signature for data descriptor
+ /// </summary>
+ /// <remarks>
+ /// This is only used where the length, Crc, or compressed size isnt known when the
+ /// entry is created and the output stream doesnt support seeking.
+ /// The local entry cannot be 'patched' with the correct values in this case
+ /// so the values are recorded after the data prefixed by this header, as well as in the central directory.
+ /// </remarks>
+ public const int DataDescriptorSignature = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);
+
+ /// <summary>
+ /// Signature for data descriptor
+ /// </summary>
+ /// <remarks>
+ /// This is only used where the length, Crc, or compressed size isnt known when the
+ /// entry is created and the output stream doesnt support seeking.
+ /// The local entry cannot be 'patched' with the correct values in this case
+ /// so the values are recorded after the data prefixed by this header, as well as in the central directory.
+ /// </remarks>
+ [Obsolete("Use DataDescriptorSignature instead")]
+ public const int EXTSIG = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);
+
+ /// <summary>
+ /// Signature for central header
+ /// </summary>
+ [Obsolete("Use CentralHeaderSignature instead")]
+ public const int CENSIG = 'P' | ('K' << 8) | (1 << 16) | (2 << 24);
+
+ /// <summary>
+ /// Signature for central header
+ /// </summary>
+ public const int CentralHeaderSignature = 'P' | ('K' << 8) | (1 << 16) | (2 << 24);
+
+ /// <summary>
+ /// Signature for Zip64 central file header
+ /// </summary>
+ public const int Zip64CentralFileHeaderSignature = 'P' | ('K' << 8) | (6 << 16) | (6 << 24);
+
+ /// <summary>
+ /// Signature for Zip64 central file header
+ /// </summary>
+ [Obsolete("Use Zip64CentralFileHeaderSignature instead")]
+ public const int CENSIG64 = 'P' | ('K' << 8) | (6 << 16) | (6 << 24);
+
+ /// <summary>
+ /// Signature for Zip64 central directory locator
+ /// </summary>
+ public const int Zip64CentralDirLocatorSignature = 'P' | ('K' << 8) | (6 << 16) | (7 << 24);
+
+ /// <summary>
+ /// Signature for archive extra data signature (were headers are encrypted).
+ /// </summary>
+ public const int ArchiveExtraDataSignature = 'P' | ('K' << 8) | (6 << 16) | (7 << 24);
+
+ /// <summary>
+ /// Central header digitial signature
+ /// </summary>
+ public const int CentralHeaderDigitalSignature = 'P' | ('K' << 8) | (5 << 16) | (5 << 24);
+
+ /// <summary>
+ /// Central header digitial signature
+ /// </summary>
+ [Obsolete("Use CentralHeaderDigitalSignaure instead")]
+ public const int CENDIGITALSIG = 'P' | ('K' << 8) | (5 << 16) | (5 << 24);
+
+ /// <summary>
+ /// End of central directory record signature
+ /// </summary>
+ public const int EndOfCentralDirectorySignature = 'P' | ('K' << 8) | (5 << 16) | (6 << 24);
+
+ /// <summary>
+ /// End of central directory record signature
+ /// </summary>
+ [Obsolete("Use EndOfCentralDirectorySignature instead")]
+ public const int ENDSIG = 'P' | ('K' << 8) | (5 << 16) | (6 << 24);
+ #endregion
+
+ /// <summary>
+ /// Convert a portion of a byte array to a string.
+ /// </summary>
+ /// <param name="data">
+ /// Data to convert to string
+ /// </param>
+ /// <param name="count">
+ /// Number of bytes to convert starting from index 0
+ /// </param>
+ /// <returns>
+ /// data[0]..data[length - 1] converted to a string
+ /// </returns>
+ public static string ConvertToString(byte[] data, int count)
+ {
+ if ( data == null ) {
+ return string.Empty;
+ }
+
+ return Encoding.UTF8.GetString(data, 0, count);
+ }
+
+ /// <summary>
+ /// Convert a byte array to string
+ /// </summary>
+ /// <param name="data">
+ /// Byte array to convert
+ /// </param>
+ /// <returns>
+ /// <paramref name="data">data</paramref>converted to a string
+ /// </returns>
+ public static string ConvertToString(byte[] data)
+ {
+ if ( data == null ) {
+ return string.Empty;
+ }
+ return ConvertToString(data, data.Length);
+ }
+
+ /// <summary>
+ /// Convert a byte array to string
+ /// </summary>
+ /// <param name="flags">The applicable general purpose bits flags</param>
+ /// <param name="data">
+ /// Byte array to convert
+ /// </param>
+ /// <param name="count">The number of bytes to convert.</param>
+ /// <returns>
+ /// <paramref name="data">data</paramref>converted to a string
+ /// </returns>
+ public static string ConvertToStringExt(int flags, byte[] data, int count)
+ {
+ if ( data == null ) {
+ return string.Empty;
+ }
+
+ if ( (flags & (int)GeneralBitFlags.UnicodeText) != 0 ) {
+ return Encoding.UTF8.GetString(data, 0, count);
+ }
+
+ return ConvertToString(data, count);
+ }
+
+ /// <summary>
+ /// Convert a byte array to string
+ /// </summary>
+ /// <param name="data">
+ /// Byte array to convert
+ /// </param>
+ /// <param name="flags">The applicable general purpose bits flags</param>
+ /// <returns>
+ /// <paramref name="data">data</paramref>converted to a string
+ /// </returns>
+ public static string ConvertToStringExt(int flags, byte[] data)
+ {
+ if ( data == null ) {
+ return string.Empty;
+ }
+
+ if ( (flags & (int)GeneralBitFlags.UnicodeText) != 0 ) {
+ return Encoding.UTF8.GetString(data, 0, data.Length);
+ }
+ else {
+ return ConvertToString(data, data.Length);
+ }
+ }
+
+ /// <summary>
+ /// Convert a string to a byte array
+ /// </summary>
+ /// <param name="str">
+ /// String to convert to an array
+ /// </param>
+ /// <returns>Converted array</returns>
+ public static byte[] ConvertToArray(string str)
+ {
+ if ( str == null ) {
+ return new byte[0];
+ }
+
+ return Encoding.UTF8.GetBytes(str);
+ }
+
+ /// <summary>
+ /// Convert a string to a byte array
+ /// </summary>
+ /// <param name="flags">The applicable general purpose bits flags</param>
+ /// <param name="str">
+ /// String to convert to an array
+ /// </param>
+ /// <returns>Converted array</returns>
+ public static byte[] ConvertToArray(int flags, string str)
+ {
+ if (str == null) {
+ return new byte[0];
+ }
+
+ if ((flags & (int)GeneralBitFlags.UnicodeText) != 0) {
+ return Encoding.UTF8.GetBytes(str);
+ }
+ else {
+ return ConvertToArray(str);
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// ZipEntry.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+using ICSharpCode.SharpZipLib.Silverlight.Zip;
+using ICSharpCode.SharpZipLib.Zip;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip
+{
+ /// <summary>
+ /// Defines known values for the <see cref="HostSystemID"/> property.
+ /// </summary>
+ public enum HostSystemID
+ {
+ /// <summary>
+ /// Host system = MSDOS
+ /// </summary>
+ Msdos = 0,
+ /// <summary>
+ /// Host system = Amiga
+ /// </summary>
+ Amiga = 1,
+ /// <summary>
+ /// Host system = Open VMS
+ /// </summary>
+ OpenVms = 2,
+ /// <summary>
+ /// Host system = Unix
+ /// </summary>
+ Unix = 3,
+ /// <summary>
+ /// Host system = VMCms
+ /// </summary>
+ VMCms = 4,
+ /// <summary>
+ /// Host system = Atari ST
+ /// </summary>
+ AtariST = 5,
+ /// <summary>
+ /// Host system = OS2
+ /// </summary>
+ OS2 = 6,
+ /// <summary>
+ /// Host system = Macintosh
+ /// </summary>
+ Macintosh = 7,
+ /// <summary>
+ /// Host system = ZSystem
+ /// </summary>
+ ZSystem = 8,
+ /// <summary>
+ /// Host system = Cpm
+ /// </summary>
+ Cpm = 9,
+ /// <summary>
+ /// Host system = Windows NT
+ /// </summary>
+ WindowsNT = 10,
+ /// <summary>
+ /// Host system = MVS
+ /// </summary>
+ MVS = 11,
+ /// <summary>
+ /// Host system = VSE
+ /// </summary>
+ Vse = 12,
+ /// <summary>
+ /// Host system = Acorn RISC
+ /// </summary>
+ AcornRisc = 13,
+ /// <summary>
+ /// Host system = VFAT
+ /// </summary>
+ Vfat = 14,
+ /// <summary>
+ /// Host system = Alternate MVS
+ /// </summary>
+ AlternateMvs = 15,
+ /// <summary>
+ /// Host system = BEOS
+ /// </summary>
+ BeOS = 16,
+ /// <summary>
+ /// Host system = Tandem
+ /// </summary>
+ Tandem = 17,
+ /// <summary>
+ /// Host system = OS400
+ /// </summary>
+ OS400 = 18,
+ /// <summary>
+ /// Host system = OSX
+ /// </summary>
+ OSX = 19,
+ /// <summary>
+ /// Host system = WinZIP AES
+ /// </summary>
+ WinZipAES = 99,
+ }
+
+ /// <summary>
+ /// This class represents an entry in a zip archive. This can be a file
+ /// or a directory
+ /// ZipFile and ZipInputStream will give you instances of this class as
+ /// information about the members in an archive. ZipOutputStream
+ /// uses an instance of this class when creating an entry in a Zip file.
+ /// <br/>
+ /// <br/>Author of the original java version : Jochen Hoenicke
+ /// </summary>
+ public class ZipEntry
+ {
+ [Flags]
+ enum Known : byte
+ {
+ None = 0,
+ Size = 0x01,
+ CompressedSize = 0x02,
+ Crc = 0x04,
+ Time = 0x08,
+ ExternalAttributes = 0x10,
+ }
+
+ #region Constructors
+ /// <summary>
+ /// Creates a zip entry with the given name.
+ /// </summary>
+ /// <param name="name">
+ /// The name for this entry. Can include directory components.
+ /// The convention for names is 'unix' style paths with relative names only.
+ /// There are with no device names and path elements are separated by '/' characters.
+ /// </param>
+ /// <exception cref="ArgumentNullException">
+ /// The name passed is null
+ /// </exception>
+ public ZipEntry(string name)
+ : this(name, 0, ZipConstants.VersionMadeBy, CompressionMethod.Deflated)
+ {
+ }
+
+ /// <summary>
+ /// Creates a zip entry with the given name and version required to extract
+ /// </summary>
+ /// <param name="name">
+ /// The name for this entry. Can include directory components.
+ /// The convention for names is 'unix' style paths with no device names and
+ /// path elements separated by '/' characters. This is not enforced see <see cref="CleanName(string)">CleanName</see>
+ /// on how to ensure names are valid if this is desired.
+ /// </param>
+ /// <param name="versionRequiredToExtract">
+ /// The minimum 'feature version' required this entry
+ /// </param>
+ /// <exception cref="ArgumentNullException">
+ /// The name passed is null
+ /// </exception>
+ internal ZipEntry(string name, int versionRequiredToExtract)
+ : this(name, versionRequiredToExtract, ZipConstants.VersionMadeBy,
+ CompressionMethod.Deflated)
+ {
+ }
+
+ /// <summary>
+ /// Initializes an entry with the given name and made by information
+ /// </summary>
+ /// <param name="name">Name for this entry</param>
+ /// <param name="madeByInfo">Version and HostSystem Information</param>
+ /// <param name="versionRequiredToExtract">Minimum required zip feature version required to extract this entry</param>
+ /// <param name="method">Compression method for this entry.</param>
+ /// <exception cref="ArgumentNullException">
+ /// The name passed is null
+ /// </exception>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// versionRequiredToExtract should be 0 (auto-calculate) or > 10
+ /// </exception>
+ /// <remarks>
+ /// This constructor is used by the ZipFile class when reading from the central header
+ /// It is not generally useful, use the constructor specifying the name only.
+ /// </remarks>
+ internal ZipEntry(string name, int versionRequiredToExtract, int madeByInfo,
+ CompressionMethod method)
+ {
+ if (name == null) {
+ throw new System.ArgumentNullException("ZipEntry name");
+ }
+
+ if ( name.Length > 0xffff ) {
+ throw new ArgumentException("Name is too long", "name");
+ }
+
+ if ( (versionRequiredToExtract != 0) && (versionRequiredToExtract < 10) ) {
+ throw new ArgumentOutOfRangeException("versionRequiredToExtract");
+ }
+
+ this.DateTime = System.DateTime.Now;
+ this.name = name;
+ this.versionMadeBy = (ushort)madeByInfo;
+ this.versionToExtract = (ushort)versionRequiredToExtract;
+ this.method = method;
+ }
+
+ /// <summary>
+ /// Creates a deep copy of the given zip entry.
+ /// </summary>
+ /// <param name="entry">
+ /// The entry to copy.
+ /// </param>
+ [Obsolete("Use Clone instead")]
+ public ZipEntry(ZipEntry entry)
+ {
+ if ( entry == null ) {
+ throw new ArgumentNullException("entry");
+ }
+
+ known = entry.known;
+ name = entry.name;
+ size = entry.size;
+ compressedSize = entry.compressedSize;
+ crc = entry.crc;
+ dosTime = entry.dosTime;
+ method = entry.method;
+ comment = entry.comment;
+ versionToExtract = entry.versionToExtract;
+ versionMadeBy = entry.versionMadeBy;
+ externalFileAttributes = entry.externalFileAttributes;
+ flags = entry.flags;
+
+ zipFileIndex = entry.zipFileIndex;
+ offset = entry.offset;
+
+ forceZip64_ = entry.forceZip64_;
+
+ if ( entry.extra != null ) {
+ extra = new byte[entry.extra.Length];
+ Array.Copy(entry.extra, 0, extra, 0, entry.extra.Length);
+ }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Get a value indicating wether the entry has a CRC value available.
+ /// </summary>
+ public bool HasCrc
+ {
+ get {
+ return (known & Known.Crc) != 0;
+ }
+ }
+
+ /// <summary>
+ /// Get/Set flag indicating if entry is encrypted.
+ /// A simple helper routine to aid interpretation of <see cref="Flags">flags</see>
+ /// </summary>
+ /// <remarks>This is an assistant that interprets the <see cref="Flags">flags</see> property.</remarks>
+ public bool IsCrypted
+ {
+ get {
+ return (flags & 1) != 0;
+ }
+ set {
+ if (value) {
+ flags |= 1;
+ }
+ else {
+ flags &= ~1;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Get / set a flag indicating wether entry name and comment text are
+ /// encoded in <a href="http://www.unicode.org">unicode UTF8</a>.
+ /// </summary>
+ /// <remarks>This is an assistant that interprets the <see cref="Flags">flags</see> property.</remarks>
+ public bool IsUnicodeText
+ {
+ get {
+ return ( flags & (int)GeneralBitFlags.UnicodeText ) != 0;
+ }
+ set {
+ if ( value ) {
+ flags |= (int)GeneralBitFlags.UnicodeText;
+ }
+ else {
+ flags &= ~(int)GeneralBitFlags.UnicodeText;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Value used during password checking for PKZIP 2.0 / 'classic' encryption.
+ /// </summary>
+ internal byte CryptoCheckValue
+ {
+ get {
+ return cryptoCheckValue_;
+ }
+
+ set {
+ cryptoCheckValue_ = value;
+ }
+ }
+
+ /// <summary>
+ /// Get/Set general purpose bit flag for entry
+ /// </summary>
+ /// <remarks>
+ /// General purpose bit flag<br/>
+ /// <br/>
+ /// Bit 0: If set, indicates the file is encrypted<br/>
+ /// Bit 1-2 Only used for compression type 6 Imploding, and 8, 9 deflating<br/>
+ /// Imploding:<br/>
+ /// Bit 1 if set indicates an 8K sliding dictionary was used. If clear a 4k dictionary was used<br/>
+ /// Bit 2 if set indicates 3 Shannon-Fanno trees were used to encode the sliding dictionary, 2 otherwise<br/>
+ /// <br/>
+ /// Deflating:<br/>
+ /// Bit 2 Bit 1<br/>
+ /// 0 0 Normal compression was used<br/>
+ /// 0 1 Maximum compression was used<br/>
+ /// 1 0 Fast compression was used<br/>
+ /// 1 1 Super fast compression was used<br/>
+ /// <br/>
+ /// Bit 3: If set, the fields crc-32, compressed size
+ /// and uncompressed size are were not able to be written during zip file creation
+ /// The correct values are held in a data descriptor immediately following the compressed data. <br/>
+ /// Bit 4: Reserved for use by PKZIP for enhanced deflating<br/>
+ /// Bit 5: If set indicates the file contains compressed patch data<br/>
+ /// Bit 6: If set indicates strong encryption was used.<br/>
+ /// Bit 7-10: Unused or reserved<br/>
+ /// Bit 11: If set the name and comments for this entry are in <a href="http://www.unicode.org">unicode</a>.<br/>
+ /// Bit 12-15: Unused or reserved<br/>
+ /// </remarks>
+ /// <seealso cref="IsUnicodeText"></seealso>
+ /// <seealso cref="IsCrypted"></seealso>
+ public int Flags
+ {
+ get {
+ return flags;
+ }
+ set {
+ flags = value;
+ }
+ }
+
+ /// <summary>
+ /// Get/Set index of this entry in Zip file
+ /// </summary>
+ /// <remarks>This is only valid when the entry is part of a <see cref="ZipFile"></see></remarks>
+ public long ZipFileIndex
+ {
+ get {
+ return zipFileIndex;
+ }
+ set {
+ zipFileIndex = value;
+ }
+ }
+
+ /// <summary>
+ /// Get/set offset for use in central header
+ /// </summary>
+ public long Offset
+ {
+ get {
+ return offset;
+ }
+ set {
+ offset = value;
+ }
+ }
+
+ /// <summary>
+ /// Get/Set external file attributes as an integer.
+ /// The values of this are operating system dependant see
+ /// <see cref="HostSystem">HostSystem</see> for details
+ /// </summary>
+ public int ExternalFileAttributes
+ {
+ get {
+ if ((known & Known.ExternalAttributes) == 0) {
+ return -1;
+ }
+ else {
+ return externalFileAttributes;
+ }
+ }
+
+ set {
+ externalFileAttributes = value;
+ known |= Known.ExternalAttributes;
+ }
+ }
+
+ /// <summary>
+ /// Get the version made by for this entry or zero if unknown.
+ /// The value / 10 indicates the major version number, and
+ /// the value mod 10 is the minor version number
+ /// </summary>
+ public int VersionMadeBy
+ {
+ get {
+ return (versionMadeBy & 0xff);
+ }
+ }
+
+ /// <summary>
+ /// Get a value indicating this entry is for a DOS/Windows system.
+ /// </summary>
+ public bool IsDOSEntry
+ {
+ get {
+ return ((HostSystem == ( int )HostSystemID.Msdos) ||
+ (HostSystem == ( int )HostSystemID.WindowsNT));
+ }
+ }
+
+ /// <summary>
+ /// Test the external attributes for this <see cref="ZipEntry"/> to
+ /// see if the external attributes are Dos based (including WINNT and variants)
+ /// and match the values
+ /// </summary>
+ /// <param name="attributes">The attributes to test.</param>
+ /// <returns>Returns true if the external attributes are known to be DOS/Windows
+ /// based and have the same attributes set as the value passed.</returns>
+ bool HasDosAttributes(int attributes)
+ {
+ bool result = false;
+ if ( (known & Known.ExternalAttributes) != 0 ) {
+ if ( ((HostSystem == (int)HostSystemID.Msdos) ||
+ (HostSystem == (int)HostSystemID.WindowsNT)) &&
+ (ExternalFileAttributes & attributes) == attributes) {
+ result = true;
+ }
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Gets the compatability information for the <see cref="ExternalFileAttributes">external file attribute</see>
+ /// If the external file attributes are compatible with MS-DOS and can be read
+ /// by PKZIP for DOS version 2.04g then this value will be zero. Otherwise the value
+ /// will be non-zero and identify the host system on which the attributes are compatible.
+ /// </summary>
+ ///
+ /// <remarks>
+ /// The values for this as defined in the Zip File format and by others are shown below. The values are somewhat
+ /// misleading in some cases as they are not all used as shown. You should consult the relevant documentation
+ /// to obtain up to date and correct information. The modified appnote by the infozip group is
+ /// particularly helpful as it documents a lot of peculiarities. The document is however a little dated.
+ /// <list type="table">
+ /// <item>0 - MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)</item>
+ /// <item>1 - Amiga</item>
+ /// <item>2 - OpenVMS</item>
+ /// <item>3 - Unix</item>
+ /// <item>4 - VM/CMS</item>
+ /// <item>5 - Atari ST</item>
+ /// <item>6 - OS/2 HPFS</item>
+ /// <item>7 - Macintosh</item>
+ /// <item>8 - Z-System</item>
+ /// <item>9 - CP/M</item>
+ /// <item>10 - Windows NTFS</item>
+ /// <item>11 - MVS (OS/390 - Z/OS)</item>
+ /// <item>12 - VSE</item>
+ /// <item>13 - Acorn Risc</item>
+ /// <item>14 - VFAT</item>
+ /// <item>15 - Alternate MVS</item>
+ /// <item>16 - BeOS</item>
+ /// <item>17 - Tandem</item>
+ /// <item>18 - OS/400</item>
+ /// <item>19 - OS/X (Darwin)</item>
+ /// <item>99 - WinZip AES</item>
+ /// <item>remainder - unused</item>
+ /// </list>
+ /// </remarks>
+ public int HostSystem
+ {
+ get {
+ return (versionMadeBy >> 8) & 0xff;
+ }
+
+ set {
+ versionMadeBy &= 0xff;
+ versionMadeBy |= (ushort)((value & 0xff) << 8);
+ }
+ }
+
+ /// <summary>
+ /// Get minimum Zip feature version required to extract this entry
+ /// </summary>
+ /// <remarks>
+ /// Minimum features are defined as:<br/>
+ /// 1.0 - Default value<br/>
+ /// 1.1 - File is a volume label<br/>
+ /// 2.0 - File is a folder/directory<br/>
+ /// 2.0 - File is compressed using Deflate compression<br/>
+ /// 2.0 - File is encrypted using traditional encryption<br/>
+ /// 2.1 - File is compressed using Deflate64<br/>
+ /// 2.5 - File is compressed using PKWARE DCL Implode<br/>
+ /// 2.7 - File is a patch data set<br/>
+ /// 4.5 - File uses Zip64 format extensions<br/>
+ /// 4.6 - File is compressed using BZIP2 compression<br/>
+ /// 5.0 - File is encrypted using DES<br/>
+ /// 5.0 - File is encrypted using 3DES<br/>
+ /// 5.0 - File is encrypted using original RC2 encryption<br/>
+ /// 5.0 - File is encrypted using RC4 encryption<br/>
+ /// 5.1 - File is encrypted using AES encryption<br/>
+ /// 5.1 - File is encrypted using corrected RC2 encryption<br/>
+ /// 5.1 - File is encrypted using corrected RC2-64 encryption<br/>
+ /// 6.1 - File is encrypted using non-OAEP key wrapping<br/>
+ /// 6.2 - Central directory encryption (not confirmed yet)<br/>
+ /// 6.3 - File is compressed using LZMA<br/>
+ /// 6.3 - File is compressed using PPMD+<br/>
+ /// 6.3 - File is encrypted using Blowfish<br/>
+ /// 6.3 - File is encrypted using Twofish<br/>
+ /// </remarks>
+ /// <seealso cref="CanDecompress"></seealso>
+ public int Version
+ {
+ get {
+ // Return recorded version if known.
+ if (versionToExtract != 0) {
+ return versionToExtract;
+ }
+ else {
+ int result = 10;
+ if ( CentralHeaderRequiresZip64 ) {
+ result = ZipConstants.VersionZip64;
+ }
+ else if (CompressionMethod.Deflated == method) {
+ result = 20;
+ }
+ else if (IsDirectory == true) {
+ result = 20;
+ }
+ else if (IsCrypted == true) {
+ result = 20;
+ }
+ else if (HasDosAttributes(0x08) ) {
+ result = 11;
+ }
+ return result;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Get a value indicating wether this entry can be decompressed by the library.
+ /// </summary>
+ /// <remarks>This is based on the <see cref="Version"></see> and
+ /// wether the <see cref="IsCompressionMethodSupported()">compression method</see> is supported.</remarks>
+ public bool CanDecompress
+ {
+ get {
+ return (Version <= ZipConstants.VersionMadeBy) &&
+ ((Version == 10) ||
+ (Version == 11) ||
+ (Version == 20) ||
+ (Version == 45)) &&
+ IsCompressionMethodSupported();
+ }
+ }
+
+ /// <summary>
+ /// Force this entry to be recorded using Zip64 extensions.
+ /// </summary>
+ public void ForceZip64()
+ {
+ forceZip64_ = true;
+ }
+
+ /// <summary>
+ /// Get a value indicating wether Zip64 extensions were forced.
+ /// </summary>
+ /// <returns>A <see cref="bool"/> value of true if Zip64 extensions have been forced on; false if not.</returns>
+ public bool IsZip64Forced()
+ {
+ return forceZip64_;
+ }
+
+ /// <summary>
+ /// Gets a value indicating if the entry requires Zip64 extensions
+ /// to store the full entry values.
+ /// </summary>
+ /// <value>A <see cref="bool"/> value of true if a local header requires Zip64 extensions; false if not.</value>
+ public bool LocalHeaderRequiresZip64
+ {
+ get {
+ bool result = forceZip64_;
+
+ if ( !result ) {
+ ulong trueCompressedSize = compressedSize;
+
+ if ( (versionToExtract == 0) && IsCrypted ) {
+ trueCompressedSize += ZipConstants.CryptoHeaderSize;
+ }
+
+ // TODO: A better estimation of the true limit based on compression overhead should be used
+ // to determine when an entry should use Zip64.
+ result =
+ ((this.size >= uint.MaxValue) || (trueCompressedSize >= uint.MaxValue)) &&
+ ((versionToExtract == 0) || (versionToExtract >= ZipConstants.VersionZip64));
+ }
+
+ return result;
+ }
+ }
+
+ /// <summary>
+ /// Get a value indicating wether the central directory entry requires Zip64 extensions to be stored.
+ /// </summary>
+ public bool CentralHeaderRequiresZip64
+ {
+ get {
+ return LocalHeaderRequiresZip64 || (offset >= uint.MaxValue);
+ }
+ }
+
+ /// <summary>
+ /// Get/Set DosTime value.
+ /// </summary>
+ /// <remarks>
+ /// The MS-DOS date format can only represent dates between 1/1/1980 and 12/31/2107.
+ /// </remarks>
+ public long DosTime
+ {
+ get {
+ if ((known & Known.Time) == 0) {
+ return 0;
+ }
+ else {
+ return dosTime;
+ }
+ }
+
+ set {
+ unchecked {
+ dosTime = (uint)value;
+ }
+
+ known |= Known.Time;
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the time of last modification of the entry.
+ /// </summary>
+ /// <remarks>
+ /// The <see cref="DosTime"></see> property is updated to match this as far as possible.
+ /// </remarks>
+ public DateTime DateTime
+ {
+ get {
+ var sec = Math.Min(59, (int) (2 * (dosTime & 0x1f)));
+ var min = Math.Min(59, (int) ((dosTime >> 5) & 0x3f));
+ var hrs = Math.Min(23, (int) ((dosTime >> 11) & 0x1f));
+ var mon = Math.Max(1, Math.Min(12, (int) ((dosTime >> 21) & 0xf)));
+ var year = ((dosTime >> 25) & 0x7f) + 1980;
+ var day = Math.Max(1, Math.Min(DateTime.DaysInMonth((int)year, (int)mon), (int)((dosTime >> 16) & 0x1f)));
+ return new DateTime((int)year, (int)mon, day, (int)hrs, (int)min, (int)sec);
+ }
+ set {
+ var year = (uint) value.Year;
+ var month = (uint) value.Month;
+ var day = (uint) value.Day;
+ var hour = (uint) value.Hour;
+ var minute = (uint) value.Minute;
+ var second = (uint) value.Second;
+
+ if ( year < 1980 ) {
+ year = 1980;
+ month = 1;
+ day = 1;
+ hour = 0;
+ minute = 0;
+ second = 0;
+ }
+ else if ( year > 2107 ) {
+ year = 2107;
+ month = 12;
+ day = 31;
+ hour = 23;
+ minute = 59;
+ second = 59;
+ }
+
+ DosTime = ((year - 1980) & 0x7f) << 25 |
+ (month << 21) |
+ (day << 16) |
+ (hour << 11) |
+ (minute << 5) |
+ (second >> 1);
+ }
+ }
+
+ /// <summary>
+ /// Returns the entry name.
+ /// </summary>
+ /// <remarks>
+ /// The unix naming convention is followed.
+ /// Path components in the entry should always separated by forward slashes ('/').
+ /// Dos device names like C: should also be removed.
+ /// See the <see cref="ZipNameTransform"/> class, or <see cref="CleanName(string)"/>
+ ///</remarks>
+ public string Name
+ {
+ get {
+ return name;
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the size of the uncompressed data.
+ /// </summary>
+ /// <returns>
+ /// The size or -1 if unknown.
+ /// </returns>
+ /// <remarks>Setting the size before adding an entry to an archive can help
+ /// avoid compatability problems with some archivers which dont understand Zip64 extensions.</remarks>
+ public long Size
+ {
+ get {
+ return (known & Known.Size) != 0 ? (long)size : -1L;
+ }
+ set {
+ this.size = (ulong)value;
+ this.known |= Known.Size;
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the size of the compressed data.
+ /// </summary>
+ /// <returns>
+ /// The compressed entry size or -1 if unknown.
+ /// </returns>
+ public long CompressedSize
+ {
+ get {
+ return (known & Known.CompressedSize) != 0 ? (long)compressedSize : -1L;
+ }
+ set {
+ this.compressedSize = (ulong)value;
+ this.known |= Known.CompressedSize;
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the crc of the uncompressed data.
+ /// </summary>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Crc is not in the range 0..0xffffffffL
+ /// </exception>
+ /// <returns>
+ /// The crc value or -1 if unknown.
+ /// </returns>
+ public long Crc
+ {
+ get {
+ return (known & Known.Crc) != 0 ? crc & 0xffffffffL : -1L;
+ }
+ set {
+ if (((ulong)crc & 0xffffffff00000000L) != 0) {
+ throw new ArgumentOutOfRangeException("value");
+ }
+ this.crc = (uint)value;
+ this.known |= Known.Crc;
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the compression method. Only Deflated and Stored are supported.
+ /// </summary>
+ /// <returns>
+ /// The compression method for this entry
+ /// </returns>
+ /// <see cref="Zip.CompressionMethod.Deflated"/>
+ /// <see cref="Zip.CompressionMethod.Stored"/>
+ public CompressionMethod CompressionMethod {
+ get {
+ return method;
+ }
+
+ set {
+ if ( !IsCompressionMethodSupported(value) ) {
+ throw new NotSupportedException("Compression method not supported");
+ }
+ this.method = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the extra data.
+ /// </summary>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Extra data is longer than 64KB (0xffff) bytes.
+ /// </exception>
+ /// <returns>
+ /// Extra data or null if not set.
+ /// </returns>
+ public byte[] ExtraData {
+
+ get {
+// TODO: This is slightly safer but less efficient. Think about wether it should change.
+// return (byte[]) extra.Clone();
+ return extra;
+ }
+
+ set {
+ if (value == null) {
+ extra = null;
+ }
+ else {
+ if (value.Length > 0xffff) {
+ throw new System.ArgumentOutOfRangeException("value");
+ }
+
+ extra = new byte[value.Length];
+ Array.Copy(value, 0, extra, 0, value.Length);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Process extra data fields updating the entry based on the contents.
+ /// </summary>
+ /// <param name="localHeader">True if the extra data fields should be handled
+ /// for a local header, rather than for a central header.
+ /// </param>
+ internal void ProcessExtraData(bool localHeader)
+ {
+ ZipExtraData extraData = new ZipExtraData(this.extra);
+
+ if ( extraData.Find(0x0001) ) {
+ if ( (versionToExtract & 0xff) < ZipConstants.VersionZip64 ) {
+ throw new ZipException("Zip64 Extended information found but version is not valid");
+ }
+
+ // The recorded size will change but remember that this is zip64.
+ forceZip64_ = true;
+
+ if ( extraData.ValueLength < 4 ) {
+ throw new ZipException("Extra data extended Zip64 information length is invalid");
+ }
+
+ if ( localHeader || (size == uint.MaxValue) ) {
+ size = (ulong)extraData.ReadLong();
+ }
+
+ if ( localHeader || (compressedSize == uint.MaxValue) ) {
+ compressedSize = (ulong)extraData.ReadLong();
+ }
+
+ if ( !localHeader && (offset == uint.MaxValue) ) {
+ offset = extraData.ReadLong();
+ }
+ }
+ else {
+ if (
+ ((versionToExtract & 0xff) >= ZipConstants.VersionZip64) &&
+ ((size == uint.MaxValue) || (compressedSize == uint.MaxValue))
+ ) {
+ throw new ZipException("Zip64 Extended information required but is missing.");
+ }
+ }
+
+ if ( extraData.Find(10) ) {
+ // No room for any tags.
+ if ( extraData.ValueLength < 8 ) {
+ throw new ZipException("NTFS Extra data invalid");
+ }
+
+ extraData.ReadInt(); // Reserved
+
+ while ( extraData.UnreadCount >= 4 ) {
+ int ntfsTag = extraData.ReadShort();
+ int ntfsLength = extraData.ReadShort();
+ if ( ntfsTag == 1 ) {
+ if ( ntfsLength >= 24 ) {
+ long lastModification = extraData.ReadLong();
+ long lastAccess = extraData.ReadLong();
+ long createTime = extraData.ReadLong();
+
+ DateTime = System.DateTime.FromFileTime(lastModification);
+ }
+ break;
+ }
+ else {
+ // An unknown NTFS tag so simply skip it.
+ extraData.Skip(ntfsLength);
+ }
+ }
+ }
+ else if ( extraData.Find(0x5455) ) {
+ int length = extraData.ValueLength;
+ int flags = extraData.ReadByte();
+
+ // Can include other times but these are ignored. Length of data should
+ // actually be 1 + 4 * no of bits in flags.
+ if ( ((flags & 1) != 0) && (length >= 5) ) {
+ int iTime = extraData.ReadInt();
+
+ DateTime = (new System.DateTime ( 1970, 1, 1, 0, 0, 0 ).ToUniversalTime() +
+ new TimeSpan ( 0, 0, 0, iTime, 0 )).ToLocalTime();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the entry comment.
+ /// </summary>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// If comment is longer than 0xffff.
+ /// </exception>
+ /// <returns>
+ /// The comment or null if not set.
+ /// </returns>
+ /// <remarks>
+ /// A comment is only available for entries when read via the <see cref="ZipFile"/> class.
+ /// The <see cref="ZipInputStream"/> class doesnt have the comment data available.
+ /// </remarks>
+ public string Comment {
+ get {
+ return comment;
+ }
+ set {
+ // This test is strictly incorrect as the length is in characters
+ // while the storage limit is in bytes.
+ // While the test is partially correct in that a comment of this length or greater
+ // is definitely invalid, shorter comments may also have an invalid length
+ // where there are multi-byte characters
+ // The full test is not possible here however as the code page to apply conversions with
+ // isnt available.
+ if ( (value != null) && (value.Length > 0xffff) ) {
+ throw new ArgumentOutOfRangeException("value", "cannot exceed 65535");
+ }
+
+ comment = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets a value indicating if the entry is a directory.
+ /// however.
+ /// </summary>
+ /// <remarks>
+ /// A directory is determined by an entry name with a trailing slash '/'.
+ /// The external file attributes can also indicate an entry is for a directory.
+ /// Currently only dos/windows attributes are tested in this manner.
+ /// The trailing slash convention should always be followed.
+ /// </remarks>
+ public bool IsDirectory
+ {
+ get {
+ int nameLength = name.Length;
+ bool result =
+ ((nameLength > 0) &&
+ ((name[nameLength - 1] == '/') || (name[nameLength - 1] == '\\'))) ||
+ HasDosAttributes(16)
+ ;
+ return result;
+ }
+ }
+
+ /// <summary>
+ /// Get a value of true if the entry appears to be a file; false otherwise
+ /// </summary>
+ /// <remarks>
+ /// This only takes account of DOS/Windows attributes. Other operating systems are ignored.
+ /// For linux and others the result may be incorrect.
+ /// </remarks>
+ public bool IsFile
+ {
+ get {
+ return !IsDirectory && !HasDosAttributes(8);
+ }
+ }
+
+ /// <summary>
+ /// Test entry to see if data can be extracted.
+ /// </summary>
+ /// <returns>Returns true if data can be extracted for this entry; false otherwise.</returns>
+ public bool IsCompressionMethodSupported()
+ {
+ return IsCompressionMethodSupported(CompressionMethod);
+ }
+
+ #region ICloneable Members
+ /// <summary>
+ /// Creates a copy of this zip entry.
+ /// </summary>
+ /// <returns>An <see cref="Object"/> that is a copy of the current instance.</returns>
+ public object Clone()
+ {
+ ZipEntry result = (ZipEntry)this.MemberwiseClone();
+
+ // Ensure extra data is unique if it exists.
+ if ( extra != null ) {
+ result.extra = new byte[extra.Length];
+ Array.Copy(extra, 0, result.extra, 0, extra.Length);
+ }
+
+ return result;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Gets a string representation of this ZipEntry.
+ /// </summary>
+ /// <returns>A readable textual representation of this <see cref="ZipEntry"/></returns>
+ public override string ToString()
+ {
+ return name;
+ }
+
+ /// <summary>
+ /// Test a <see cref="CompressionMethod">compression method</see> to see if this library
+ /// supports extracting data compressed with that method
+ /// </summary>
+ /// <param name="method">The compression method to test.</param>
+ /// <returns>Returns true if the compression method is supported; false otherwise</returns>
+ public static bool IsCompressionMethodSupported(CompressionMethod method)
+ {
+ return
+ ( method == CompressionMethod.Deflated ) ||
+ ( method == CompressionMethod.Stored );
+ }
+
+ /// <summary>
+ /// Cleans a name making it conform to Zip file conventions.
+ /// Devices names ('c:\') and UNC share names ('\\server\share') are removed
+ /// and forward slashes ('\') are converted to back slashes ('/').
+ /// Names are made relative by trimming leading slashes which is compatible
+ /// with the ZIP naming convention.
+ /// </summary>
+ /// <param name="name">The name to clean</param>
+ /// <returns>The 'cleaned' name.</returns>
+ /// <remarks>
+ /// The <seealso cref="ZipNameTransform">Zip name transform</seealso> class is more flexible.
+ /// </remarks>
+ public static string CleanName(string name)
+ {
+ if (name == null) {
+ return string.Empty;
+ }
+
+ if (Path.IsPathRooted(name) == true) {
+ // NOTE:
+ // for UNC names... \\machine\share\zoom\beet.txt gives \zoom\beet.txt
+ name = name.Substring(Path.GetPathRoot(name).Length);
+ }
+
+ name = name.Replace(@"\", "/");
+
+ while ( (name.Length > 0) && (name[0] == '/')) {
+ name = name.Remove(0, 1);
+ }
+ return name;
+ }
+
+ #region Instance Fields
+ Known known;
+ int externalFileAttributes = -1; // contains external attributes (O/S dependant)
+
+ ushort versionMadeBy; // Contains host system and version information
+ // only relevant for central header entries
+
+ string name;
+ ulong size;
+ ulong compressedSize;
+ ushort versionToExtract; // Version required to extract (library handles <= 2.0)
+ uint crc;
+ uint dosTime;
+
+ CompressionMethod method = CompressionMethod.Deflated;
+ byte[] extra;
+ string comment;
+
+ int flags; // general purpose bit flags
+
+ long zipFileIndex = -1; // used by ZipFile
+ long offset; // used by ZipFile and ZipOutputStream
+
+ bool forceZip64_;
+ byte cryptoCheckValue_;
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+// ZipEntryFactory.cs
+//
+// Copyright 2006 John Reilly
+//
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+using ICSharpCode.SharpZipLib.Silverlight.Core;
+using IEntryFactory=ICSharpCode.SharpZipLib.Silverlight.Zip.IEntryFactory;
+using ZipEntry=ICSharpCode.SharpZipLib.Silverlight.Zip.ZipEntry;
+using ZipException=ICSharpCode.SharpZipLib.Silverlight.Zip.ZipException;
+using ZipNameTransform=ICSharpCode.SharpZipLib.Zip.ZipNameTransform;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip
+{
+ /// <summary>
+ /// Basic implementation of <see cref="IEntryFactory"></see>
+ /// </summary>
+ public class ZipEntryFactory : IEntryFactory
+ {
+ #region Enumerations
+ /// <summary>
+ /// Defines the possible values to be used for the <see cref="ZipEntry.DateTime"/>.
+ /// </summary>
+ public enum TimeSetting
+ {
+ /// <summary>
+ /// Use the recorded LastWriteTime value for the file.
+ /// </summary>
+ LastWriteTime,
+ /// <summary>
+ /// Use the recorded LastWriteTimeUtc value for the file
+ /// </summary>
+ LastWriteTimeUtc,
+ /// <summary>
+ /// Use the recorded CreateTime value for the file.
+ /// </summary>
+ CreateTime,
+ /// <summary>
+ /// Use the recorded CreateTimeUtc value for the file.
+ /// </summary>
+ CreateTimeUtc,
+ /// <summary>
+ /// Use the recorded LastAccessTime value for the file.
+ /// </summary>
+ LastAccessTime,
+ /// <summary>
+ /// Use the recorded LastAccessTimeUtc value for the file.
+ /// </summary>
+ LastAccessTimeUtc,
+ /// <summary>
+ /// Use a fixed value.
+ /// </summary>
+ /// <remarks>The actual <see cref="DateTime"/> value used can be
+ /// specified via the <see cref="ZipEntryFactory(DateTime)"/> constructor or
+ /// using the <see cref="ZipEntryFactory(TimeSetting)"/> with the setting set
+ /// to <see cref="TimeSetting.Fixed"/> which will use the <see cref="DateTime"/> when this class was constructed.
+ /// The <see cref="FixedDateTime"/> property can also be used to set this value.</remarks>
+ Fixed,
+ }
+ #endregion
+
+ #region Constructors
+ /// <summary>
+ /// Initialise a new instance of the <see cref="ZipEntryFactory"/> class.
+ /// </summary>
+ /// <remarks>A default <see cref="INameTransform"/>, and the LastWriteTime for files is used.</remarks>
+ public ZipEntryFactory()
+ {
+ nameTransform_ = new ZipNameTransform();
+ }
+
+ /// <summary>
+ /// Initialise a new instance of <see cref="ZipEntryFactory"/> using the specified <see cref="TimeSetting"/>
+ /// </summary>
+ /// <param name="timeSetting">The <see cref="TimeSetting">time setting</see> to use when creating <see cref="ZipEntry">Zip entries</see>.</param>
+ public ZipEntryFactory(TimeSetting timeSetting)
+ {
+ timeSetting_ = timeSetting;
+ nameTransform_ = new ZipNameTransform();
+ }
+
+ /// <summary>
+ /// Initialise a new instance of <see cref="ZipEntryFactory"/> using the specified <see cref="DateTime"/>
+ /// </summary>
+ /// <param name="time">The time to set all <see cref="ZipEntry.DateTime"/> values to.</param>
+ public ZipEntryFactory(DateTime time)
+ {
+ timeSetting_ = TimeSetting.Fixed;
+ FixedDateTime = time;
+ nameTransform_ = new ZipNameTransform();
+ }
+
+ #endregion
+
+ #region Properties
+ /// <summary>
+ /// Get / set the <see cref="INameTransform"/> to be used when creating new <see cref="ZipEntry"/> values.
+ /// </summary>
+ /// <remarks>
+ /// Setting this property to null will cause a default <see cref="ZipNameTransform">name transform</see> to be used.
+ /// </remarks>
+ public INameTransform NameTransform
+ {
+ get { return nameTransform_; }
+ set
+ {
+ nameTransform_ = value ?? new ZipNameTransform();
+ }
+ }
+
+ /// <summary>
+ /// Get / set the <see cref="TimeSetting"/> in use.
+ /// </summary>
+ public TimeSetting Setting
+ {
+ get { return timeSetting_; }
+ set { timeSetting_ = value; }
+ }
+
+ /// <summary>
+ /// Get / set the <see cref="DateTime"/> value to use when <see cref="Setting"/> is set to <see cref="TimeSetting.Fixed"/>
+ /// </summary>
+ public DateTime FixedDateTime
+ {
+ get { return fixedDateTime_; }
+ set
+ {
+ if (value.Year < 1970) {
+ throw new ArgumentException("Value is too old to be valid", "value");
+ }
+ fixedDateTime_ = value;
+ }
+ }
+
+ /// <summary>
+ /// A bitmask defining the attributes to be retrieved from the actual file.
+ /// </summary>
+ /// <remarks>The default is to get all possible attributes from the actual file.</remarks>
+ public int GetAttributes
+ {
+ get { return getAttributes_; }
+ set { getAttributes_ = value; }
+ }
+
+ /// <summary>
+ /// A bitmask defining which attributes are to be set on.
+ /// </summary>
+ /// <remarks>By default no attributes are set on.</remarks>
+ public int SetAttributes
+ {
+ get { return setAttributes_; }
+ set { setAttributes_ = value; }
+ }
+
+ /// <summary>
+ /// Get set a value indicating wether unidoce text should be set on.
+ /// </summary>
+ public bool IsUnicodeText
+ {
+ get { return isUnicodeText_; }
+ set { isUnicodeText_ = value; }
+ }
+
+ #endregion
+
+ #region IEntryFactory Members
+
+ /// <summary>
+ /// Make a new <see cref="ZipEntry"/> for a file.
+ /// </summary>
+ /// <param name="fileName">The name of the file to create a new entry for.</param>
+ /// <returns>Returns a new <see cref="ZipEntry"/> based on the <paramref name="fileName"/>.</returns>
+ public ZipEntry MakeFileEntry(string fileName)
+ {
+ return MakeFileEntry(fileName, true);
+ }
+
+ /// <summary>
+ /// Make a new <see cref="ZipEntry"/> from a name.
+ /// </summary>
+ /// <param name="fileName">The name of the file to create a new entry for.</param>
+ /// <param name="useFileSystem">If true entry detail is retrieved from the file system if the file exists.</param>
+ /// <returns>Returns a new <see cref="ZipEntry"/> based on the <paramref name="fileName"/>.</returns>
+ public ZipEntry MakeFileEntry(string fileName, bool useFileSystem)
+ {
+ var result = new ZipEntry(nameTransform_.TransformFile(fileName)){IsUnicodeText = isUnicodeText_};
+
+ var externalAttributes = 0;
+ var useAttributes = (setAttributes_ != 0);
+
+ FileInfo fi = null;
+ if (useFileSystem)
+ {
+ fi = new FileInfo(fileName);
+ }
+
+ if ((fi != null) && fi.Exists)
+ {
+ switch (timeSetting_)
+ {
+ case TimeSetting.CreateTime:
+ result.DateTime = fi.CreationTime;
+ break;
+
+ //case TimeSetting.CreateTimeUtc:
+ //result.DateTime = fi.CreationTimeUtc;
+ //break;
+
+ case TimeSetting.LastAccessTime:
+ result.DateTime = fi.LastAccessTime;
+ break;
+
+ //case TimeSetting.LastAccessTimeUtc:
+ //result.DateTime = fi.LastAccessTimeUtc;
+ //break;
+
+ case TimeSetting.LastWriteTime:
+ result.DateTime = fi.LastWriteTime;
+ break;
+
+ //case TimeSetting.LastWriteTimeUtc:
+ //result.DateTime = fi.LastWriteTimeUtc;
+ //break;
+
+ case TimeSetting.Fixed:
+ result.DateTime = fixedDateTime_;
+ break;
+
+ default:
+ throw new ZipException("Unhandled time setting in MakeFileEntry");
+ }
+
+ result.Size = fi.Length;
+
+ useAttributes = true;
+ externalAttributes = ((int)fi.Attributes & getAttributes_);
+ }
+ else
+ {
+ if (timeSetting_ == TimeSetting.Fixed)
+ {
+ result.DateTime = fixedDateTime_;
+ }
+ }
+
+ if (useAttributes)
+ {
+ externalAttributes |= setAttributes_;
+ result.ExternalFileAttributes = externalAttributes;
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Make a new <see cref="ZipEntry"></see> for a directory.
+ /// </summary>
+ /// <param name="directoryName">The raw untransformed name for the new directory</param>
+ /// <returns>Returns a new <see cref="ZipEntry"></see> representing a directory.</returns>
+ public ZipEntry MakeDirectoryEntry(string directoryName)
+ {
+ return MakeDirectoryEntry(directoryName, true);
+ }
+
+ /// <summary>
+ /// Make a new <see cref="ZipEntry"></see> for a directory.
+ /// </summary>
+ /// <param name="directoryName">The raw untransformed name for the new directory</param>
+ /// <param name="useFileSystem">If true entry detail is retrieved from the file system if the file exists.</param>
+ /// <returns>Returns a new <see cref="ZipEntry"></see> representing a directory.</returns>
+ public ZipEntry MakeDirectoryEntry(string directoryName, bool useFileSystem)
+ {
+
+ var result = new ZipEntry(nameTransform_.TransformDirectory(directoryName)){Size = 0};
+
+ var externalAttributes = 0;
+
+ DirectoryInfo di = null;
+
+ if (useFileSystem)
+ {
+ di = new DirectoryInfo(directoryName);
+ }
+
+
+ if ((di != null) && di.Exists)
+ {
+ switch (timeSetting_)
+ {
+ case TimeSetting.CreateTime:
+ result.DateTime = di.CreationTime;
+ break;
+
+ //case TimeSetting.CreateTimeUtc:
+ //result.DateTime = di.CreationTimeUtc;
+ //break;
+
+ case TimeSetting.LastAccessTime:
+ result.DateTime = di.LastAccessTime;
+ break;
+
+ //case TimeSetting.LastAccessTimeUtc:
+ //result.DateTime = di.LastAccessTimeUtc;
+ //break;
+
+ case TimeSetting.LastWriteTime:
+ result.DateTime = di.LastWriteTime;
+ break;
+
+ //case TimeSetting.LastWriteTimeUtc:
+ //result.DateTime = di.LastWriteTimeUtc;
+ //break;
+
+ case TimeSetting.Fixed:
+ result.DateTime = fixedDateTime_;
+ break;
+
+ default:
+ throw new ZipException("Unhandled time setting in MakeDirectoryEntry");
+ }
+
+ externalAttributes = ((int)di.Attributes & getAttributes_);
+ }
+ else
+ {
+ if (timeSetting_ == TimeSetting.Fixed)
+ {
+ result.DateTime = fixedDateTime_;
+ }
+ }
+
+ // Always set directory attribute on.
+ externalAttributes |= (setAttributes_ | 16);
+ result.ExternalFileAttributes = externalAttributes;
+
+ return result;
+ }
+
+ #endregion
+
+ #region Instance Fields
+ INameTransform nameTransform_;
+ DateTime fixedDateTime_ = DateTime.Now;
+ TimeSetting timeSetting_;
+ bool isUnicodeText_;
+
+ int getAttributes_ = -1;
+ int setAttributes_;
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+// ZipException.cs
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using ICSharpCode.SharpZipLib.Silverlight;
+using ICSharpCode.SharpZipLib.Silverlight.Serialization;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip
+{
+ /// <summary>
+ /// Represents exception conditions specific to Zip archive handling
+ /// </summary>
+ [Serializable]
+ public class ZipException : SharpZipBaseException
+ {
+ /// <summary>
+ /// Deserialization constructor
+ /// </summary>
+ /// <param name="info"><see cref="SerializationInfo"/> for this constructor</param>
+ protected ZipException(SerializationInfo info)
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the ZipException class.
+ /// </summary>
+ public ZipException()
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the ZipException class with a specified error message.
+ /// </summary>
+ /// <param name="message">The error message that explains the reason for the exception.</param>
+ public ZipException(string message)
+ : base(message)
+ {
+ }
+
+ /// <summary>
+ /// Initialise a new instance of ZipException.
+ /// </summary>
+ /// <param name="message">A message describing the error.</param>
+ /// <param name="exception">The exception that is the cause of the current exception.</param>
+ public ZipException(string message, Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// ZipExtraData.cs
+//
+// Copyright 2004-2007 John Reilly
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.Collections;
+using System.IO;
+using ICSharpCode.SharpZipLib.Zip;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip
+{
+ /// <summary>
+ /// ExtraData tagged value interface.
+ /// </summary>
+ public interface ITaggedData
+ {
+ /// <summary>
+ /// Get the ID for this tagged data value.
+ /// </summary>
+ short TagID { get; }
+
+ /// <summary>
+ /// Set the contents of this instance from the data passed.
+ /// </summary>
+ /// <param name="data">The data to extract contents from.</param>
+ /// <param name="offset">The offset to begin extracting data from.</param>
+ /// <param name="count">The number of bytes to extract.</param>
+ void SetData(byte[] data, int offset, int count);
+
+ /// <summary>
+ /// Get the data representing this instance.
+ /// </summary>
+ /// <returns>Returns the data for this instance.</returns>
+ byte[] GetData();
+ }
+
+ /// <summary>
+ /// A raw binary tagged value
+ /// </summary>
+ public class RawTaggedData : ITaggedData
+ {
+ /// <summary>
+ /// Initialise a new instance.
+ /// </summary>
+ /// <param name="tag">The tag ID.</param>
+ public RawTaggedData(short tag)
+ {
+ tag_ = tag;
+ }
+
+ #region ITaggedData Members
+
+ /// <summary>
+ /// Get the ID for this tagged data value.
+ /// </summary>
+ public short TagID
+ {
+ get { return tag_; }
+ set { tag_ = value; }
+ }
+
+ /// <summary>
+ /// Set the data from the raw values provided.
+ /// </summary>
+ /// <param name="data">The raw data to extract values from.</param>
+ /// <param name="offset">The index to start extracting values from.</param>
+ /// <param name="count">The number of bytes available.</param>
+ public void SetData(byte[] data, int offset, int count)
+ {
+ if( data==null )
+ {
+ throw new ArgumentNullException("data");
+ }
+
+ data_=new byte[count];
+ Array.Copy(data, offset, data_, 0, count);
+ }
+
+ /// <summary>
+ /// Get the binary data representing this instance.
+ /// </summary>
+ /// <returns>The raw binary data representing this instance.</returns>
+ public byte[] GetData()
+ {
+ return data_;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Get /set the binary data representing this instance.
+ /// </summary>
+ /// <returns>The raw binary data representing this instance.</returns>
+ public byte[] Data
+ {
+ get { return data_; }
+ set { data_=value; }
+ }
+
+ #region Instance Fields
+ /// <summary>
+ /// The tag ID for this instance.
+ /// </summary>
+ protected short tag_;
+
+ byte[] data_;
+ #endregion
+ }
+
+ /// <summary>
+ /// Class representing extended unix date time values.
+ /// </summary>
+ public class ExtendedUnixData : ITaggedData
+ {
+ /// <summary>
+ /// Flags indicate which values are included in this instance.
+ /// </summary>
+ [Flags]
+ public enum Flags : byte
+ {
+ /// <summary>
+ /// The modification time is included
+ /// </summary>
+ ModificationTime = 0x01,
+
+ /// <summary>
+ /// The access time is included
+ /// </summary>
+ AccessTime = 0x02,
+
+ /// <summary>
+ /// The create time is included.
+ /// </summary>
+ CreateTime = 0x04,
+ }
+
+ #region ITaggedData Members
+
+ /// <summary>
+ /// Get the ID
+ /// </summary>
+ public short TagID
+ {
+ get { return 0x5455; }
+ }
+
+ /// <summary>
+ /// Set the data from the raw values provided.
+ /// </summary>
+ /// <param name="data">The raw data to extract values from.</param>
+ /// <param name="index">The index to start extracting values from.</param>
+ /// <param name="count">The number of bytes available.</param>
+ public void SetData(byte[] data, int index, int count)
+ {
+ using (MemoryStream ms = new MemoryStream(data, index, count, false))
+ using (ZipHelperStream helperStream = new ZipHelperStream(ms))
+ {
+ // bit 0 if set, modification time is present
+ // bit 1 if set, access time is present
+ // bit 2 if set, creation time is present
+
+ flags_ = (Flags)helperStream.ReadByte();
+ if (((flags_ & Flags.ModificationTime) != 0) && (count >= 5))
+ {
+ int iTime = helperStream.ReadLEInt();
+
+ modificationTime_ = (new System.DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
+ new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
+ }
+
+ if ((flags_ & Flags.AccessTime) != 0)
+ {
+ int iTime = helperStream.ReadLEInt();
+
+ lastAccessTime_ = (new System.DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
+ new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
+ }
+
+ if ((flags_ & Flags.CreateTime) != 0)
+ {
+ int iTime = helperStream.ReadLEInt();
+
+ createTime_ = (new System.DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
+ new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Get the binary data representing this instance.
+ /// </summary>
+ /// <returns>The raw binary data representing this instance.</returns>
+ public byte[] GetData()
+ {
+ using (MemoryStream ms = new MemoryStream())
+ using (ZipHelperStream helperStream = new ZipHelperStream(ms))
+ {
+ helperStream.IsStreamOwner = false;
+ helperStream.WriteByte((byte)flags_); // Flags
+ if ( (flags_ & Flags.ModificationTime) != 0) {
+ TimeSpan span = modificationTime_.ToUniversalTime() - new System.DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();
+ int seconds = (int)span.TotalSeconds;
+ helperStream.WriteLEInt(seconds);
+ }
+ if ( (flags_ & Flags.AccessTime) != 0) {
+ TimeSpan span = lastAccessTime_.ToUniversalTime() - new System.DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();
+ int seconds = (int)span.TotalSeconds;
+ helperStream.WriteLEInt(seconds);
+ }
+ if ( (flags_ & Flags.CreateTime) != 0) {
+ TimeSpan span = createTime_.ToUniversalTime() - new System.DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();
+ int seconds = (int)span.TotalSeconds;
+ helperStream.WriteLEInt(seconds);
+ }
+ return ms.ToArray();
+ }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Test a <see cref="DateTime"> value to see if is valid and can be represented here.</see>
+ /// </summary>
+ /// <param name="value">The <see cref="DateTime">value</see> to test.</param>
+ /// <returns>Returns true if the value is valid and can be represented; false if not.</returns>
+ /// <remarks>The standard Unix time is a signed integer data type, directly encoding the Unix time number,
+ /// which is the number of seconds since 1970-01-01.
+ /// Being 32 bits means the values here cover a range of about 136 years.
+ /// The minimum representable time is 1901-12-13 20:45:52,
+ /// and the maximum representable time is 2038-01-19 03:14:07.
+ /// </remarks>
+ public static bool IsValidValue(DateTime value)
+ {
+ return (( value >= new DateTime(1901, 12, 13, 20, 45, 52)) ||
+ ( value <= new DateTime(2038, 1, 19, 03, 14, 07) ));
+ }
+
+ /// <summary>
+ /// Get /set the Modification Time
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException"></exception>
+ /// <seealso cref="IsValidValue"></seealso>
+ public DateTime ModificationTime
+ {
+ get { return modificationTime_; }
+ set
+ {
+ if ( !IsValidValue(value) ) {
+ throw new ArgumentOutOfRangeException("value");
+ }
+
+ flags_ |= Flags.ModificationTime;
+ modificationTime_=value;
+ }
+ }
+
+ /// <summary>
+ /// Get / set the Access Time
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException"></exception>
+ /// <seealso cref="IsValidValue"></seealso>
+ public DateTime AccessTime
+ {
+ get { return lastAccessTime_; }
+ set {
+ if ( !IsValidValue(value) ) {
+ throw new ArgumentOutOfRangeException("value");
+ }
+
+ flags_ |= Flags.AccessTime;
+ lastAccessTime_=value;
+ }
+ }
+
+ /// <summary>
+ /// Get / Set the Create Time
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException"></exception>
+ /// <seealso cref="IsValidValue"></seealso>
+ public DateTime CreateTime
+ {
+ get { return createTime_; }
+ set {
+ if ( !IsValidValue(value) ) {
+ throw new ArgumentOutOfRangeException("value");
+ }
+
+ flags_ |= Flags.CreateTime;
+ createTime_=value;
+ }
+ }
+
+ /// <summary>
+ /// Get/set the <see cref="Flags">values</see> to include.
+ /// </summary>
+ Flags Include
+ {
+ get { return flags_; }
+ set { flags_ = value; }
+ }
+
+ #region Instance Fields
+ Flags flags_;
+ DateTime modificationTime_ = new DateTime(1970,1,1);
+ DateTime lastAccessTime_ = new DateTime(1970, 1, 1);
+ DateTime createTime_ = new DateTime(1970, 1, 1);
+ #endregion
+ }
+
+ /// <summary>
+ /// Class handling NT date time values.
+ /// </summary>
+ public class NTTaggedData : ITaggedData
+ {
+ /// <summary>
+ /// Get the ID for this tagged data value.
+ /// </summary>
+ public short TagID
+ {
+ get { return 10; }
+ }
+
+ /// <summary>
+ /// Set the data from the raw values provided.
+ /// </summary>
+ /// <param name="data">The raw data to extract values from.</param>
+ /// <param name="index">The index to start extracting values from.</param>
+ /// <param name="count">The number of bytes available.</param>
+ public void SetData(byte[] data, int index, int count)
+ {
+ using (MemoryStream ms = new MemoryStream(data, index, count, false))
+ using (ZipHelperStream helperStream = new ZipHelperStream(ms))
+ {
+ helperStream.ReadLEInt(); // Reserved
+ while (helperStream.Position < helperStream.Length)
+ {
+ int ntfsTag = helperStream.ReadLEShort();
+ int ntfsLength = helperStream.ReadLEShort();
+ if (ntfsTag == 1)
+ {
+ if (ntfsLength >= 24)
+ {
+ long lastModificationTicks = helperStream.ReadLELong();
+ lastModificationTime_ = DateTime.FromFileTime(lastModificationTicks);
+
+ long lastAccessTicks = helperStream.ReadLELong();
+ lastAccessTime_ = DateTime.FromFileTime(lastAccessTicks);
+
+ long createTimeTicks = helperStream.ReadLELong();
+ createTime_ = DateTime.FromFileTime(createTimeTicks);
+ }
+ break;
+ }
+ else
+ {
+ // An unknown NTFS tag so simply skip it.
+ helperStream.Seek(ntfsLength, SeekOrigin.Current);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Get the binary data representing this instance.
+ /// </summary>
+ /// <returns>The raw binary data representing this instance.</returns>
+ public byte[] GetData()
+ {
+ using (MemoryStream ms = new MemoryStream())
+ using (ZipHelperStream helperStream = new ZipHelperStream(ms))
+ {
+ helperStream.IsStreamOwner = false;
+ helperStream.WriteLEInt(0); // Reserved
+ helperStream.WriteLEShort(1); // Tag
+ helperStream.WriteLEShort(24); // Length = 3 x 8.
+ helperStream.WriteLELong(lastModificationTime_.ToFileTime());
+ helperStream.WriteLELong(lastAccessTime_.ToFileTime());
+ helperStream.WriteLELong(createTime_.ToFileTime());
+ return ms.ToArray();
+ }
+ }
+
+ /// <summary>
+ /// Test a <see cref="DateTime"> valuie to see if is valid and can be represented here.</see>
+ /// </summary>
+ /// <param name="value">The <see cref="DateTime">value</see> to test.</param>
+ /// <returns>Returns true if the value is valid and can be represented; false if not.</returns>
+ /// <remarks>
+ /// NTFS filetimes are 64-bit unsigned integers, stored in Intel
+ /// (least significant byte first) byte order. They determine the
+ /// number of 1.0E-07 seconds (1/10th microseconds!) past WinNT "epoch",
+ /// which is "01-Jan-1601 00:00:00 UTC". 28 May 60056 is the upper limit
+ /// </remarks>
+ public static bool IsValidValue(DateTime value)
+ {
+ bool result = true;
+ try
+ {
+ value.ToFileTimeUtc();
+ }
+ catch
+ {
+ result = false;
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Get/set the <see cref="DateTime">last modification time</see>.
+ /// </summary>
+ public DateTime LastModificationTime
+ {
+ get { return lastModificationTime_; }
+ set {
+ if (! IsValidValue(value))
+ {
+ throw new ArgumentOutOfRangeException("value");
+ }
+ lastModificationTime_ = value;
+ }
+ }
+
+ /// <summary>
+ /// Get /set the <see cref="DateTime">create time</see>
+ /// </summary>
+ public DateTime CreateTime
+ {
+ get { return createTime_; }
+ set {
+ if ( !IsValidValue(value)) {
+ throw new ArgumentOutOfRangeException("value");
+ }
+ createTime_ = value;
+ }
+ }
+
+ /// <summary>
+ /// Get /set the <see cref="DateTime">last access time</see>.
+ /// </summary>
+ public DateTime LastAccessTime
+ {
+ get { return lastAccessTime_; }
+ set {
+ if (!IsValidValue(value)) {
+ throw new ArgumentOutOfRangeException("value");
+ }
+ lastAccessTime_ = value;
+ }
+ }
+
+ #region Instance Fields
+ DateTime lastAccessTime_ = DateTime.FromFileTime(0);
+ DateTime lastModificationTime_ = DateTime.FromFileTime(0);
+ DateTime createTime_ = DateTime.FromFileTime(0);
+ #endregion
+ }
+
+ /// <summary>
+ /// A factory that creates <see cref="ITaggedData">tagged data</see> instances.
+ /// </summary>
+ interface ITaggedDataFactory
+ {
+ /// <summary>
+ /// Get data for a specific tag value.
+ /// </summary>
+ /// <param name="tag">The tag ID to find.</param>
+ /// <param name="data">The data to search.</param>
+ /// <param name="offset">The offset to begin extracting data from.</param>
+ /// <param name="count">The number of bytes to extract.</param>
+ /// <returns>The located <see cref="ITaggedData">value found</see>, or null if not found.</returns>
+ ITaggedData Create(short tag, byte[] data, int offset, int count);
+ }
+
+ ///
+ /// <summary>
+ /// A class to handle the extra data field for Zip entries
+ /// </summary>
+ /// <remarks>
+ /// Extra data contains 0 or more values each prefixed by a header tag and length.
+ /// They contain zero or more bytes of actual data.
+ /// The data is held internally using a copy on write strategy. This is more efficient but
+ /// means that for extra data created by passing in data can have the values modified by the caller
+ /// in some circumstances.
+ /// </remarks>
+ sealed public class ZipExtraData : IDisposable
+ {
+ #region Constructors
+ /// <summary>
+ /// Initialise a default instance.
+ /// </summary>
+ public ZipExtraData()
+ {
+ Clear();
+ }
+
+ /// <summary>
+ /// Initialise with known extra data.
+ /// </summary>
+ /// <param name="data">The extra data.</param>
+ public ZipExtraData(byte[] data)
+ {
+ if ( data == null )
+ {
+ data_ = new byte[0];
+ }
+ else
+ {
+ data_ = data;
+ }
+ }
+ #endregion
+
+ /// <summary>
+ /// Get the raw extra data value
+ /// </summary>
+ /// <returns>Returns the raw byte[] extra data this instance represents.</returns>
+ public byte[] GetEntryData()
+ {
+ if ( Length > ushort.MaxValue ) {
+ throw new ZipException("Data exceeds maximum length");
+ }
+
+ return (byte[])data_.Clone();
+ }
+
+ /// <summary>
+ /// Clear the stored data.
+ /// </summary>
+ public void Clear()
+ {
+ if ( (data_ == null) || (data_.Length != 0) ) {
+ data_ = new byte[0];
+ }
+ }
+
+ /// <summary>
+ /// Gets the current extra data length.
+ /// </summary>
+ public int Length
+ {
+ get { return data_.Length; }
+ }
+
+ /// <summary>
+ /// Get a read-only <see cref="Stream"/> for the associated tag.
+ /// </summary>
+ /// <param name="tag">The tag to locate data for.</param>
+ /// <returns>Returns a <see cref="Stream"/> containing tag data or null if no tag was found.</returns>
+ public Stream GetStreamForTag(int tag)
+ {
+ Stream result = null;
+ if ( Find(tag) ) {
+ result = new MemoryStream(data_, index_, readValueLength_, false);
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Get the <see cref="ITaggedData">tagged data</see> for a tag.
+ /// </summary>
+ /// <param name="tag">The tag to search for.</param>
+ /// <returns>Returns a <see cref="ITaggedData">tagged value</see> or null if none found.</returns>
+ private ITaggedData GetData(short tag)
+ {
+ ITaggedData result = null;
+ if (Find(tag))
+ {
+ result = Create(tag, data_, readValueStart_, readValueLength_);
+ }
+ return result;
+ }
+
+ ITaggedData Create(short tag, byte[] data, int offset, int count)
+ {
+ ITaggedData result = null;
+ switch ( tag )
+ {
+ case 0x000A:
+ result = new NTTaggedData();
+ break;
+ case 0x5455:
+ result = new ExtendedUnixData();
+ break;
+ default:
+ result = new RawTaggedData(tag);
+ break;
+ }
+ result.SetData(data_, readValueStart_, readValueLength_);
+ return result;
+ }
+
+ /// <summary>
+ /// Get the length of the last value found by <see cref="Find"/>
+ /// </summary>
+ /// <remarks>This is only value if <see cref="Find"/> has previsouly returned true.</remarks>
+ public int ValueLength
+ {
+ get { return readValueLength_; }
+ }
+
+ /// <summary>
+ /// Get the index for the current read value.
+ /// </summary>
+ /// <remarks>This is only valid if <see cref="Find"/> has previously returned true.
+ /// Initially it will be the index of the first byte of actual data. The value is updated after calls to
+ /// <see cref="ReadInt"/>, <see cref="ReadShort"/> and <see cref="ReadLong"/>. </remarks>
+ public int CurrentReadIndex
+ {
+ get { return index_; }
+ }
+
+ /// <summary>
+ /// Get the number of bytes remaining to be read for the current value;
+ /// </summary>
+ public int UnreadCount
+ {
+ get
+ {
+ if ((readValueStart_ > data_.Length) ||
+ (readValueStart_ < 4) ) {
+ throw new ZipException("Find must be called before calling a Read method");
+ }
+
+ return readValueStart_ + readValueLength_ - index_;
+ }
+ }
+
+ /// <summary>
+ /// Find an extra data value
+ /// </summary>
+ /// <param name="headerID">The identifier for the value to find.</param>
+ /// <returns>Returns true if the value was found; false otherwise.</returns>
+ public bool Find(int headerID)
+ {
+ readValueStart_ = data_.Length;
+ readValueLength_ = 0;
+ index_ = 0;
+
+ int localLength = readValueStart_;
+ int localTag = headerID - 1;
+
+ // Trailing bytes that cant make up an entry (as there arent enough
+ // bytes for a tag and length) are ignored!
+ while ( (localTag != headerID) && (index_ < data_.Length - 3) ) {
+ localTag = ReadShortInternal();
+ localLength = ReadShortInternal();
+ if ( localTag != headerID ) {
+ index_ += localLength;
+ }
+ }
+
+ bool result = (localTag == headerID) && ((index_ + localLength) <= data_.Length);
+
+ if ( result ) {
+ readValueStart_ = index_;
+ readValueLength_ = localLength;
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Add a new entry to extra data.
+ /// </summary>
+ /// <param name="taggedData">The <see cref="ITaggedData"/> value to add.</param>
+ public void AddEntry(ITaggedData taggedData)
+ {
+ if (taggedData == null)
+ {
+ throw new ArgumentNullException("taggedData");
+ }
+ AddEntry(taggedData.TagID, taggedData.GetData());
+ }
+
+ /// <summary>
+ /// Add a new entry to extra data
+ /// </summary>
+ /// <param name="headerID">The ID for this entry.</param>
+ /// <param name="fieldData">The data to add.</param>
+ /// <remarks>If the ID already exists its contents are replaced.</remarks>
+ public void AddEntry(int headerID, byte[] fieldData)
+ {
+ if ( (headerID > ushort.MaxValue) || (headerID < 0)) {
+ throw new ArgumentOutOfRangeException("headerID");
+ }
+
+ int addLength = (fieldData == null) ? 0 : fieldData.Length;
+
+ if ( addLength > ushort.MaxValue ) {
+ throw new ArgumentOutOfRangeException("fieldData", "exceeds maximum length");
+ }
+
+ // Test for new length before adjusting data.
+ int newLength = data_.Length + addLength + 4;
+
+ if ( Find(headerID) )
+ {
+ newLength -= (ValueLength + 4);
+ }
+
+ if ( newLength > ushort.MaxValue ) {
+ throw new ZipException("Data exceeds maximum length");
+ }
+
+ Delete(headerID);
+
+ byte[] newData = new byte[newLength];
+ data_.CopyTo(newData, 0);
+ int index = data_.Length;
+ data_ = newData;
+ SetShort(ref index, headerID);
+ SetShort(ref index, addLength);
+ if ( fieldData != null ) {
+ fieldData.CopyTo(newData, index);
+ }
+ }
+
+ /// <summary>
+ /// Start adding a new entry.
+ /// </summary>
+ /// <remarks>Add data using <see cref="AddData(byte[])"/>, <see cref="AddLeShort"/>, <see cref="AddLeInt"/>, or <see cref="AddLeLong"/>.
+ /// The new entry is completed and actually added by calling <see cref="AddNewEntry"/></remarks>
+ /// <seealso cref="AddEntry(ITaggedData)"/>
+ public void StartNewEntry()
+ {
+ newEntry_ = new MemoryStream();
+ }
+
+ /// <summary>
+ /// Add entry data added since <see cref="StartNewEntry"/> using the ID passed.
+ /// </summary>
+ /// <param name="headerID">The identifier to use for this entry.</param>
+ public void AddNewEntry(int headerID)
+ {
+ byte[] newData = newEntry_.ToArray();
+ newEntry_ = null;
+ AddEntry(headerID, newData);
+ }
+
+ /// <summary>
+ /// Add a byte of data to the pending new entry.
+ /// </summary>
+ /// <param name="data">The byte to add.</param>
+ /// <seealso cref="StartNewEntry"/>
+ public void AddData(byte data)
+ {
+ newEntry_.WriteByte(data);
+ }
+
+ /// <summary>
+ /// Add data to a pending new entry.
+ /// </summary>
+ /// <param name="data">The data to add.</param>
+ /// <seealso cref="StartNewEntry"/>
+ public void AddData(byte[] data)
+ {
+ if ( data == null ) {
+ throw new ArgumentNullException("data");
+ }
+
+ newEntry_.Write(data, 0, data.Length);
+ }
+
+ /// <summary>
+ /// Add a short value in little endian order to the pending new entry.
+ /// </summary>
+ /// <param name="toAdd">The data to add.</param>
+ /// <seealso cref="StartNewEntry"/>
+ public void AddLeShort(int toAdd)
+ {
+ unchecked {
+ newEntry_.WriteByte(( byte )toAdd);
+ newEntry_.WriteByte(( byte )(toAdd >> 8));
+ }
+ }
+
+ /// <summary>
+ /// Add an integer value in little endian order to the pending new entry.
+ /// </summary>
+ /// <param name="toAdd">The data to add.</param>
+ /// <seealso cref="StartNewEntry"/>
+ public void AddLeInt(int toAdd)
+ {
+ unchecked {
+ AddLeShort(( short )toAdd);
+ AddLeShort(( short )(toAdd >> 16));
+ }
+ }
+
+ /// <summary>
+ /// Add a long value in little endian order to the pending new entry.
+ /// </summary>
+ /// <param name="toAdd">The data to add.</param>
+ /// <seealso cref="StartNewEntry"/>
+ public void AddLeLong(long toAdd)
+ {
+ unchecked {
+ AddLeInt(( int )(toAdd & 0xffffffff));
+ AddLeInt(( int )(toAdd >> 32));
+ }
+ }
+
+ /// <summary>
+ /// Delete an extra data field.
+ /// </summary>
+ /// <param name="headerID">The identifier of the field to delete.</param>
+ /// <returns>Returns true if the field was found and deleted.</returns>
+ public bool Delete(int headerID)
+ {
+ bool result = false;
+
+ if ( Find(headerID) ) {
+ result = true;
+ int trueStart = readValueStart_ - 4;
+
+ byte[] newData = new byte[data_.Length - (ValueLength + 4)];
+ Array.Copy(data_, 0, newData, 0, trueStart);
+
+ int trueEnd = trueStart + ValueLength + 4;
+ Array.Copy(data_, trueEnd, newData, trueStart, data_.Length - trueEnd);
+ data_ = newData;
+ }
+ return result;
+ }
+
+ #region Reading Support
+ /// <summary>
+ /// Read a long in little endian form from the last <see cref="Find">found</see> data value
+ /// </summary>
+ /// <returns>Returns the long value read.</returns>
+ public long ReadLong()
+ {
+ ReadCheck(8);
+ return (ReadInt() & 0xffffffff) | ((( long )ReadInt()) << 32);
+ }
+
+ /// <summary>
+ /// Read an integer in little endian form from the last <see cref="Find">found</see> data value.
+ /// </summary>
+ /// <returns>Returns the integer read.</returns>
+ public int ReadInt()
+ {
+ ReadCheck(4);
+
+ int result = data_[index_] + (data_[index_ + 1] << 8) +
+ (data_[index_ + 2] << 16) + (data_[index_ + 3] << 24);
+ index_ += 4;
+ return result;
+ }
+
+ /// <summary>
+ /// Read a short value in little endian form from the last <see cref="Find">found</see> data value.
+ /// </summary>
+ /// <returns>Returns the short value read.</returns>
+ public int ReadShort()
+ {
+ ReadCheck(2);
+ int result = data_[index_] + (data_[index_ + 1] << 8);
+ index_ += 2;
+ return result;
+ }
+
+ /// <summary>
+ /// Read a byte from an extra data
+ /// </summary>
+ /// <returns>The byte value read or -1 if the end of data has been reached.</returns>
+ public int ReadByte()
+ {
+ int result = -1;
+ if ( (index_ < data_.Length) && (readValueStart_ + readValueLength_ > index_) ) {
+ result = data_[index_];
+ index_ += 1;
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Skip data during reading.
+ /// </summary>
+ /// <param name="amount">The number of bytes to skip.</param>
+ public void Skip(int amount)
+ {
+ ReadCheck(amount);
+ index_ += amount;
+ }
+
+ void ReadCheck(int length)
+ {
+ if ((readValueStart_ > data_.Length) ||
+ (readValueStart_ < 4) ) {
+ throw new ZipException("Find must be called before calling a Read method");
+ }
+
+ if (index_ > readValueStart_ + readValueLength_ - length ) {
+ throw new ZipException("End of extra data");
+ }
+ }
+
+ /// <summary>
+ /// Internal form of <see cref="ReadShort"/> that reads data at any location.
+ /// </summary>
+ /// <returns>Returns the short value read.</returns>
+ int ReadShortInternal()
+ {
+ if ( index_ > data_.Length - 2) {
+ throw new ZipException("End of extra data");
+ }
+
+ int result = data_[index_] + (data_[index_ + 1] << 8);
+ index_ += 2;
+ return result;
+ }
+
+ void SetShort(ref int index, int source)
+ {
+ data_[index] = (byte)source;
+ data_[index + 1] = (byte)(source >> 8);
+ index += 2;
+ }
+
+ #endregion
+
+ #region IDisposable Members
+
+ /// <summary>
+ /// Dispose of this instance.
+ /// </summary>
+ public void Dispose()
+ {
+ if ( newEntry_ != null ) {
+ newEntry_.Close();
+ }
+ }
+
+ #endregion
+
+ #region Instance Fields
+ int index_;
+ int readValueStart_;
+ int readValueLength_;
+
+ MemoryStream newEntry_;
+ byte[] data_;
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+// ZipFile.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Globalization;
+
+using System.Security.Cryptography;
+using ICSharpCode.SharpZipLib.Silverlight.Checksums;
+using ICSharpCode.SharpZipLib.Silverlight.Core;
+using ICSharpCode.SharpZipLib.Silverlight.Compat;
+using ICSharpCode.SharpZipLib.Silverlight.Encryption;
+using ICSharpCode.SharpZipLib.Silverlight.Zip;
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression;
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression.Streams;
+using ICSharpCode.SharpZipLib.Zip;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip
+{
+ /// <summary>
+ /// Arguments used with KeysRequiredEvent
+ /// </summary>
+ public class KeysRequiredEventArgs : EventArgs
+ {
+ #region Constructors
+ /// <summary>
+ /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>
+ /// </summary>
+ /// <param name="name">The name of the file for which keys are required.</param>
+ public KeysRequiredEventArgs(string name)
+ {
+ fileName = name;
+ }
+
+ /// <summary>
+ /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>
+ /// </summary>
+ /// <param name="name">The name of the file for which keys are required.</param>
+ /// <param name="keyValue">The current key value.</param>
+ public KeysRequiredEventArgs(string name, byte[] keyValue)
+ {
+ fileName = name;
+ key = keyValue;
+ }
+
+ #endregion
+ #region Properties
+ /// <summary>
+ /// Get the name of the file for which keys are required.
+ /// </summary>
+ public string FileName
+ {
+ get { return fileName; }
+ }
+
+ /// <summary>
+ /// Get/set the key value
+ /// </summary>
+ public byte[] Key
+ {
+ get { return key; }
+ set { key = value; }
+ }
+ #endregion
+ #region Instance Fields
+ string fileName;
+ byte[] key;
+ #endregion
+ }
+
+ /// <summary>
+ /// The strategy to apply to testing.
+ /// </summary>
+ public enum TestStrategy
+ {
+ /// <summary>
+ /// Find the first error only.
+ /// </summary>
+ FindFirstError,
+ /// <summary>
+ /// Find all possible errors.
+ /// </summary>
+ FindAllErrors,
+ }
+
+ /// <summary>
+ /// The operation in progress reported by a <see cref="ZipTestResultHandler"/> during testing.
+ /// </summary>
+ /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>
+ public enum TestOperation
+ {
+ /// <summary>
+ /// Setting up testing.
+ /// </summary>
+ Initialising,
+
+ /// <summary>
+ /// Testing an individual entries header
+ /// </summary>
+ EntryHeader,
+
+ /// <summary>
+ /// Testing an individual entries data
+ /// </summary>
+ EntryData,
+
+ /// <summary>
+ /// Testing an individual entry has completed.
+ /// </summary>
+ EntryComplete,
+
+ /// <summary>
+ /// Running miscellaneous tests
+ /// </summary>
+ MiscellaneousTests,
+
+ /// <summary>
+ /// Testing is complete
+ /// </summary>
+ Complete,
+ }
+
+ /// <summary>
+ /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.
+ /// </summary>
+ /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>
+ public class TestStatus
+ {
+ #region Constructors
+ /// <summary>
+ /// Initialise a new instance of <see cref="TestStatus"/>
+ /// </summary>
+ /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>
+ public TestStatus(ZipFile file)
+ {
+ file_ = file;
+ }
+ #endregion
+
+ #region Properties
+
+ /// <summary>
+ /// Get the current <see cref="TestOperation"/> in progress.
+ /// </summary>
+ public TestOperation Operation
+ {
+ get { return operation_; }
+ }
+
+ /// <summary>
+ /// Get the <see cref="ZipFile"/> this status is applicable to.
+ /// </summary>
+ public ZipFile File
+ {
+ get { return file_; }
+ }
+
+ /// <summary>
+ /// Get the current/last entry tested.
+ /// </summary>
+ public ZipEntry Entry
+ {
+ get { return entry_; }
+ }
+
+ /// <summary>
+ /// Get the number of errors detected so far.
+ /// </summary>
+ public int ErrorCount
+ {
+ get { return errorCount_; }
+ }
+
+ /// <summary>
+ /// Get the number of bytes tested so far for the current entry.
+ /// </summary>
+ public long BytesTested
+ {
+ get { return bytesTested_; }
+ }
+
+ /// <summary>
+ /// Get a value indicating wether the last entry test was valid.
+ /// </summary>
+ public bool EntryValid
+ {
+ get { return entryValid_; }
+ }
+ #endregion
+
+ #region Internal API
+ internal void AddError()
+ {
+ errorCount_++;
+ entryValid_ = false;
+ }
+
+ internal void SetOperation(TestOperation operation)
+ {
+ operation_ = operation;
+ }
+
+ internal void SetEntry(ZipEntry entry)
+ {
+ entry_ = entry;
+ entryValid_ = true;
+ bytesTested_ = 0;
+ }
+
+ internal void SetBytesTested(long value)
+ {
+ bytesTested_ = value;
+ }
+ #endregion
+
+ #region Instance Fields
+ ZipFile file_;
+ ZipEntry entry_;
+ bool entryValid_;
+ int errorCount_;
+ long bytesTested_;
+ TestOperation operation_;
+ #endregion
+ }
+
+ /// <summary>
+ /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if supplied indicating current progress and status.
+ /// </summary>
+ /// <remarks>If the message is non-null an error has occured. If the message is null
+ /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>
+ public delegate void ZipTestResultHandler(TestStatus status, string message);
+
+ /// <summary>
+ /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.
+ /// </summary>
+ public enum FileUpdateMode
+ {
+ /// <summary>
+ /// Perform all updates on temporary files ensuring that the original file is saved.
+ /// </summary>
+ Safe,
+ /// <summary>
+ /// Update the archive directly, which is faster but less safe.
+ /// </summary>
+ Direct,
+ }
+
+ /// <summary>
+ /// This class represents a Zip archive. You can ask for the contained
+ /// entries, or get an input stream for a file entry. The entry is
+ /// automatically decompressed.
+ ///
+ /// You can also update the archive adding or deleting entries.
+ ///
+ /// This class is thread safe for input: You can open input streams for arbitrary
+ /// entries in different threads.
+ /// <br/>
+ /// <br/>Author of the original java version : Jochen Hoenicke
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// using System;
+ /// using System.Text;
+ /// using System.Collections;
+ /// using System.IO;
+ ///
+ /// using ICSharpCode.SharpZipLib.Zip;
+ ///
+ /// class MainClass
+ /// {
+ /// static public void Main(string[] args)
+ /// {
+ /// using (ZipFile zFile = new ZipFile(args[0])) {
+ /// Console.WriteLine("Listing of : " + zFile.Name);
+ /// Console.WriteLine("");
+ /// Console.WriteLine("Raw Size Size Date Time Name");
+ /// Console.WriteLine("-------- -------- -------- ------ ---------");
+ /// foreach (ZipEntry e in zFile) {
+ /// if ( e.IsFile ) {
+ /// DateTime d = e.DateTime;
+ /// Console.WriteLine("{0, -10}{1, -10}{2} {3} {4}", e.Size, e.CompressedSize,
+ /// d.ToString("dd-MM-yy"), d.ToString("HH:mm"),
+ /// e.Name);
+ /// }
+ /// }
+ /// }
+ /// }
+ /// }
+ /// </code>
+ /// </example>
+ public class ZipFile : IEnumerable, IDisposable
+ {
+ #region KeyHandling
+
+ /// <summary>
+ /// Delegate for handling keys/password setting during compresion/decompression.
+ /// </summary>
+ public delegate void KeysRequiredEventHandler(
+ object sender,
+ KeysRequiredEventArgs e
+ );
+
+ /// <summary>
+ /// Event handler for handling encryption keys.
+ /// </summary>
+ public KeysRequiredEventHandler KeysRequired;
+
+ /// <summary>
+ /// Handles getting of encryption keys when required.
+ /// </summary>
+ /// <param name="fileName">The file for which encryption keys are required.</param>
+ void OnKeysRequired(string fileName)
+ {
+ if (KeysRequired != null) {
+ KeysRequiredEventArgs krea = new KeysRequiredEventArgs(fileName, key);
+ KeysRequired(this, krea);
+ key = krea.Key;
+ }
+ }
+
+
+ /// <summary>
+ /// Get/set the encryption key value.
+ /// </summary>
+ byte[] Key
+ {
+ get { return key; }
+ set { key = value; }
+ }
+
+ /// <summary>
+ /// Password to be used for encrypting/decrypting files.
+ /// </summary>
+ /// <remarks>Set to null if no password is required.</remarks>
+ public string Password
+ {
+ set
+ {
+ if ( (value == null) || (value.Length == 0) ) {
+ key = null;
+ }
+ else {
+ key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(value));
+ }
+ }
+ }
+
+ /// <summary>
+ /// Get a value indicating wether encryption keys are currently available.
+ /// </summary>
+ bool HaveKeys
+ {
+ get { return key != null; }
+ }
+ #endregion
+
+ #region Constructors
+ /// <summary>
+ /// Opens a Zip file with the given name for reading.
+ /// </summary>
+ /// <param name="name">The name of the file to open.</param>
+ /// <exception cref="IOException">
+ /// An i/o error occurs
+ /// </exception>
+ /// <exception cref="ZipException">
+ /// The file doesn't contain a valid zip archive.
+ /// </exception>
+ public ZipFile(string name)
+ {
+ name_ = name;
+
+ baseStream_ = File.OpenRead(name);
+ isStreamOwner = true;
+
+ try {
+ ReadEntries();
+ }
+ catch {
+ DisposeInternal(true);
+ throw;
+ }
+ }
+
+ /// <summary>
+ /// Opens a Zip file reading the given <see cref="FileStream"/>.
+ /// </summary>
+ /// <param name="file">The <see cref="FileStream"/> to read archive data from.</param>
+ /// <exception cref="IOException">
+ /// An i/o error occurs.
+ /// </exception>
+ /// <exception cref="ZipException">
+ /// The file doesn't contain a valid zip archive.
+ /// </exception>
+ public ZipFile(FileStream file)
+ {
+ if ( file == null ) {
+ throw new ArgumentNullException("file");
+ }
+
+ if ( !file.CanSeek ) {
+ throw new ArgumentException("Stream is not seekable", "file");
+ }
+
+ baseStream_ = file;
+ name_ = file.Name;
+ isStreamOwner = true;
+
+ try {
+ ReadEntries();
+ }
+ catch {
+ DisposeInternal(true);
+ throw;
+ }
+ }
+
+ /// <summary>
+ /// Opens a Zip file reading the given <see cref="Stream"/>.
+ /// </summary>
+ /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>
+ /// <exception cref="IOException">
+ /// An i/o error occurs
+ /// </exception>
+ /// <exception cref="ZipException">
+ /// The file doesn't contain a valid zip archive.<br/>
+ /// The stream provided cannot seek
+ /// </exception>
+ public ZipFile(Stream stream)
+ {
+ if ( stream == null ) {
+ throw new ArgumentNullException("stream");
+ }
+
+ if ( !stream.CanSeek ) {
+ throw new ArgumentException("Stream is not seekable", "stream");
+ }
+
+ baseStream_ = stream;
+ isStreamOwner = true;
+
+ if ( baseStream_.Length > 0 ) {
+ try {
+ ReadEntries();
+ }
+ catch {
+ DisposeInternal(true);
+ throw;
+ }
+ } else {
+ entries_ = new ZipEntry[0];
+ isNewArchive_ = true;
+ }
+ }
+
+ /// <summary>
+ /// Initialises a default <see cref="ZipFile"/> instance with no entries and no file storage.
+ /// </summary>
+ internal ZipFile()
+ {
+ entries_ = new ZipEntry[0];
+ isNewArchive_ = true;
+ }
+
+ #endregion
+
+ #region Destructors and Closing
+ /// <summary>
+ /// Finalize this instance.
+ /// </summary>
+ ~ZipFile()
+ {
+ Dispose(false);
+ }
+
+ /// <summary>
+ /// Closes the ZipFile. If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying input stream.
+ /// Once closed, no further instance methods should be called.
+ /// </summary>
+ /// <exception cref="System.IO.IOException">
+ /// An i/o error occurs.
+ /// </exception>
+ public void Close()
+ {
+ DisposeInternal(true);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+
+ #region Creators
+ /// <summary>
+ /// Create a new <see cref="ZipFile"/> whose data will be stored in a file.
+ /// </summary>
+ /// <param name="fileName">The name of the archive to create.</param>
+ /// <returns>Returns the newly created <see cref="ZipFile"/></returns>
+ public static ZipFile Create(string fileName)
+ {
+ if ( fileName == null ) {
+ throw new ArgumentNullException("fileName");
+ }
+
+ FileStream fs = File.Create(fileName);
+
+ ZipFile result = new ZipFile();
+ result.name_ = fileName;
+ result.baseStream_ = fs;
+ result.isStreamOwner = true;
+ return result;
+ }
+
+ /// <summary>
+ /// Create a new <see cref="ZipFile"/> whose data will be stored on a stream.
+ /// </summary>
+ /// <param name="outStream">The stream providing data storage.</param>
+ /// <returns>Returns the newly created <see cref="ZipFile"/></returns>
+ public static ZipFile Create(Stream outStream)
+ {
+ if ( outStream == null ) {
+ throw new ArgumentNullException("outStream");
+ }
+
+ if ( !outStream.CanWrite ) {
+ throw new ArgumentException("Stream is not writeable", "outStream");
+ }
+
+ if ( !outStream.CanSeek ) {
+ throw new ArgumentException("Stream is not seekable", "outStream");
+ }
+
+ ZipFile result = new ZipFile();
+ result.baseStream_ = outStream;
+ return result;
+ }
+
+ #endregion
+
+ #region Properties
+ /// <summary>
+ /// Get/set a flag indicating if the underlying stream is owned by the ZipFile instance.
+ /// If the flag is true then the stream will be closed when <see cref="Close">Close</see> is called.
+ /// </summary>
+ /// <remarks>
+ /// The default value is true in all cases.
+ /// </remarks>
+ public bool IsStreamOwner
+ {
+ get { return isStreamOwner; }
+ set { isStreamOwner = value; }
+ }
+
+ /// <summary>
+ /// Get a value indicating wether
+ /// this archive is embedded in another file or not.
+ /// </summary>
+ public bool IsEmbeddedArchive
+ {
+ // Not strictly correct in all circumstances currently
+ get { return offsetOfFirstEntry > 0; }
+ }
+
+ /// <summary>
+ /// Get a value indicating that this archive is a new one.
+ /// </summary>
+ public bool IsNewArchive
+ {
+ get { return isNewArchive_; }
+ }
+
+ /// <summary>
+ /// Gets the comment for the zip file.
+ /// </summary>
+ public string ZipFileComment
+ {
+ get { return comment_; }
+ }
+
+ /// <summary>
+ /// Gets the name of this zip file.
+ /// </summary>
+ public string Name
+ {
+ get { return name_; }
+ }
+
+ /// <summary>
+ /// Gets the number of entries in this zip file.
+ /// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The Zip file has been closed.
+ /// </exception>
+ [Obsolete("Use the Count property instead")]
+ public int Size
+ {
+ get
+ {
+ if (entries_ != null) {
+ return entries_.Length;
+ } else {
+ throw new InvalidOperationException("ZipFile is closed");
+ }
+ }
+ }
+
+ /// <summary>
+ /// Get the number of entries contained in this <see cref="ZipFile"/>.
+ /// </summary>
+ public long Count
+ {
+ get
+ {
+ if (entries_ != null) {
+ return entries_.Length;
+ } else {
+ throw new InvalidOperationException("ZipFile is closed");
+ }
+ }
+ }
+
+ /// <summary>
+ /// Indexer property for ZipEntries
+ /// </summary>
+ [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]
+ public ZipEntry this[int index]
+ {
+ get {
+ return (ZipEntry) entries_[index].Clone();
+ }
+ }
+
+ #endregion
+
+ #region Input Handling
+ /// <summary>
+ /// Gets an enumerator for the Zip entries in this Zip file.
+ /// </summary>
+ /// <returns>Returns an <see cref="IEnumerator"/> for this archive.</returns>
+ /// <exception cref="InvalidOperationException">
+ /// The Zip file has been closed.
+ /// </exception>
+ public IEnumerator GetEnumerator()
+ {
+ if (entries_ == null) {
+ throw new InvalidOperationException("ZipFile has closed");
+ }
+
+ return new ZipEntryEnumerator(entries_);
+ }
+
+ /// <summary>
+ /// Return the index of the entry with a matching name
+ /// </summary>
+ /// <param name="name">Entry name to find</param>
+ /// <param name="ignoreCase">If true the comparison is case insensitive</param>
+ /// <returns>The index position of the matching entry or -1 if not found</returns>
+ /// <exception cref="InvalidOperationException">
+ /// The Zip file has been closed.
+ /// </exception>
+ public int FindEntry(string name, bool ignoreCase)
+ {
+ if (entries_ == null) {
+ throw new InvalidOperationException("ZipFile has been closed");
+ }
+
+ // TODO: This will be slow as the next ice age for huge archives!
+ for (int i = 0; i < entries_.Length; i++) {
+ // BUG: Throws MissingMethodException!
+ // CompareOptions options = (ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
+ // int comparison = string.Compare(name, entries_[i].Name, CultureInfo.InvariantCulture, options);
+ if (name.Compare(entries_[i].Name, ignoreCase, CultureInfo.InvariantCulture) == 0)
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /// <summary>
+ /// Searches for a zip entry in this archive with the given name.
+ /// String comparisons are case insensitive
+ /// </summary>
+ /// <param name="name">
+ /// The name to find. May contain directory components separated by slashes ('/').
+ /// </param>
+ /// <returns>
+ /// A clone of the zip entry, or null if no entry with that name exists.
+ /// </returns>
+ /// <exception cref="InvalidOperationException">
+ /// The Zip file has been closed.
+ /// </exception>
+ public ZipEntry GetEntry(string name)
+ {
+ if (entries_ == null) {
+ throw new InvalidOperationException("ZipFile has been closed");
+ }
+
+ int index = FindEntry(name, true);
+ return (index >= 0) ? (ZipEntry) entries_[index].Clone() : null;
+ }
+
+ /// <summary>
+ /// Gets an input stream for reading the given zip entry data in an uncompressed form.
+ /// Normally the <see cref="ZipEntry"/> should be an entry returned by GetEntry().
+ /// </summary>
+ /// <param name="entry">The <see cref="ZipEntry"/> to obtain a data <see cref="Stream"/> for</param>
+ /// <returns>An input <see cref="Stream"/> containing data for this <see cref="ZipEntry"/></returns>
+ /// <exception cref="InvalidOperationException">
+ /// The ZipFile has already been closed
+ /// </exception>
+ /// <exception cref="ZipException">
+ /// The compression method for the entry is unknown
+ /// </exception>
+ /// <exception cref="IndexOutOfRangeException">
+ /// The entry is not found in the ZipFile
+ /// </exception>
+ public Stream GetInputStream(ZipEntry entry)
+ {
+ if ( entry == null ) {
+ throw new ArgumentNullException("entry");
+ }
+
+ if ( entries_ == null ) {
+ throw new InvalidOperationException("ZipFile has closed");
+ }
+
+ long index = entry.ZipFileIndex;
+ if ( (index < 0) || (index >= entries_.Length) || (entries_[index].Name != entry.Name) ) {
+ index = FindEntry(entry.Name, true);
+ if (index < 0) {
+ throw new ZipException("Entry cannot be found");
+ }
+ }
+ return GetInputStream(index);
+ }
+
+ /// <summary>
+ /// Creates an input stream reading a zip entry
+ /// </summary>
+ /// <param name="entryIndex">The index of the entry to obtain an input stream for.</param>
+ /// <returns>
+ /// An input <see cref="Stream"/> containing data for this <paramref name="entryIndex"/>
+ /// </returns>
+ /// <exception cref="InvalidOperationException">
+ /// The ZipFile has already been closed
+ /// </exception>
+ /// <exception cref="ZipException">
+ /// The compression method for the entry is unknown
+ /// </exception>
+ /// <exception cref="IndexOutOfRangeException">
+ /// The entry is not found in the ZipFile
+ /// </exception>
+ public Stream GetInputStream(long entryIndex)
+ {
+ if ( entries_ == null ) {
+ throw new InvalidOperationException("ZipFile is not open");
+ }
+
+ long start = LocateEntry(entries_[entryIndex]);
+ CompressionMethod method = entries_[entryIndex].CompressionMethod;
+ Stream result = new PartialInputStream(baseStream_, start, entries_[entryIndex].CompressedSize);
+
+ if (entries_[entryIndex].IsCrypted == true) {
+#if NETCF_1_0
+ throw new ZipException("decryption not supported for Compact Framework 1.0");
+#else
+ result = CreateAndInitDecryptionStream(result, entries_[entryIndex]);
+ if (result == null) {
+ throw new ZipException("Unable to decrypt this entry");
+ }
+#endif
+ }
+
+ switch (method) {
+ case CompressionMethod.Stored:
+ // read as is.
+ break;
+
+ case CompressionMethod.Deflated:
+ // No need to worry about ownership and closing as underlying stream close does nothing.
+ result = new InflaterInputStream(result, new Inflater(true));
+ break;
+
+ default:
+ throw new ZipException("Unsupported compression method " + method);
+ }
+
+ return result;
+ }
+
+ #endregion
+
+ #region Archive Testing
+ /// <summary>
+ /// Test an archive for integrity/validity
+ /// </summary>
+ /// <param name="testData">Perform low level data Crc check</param>
+ /// <returns>true if all tests pass, false otherwise</returns>
+ /// <remarks>Testing will terminate on the first error found.</remarks>
+ public bool TestArchive(bool testData)
+ {
+ return TestArchive(testData, TestStrategy.FindFirstError, null);
+ }
+
+ /// <summary>
+ /// Test an archive for integrity/validity
+ /// </summary>
+ /// <param name="testData">Perform low level data Crc check</param>
+ /// <param name="strategy">The <see cref="TestStrategy"></see> to apply.</param>
+ /// <param name="resultHandler">The <see cref="ZipTestResultHandler"></see> handler to call during testing.</param>
+ /// <returns>true if all tests pass, false otherwise</returns>
+ public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler)
+ {
+ TestStatus status = new TestStatus(this);
+
+ if ( resultHandler != null ) {
+ resultHandler(status, null);
+ }
+
+ HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;
+
+ bool testing = true;
+
+ try {
+ int entryIndex = 0;
+
+ while ( testing && (entryIndex < Count) ) {
+ if ( resultHandler != null ) {
+ status.SetEntry(this[entryIndex]);
+ status.SetOperation(TestOperation.EntryHeader);
+ resultHandler(status, null);
+ }
+
+ try {
+ TestLocalHeader(this[entryIndex], test);
+ }
+ catch(ZipException ex) {
+ status.AddError();
+
+ if ( resultHandler != null ) {
+ resultHandler(status,
+ string.Format("Exception during test - '{0}'", ex.Message));
+ }
+
+ if ( strategy == TestStrategy.FindFirstError ) {
+ testing = false;
+ }
+ }
+
+ if ( testing && testData && this[entryIndex].IsFile ) {
+ if ( resultHandler != null ) {
+ status.SetOperation(TestOperation.EntryData);
+ resultHandler(status, null);
+ }
+
+ Stream entryStream = this.GetInputStream(this[entryIndex]);
+
+ Crc32 crc = new Crc32();
+ byte[] buffer = new byte[4096];
+ long totalBytes = 0;
+ int bytesRead;
+ while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0) {
+ crc.Update(buffer, 0, bytesRead);
+
+ if ( resultHandler != null ) {
+ totalBytes += bytesRead;
+ status.SetBytesTested(totalBytes);
+ resultHandler(status, null);
+ }
+ }
+
+ if (this[entryIndex].Crc != crc.Value) {
+ status.AddError();
+
+ if ( resultHandler != null ) {
+ resultHandler(status, "CRC mismatch");
+ }
+
+ if ( strategy == TestStrategy.FindFirstError ) {
+ testing = false;
+ }
+ }
+
+ if (( this[entryIndex].Flags & (int)GeneralBitFlags.Descriptor) != 0 ) {
+ ZipHelperStream helper = new ZipHelperStream(baseStream_);
+ DescriptorData data = new DescriptorData();
+ helper.ReadDataDescriptor(this[entryIndex].LocalHeaderRequiresZip64, data);
+ if (this[entryIndex].Crc != data.Crc) {
+ status.AddError();
+ }
+
+ if (this[entryIndex].CompressedSize != data.CompressedSize) {
+ status.AddError();
+ }
+
+ if (this[entryIndex].Size != data.Size) {
+ status.AddError();
+ }
+ }
+ }
+
+ if ( resultHandler != null ) {
+ status.SetOperation(TestOperation.EntryComplete);
+ resultHandler(status, null);
+ }
+
+ entryIndex += 1;
+ }
+
+ if ( resultHandler != null ) {
+ status.SetOperation(TestOperation.MiscellaneousTests);
+ resultHandler(status, null);
+ }
+
+ // TODO: the 'Corrina Johns' test where local headers are missing from
+ // the central directory. They are therefore invisible to many archivers.
+ }
+ catch (Exception ex) {
+ status.AddError();
+
+ if ( resultHandler != null ) {
+ resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));
+ }
+ }
+
+ if ( resultHandler != null ) {
+ status.SetOperation(TestOperation.Complete);
+ status.SetEntry(null);
+ resultHandler(status, null);
+ }
+
+ return (status.ErrorCount == 0);
+ }
+
+ [Flags]
+ enum HeaderTest
+ {
+ Extract = 0x01, // Check that this header represents an entry whose data can be extracted
+ Header = 0x02, // Check that this header contents are valid
+ }
+
+ /// <summary>
+ /// Test a local header against that provided from the central directory
+ /// </summary>
+ /// <param name="entry">
+ /// The entry to test against
+ /// </param>
+ /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param>
+ /// <returns>The offset of the entries data in the file</returns>
+ long TestLocalHeader(ZipEntry entry, HeaderTest tests)
+ {
+ lock(baseStream_)
+ {
+ bool testHeader = (tests & HeaderTest.Header) != 0;
+ bool testData = (tests & HeaderTest.Extract) != 0;
+
+ baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);
+ if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) {
+ throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset));
+ }
+
+ short extractVersion = ( short )ReadLEUshort();
+ short localFlags = ( short )ReadLEUshort();
+ short compressionMethod = ( short )ReadLEUshort();
+ short fileTime = ( short )ReadLEUshort();
+ short fileDate = ( short )ReadLEUshort();
+ uint crcValue = ReadLEUint();
+ long compressedSize = ReadLEUint();
+ long size = ReadLEUint();
+ int storedNameLength = ReadLEUshort();
+ int extraDataLength = ReadLEUshort();
+
+ byte[] nameData = new byte[storedNameLength];
+ StreamUtils.ReadFully(baseStream_, nameData);
+
+ byte[] extraData = new byte[extraDataLength];
+ StreamUtils.ReadFully(baseStream_, extraData);
+
+ ZipExtraData ed = new ZipExtraData(extraData);
+
+ // Extra data / zip64 checks
+ if (ed.Find(1))
+ {
+ // TODO Check for tag values being distinct.. Multiple zip64 tags means what?
+
+ // Zip64 extra data but 'extract version' is too low
+ if (extractVersion < ZipConstants.VersionZip64)
+ {
+ throw new ZipException(
+ string.Format("Extra data contains Zip64 information but version {0}.{1} is not high enough",
+ extractVersion / 10, extractVersion % 10));
+ }
+
+ // Zip64 extra data but size fields dont indicate its required.
+ if (((uint)size != uint.MaxValue) && ((uint)compressedSize != uint.MaxValue))
+ {
+ throw new ZipException("Entry sizes not correct for Zip64");
+ }
+
+ size = ed.ReadLong();
+ compressedSize = ed.ReadLong();
+ }
+ else
+ {
+ // No zip64 extra data but entry requires it.
+ if ((extractVersion >= ZipConstants.VersionZip64) &&
+ (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue)))
+ {
+ throw new ZipException("Required Zip64 extended information missing");
+ }
+ }
+
+ if ( testData ) {
+ if ( entry.IsFile ) {
+ if ( !entry.IsCompressionMethodSupported() ) {
+ throw new ZipException("Compression method not supported");
+ }
+
+ if ( (extractVersion > ZipConstants.VersionMadeBy)
+ || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64)) ) {
+ throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extractVersion));
+ }
+
+ if ( (localFlags & ( int )(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.EnhancedCompress | GeneralBitFlags.HeaderMasked)) != 0 ) {
+ throw new ZipException("The library does not support the zip version required to extract this entry");
+ }
+ }
+ }
+
+ if ( testHeader ) {
+ if ((extractVersion <= 63) && // Ignore later versions as we dont know about them..
+ (extractVersion != 10) &&
+ (extractVersion != 11) &&
+ (extractVersion != 20) &&
+ (extractVersion != 21) &&
+ (extractVersion != 25) &&
+ (extractVersion != 27) &&
+ (extractVersion != 45) &&
+ (extractVersion != 46) &&
+ (extractVersion != 50) &&
+ (extractVersion != 51) &&
+ (extractVersion != 52) &&
+ (extractVersion != 61) &&
+ (extractVersion != 62) &&
+ (extractVersion != 63)
+ ) {
+ throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", extractVersion));
+ }
+
+ // Local entry flags dont have reserved bit set on.
+ if ( (localFlags & ( int )(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.ReservedPkware15)) != 0 ) {
+ throw new ZipException("Reserved bit flags cannot be set.");
+ }
+
+ // Encryption requires extract version >= 20
+ if ( ((localFlags & ( int )GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20) ) {
+ throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})", extractVersion));
+ }
+
+ // Strong encryption requires encryption flag to be set and extract version >= 50.
+ if ( (localFlags & (int)GeneralBitFlags.StrongEncryption) != 0 ) {
+ if ( (localFlags & (int)GeneralBitFlags.Encrypted) == 0 ) {
+ throw new ZipException("Strong encryption flag set but encryption flag is not set");
+ }
+
+ if ( extractVersion < 50 ) {
+ throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})", extractVersion));
+ }
+ }
+
+ // Patched entries require extract version >= 27
+ if ( ((localFlags & ( int )GeneralBitFlags.Patched) != 0) && (extractVersion < 27) ) {
+ throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));
+ }
+
+ // Central header flags match local entry flags.
+ if ( localFlags != entry.Flags ) {
+ throw new ZipException("Central header/local header flags mismatch");
+ }
+
+ // Central header compression method matches local entry
+ if ( entry.CompressionMethod != ( CompressionMethod )compressionMethod ) {
+ throw new ZipException("Central header/local header compression method mismatch");
+ }
+
+ // Strong encryption and extract version match
+ if ( (localFlags & ( int )GeneralBitFlags.StrongEncryption) != 0 ) {
+ if ( extractVersion < 62 ) {
+ throw new ZipException("Strong encryption flag set but version not high enough");
+ }
+ }
+
+ if ( (localFlags & ( int )GeneralBitFlags.HeaderMasked) != 0 ) {
+ if ( (fileTime != 0) || (fileDate != 0) ) {
+ throw new ZipException("Header masked set but date/time values non-zero");
+ }
+ }
+
+ if ( (localFlags & ( int )GeneralBitFlags.Descriptor) == 0 ) {
+ if ( crcValue != (uint)entry.Crc ) {
+ throw new ZipException("Central header/local header crc mismatch");
+ }
+ }
+
+ // Crc valid for empty entry.
+ // This will also apply to streamed entries where size isnt known and the header cant be patched
+ if ( (size == 0) && (compressedSize == 0) ) {
+ if ( crcValue != 0 ) {
+ throw new ZipException("Invalid CRC for empty entry");
+ }
+ }
+
+ // TODO: make test more correct... can't compare lengths as was done originally as this can fail for MBCS strings
+ // Assuming a code page at this point is not valid? Best is to store the name length in the ZipEntry probably
+ if ( entry.Name.Length > storedNameLength ) {
+ throw new ZipException("File name length mismatch");
+ }
+
+ // Name data has already been read convert it and compare.
+ string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);
+
+ // Central directory and local entry name match
+ if ( localName != entry.Name ) {
+ throw new ZipException("Central header and local header file name mismatch");
+ }
+
+ // Directories have zero size.
+ if ( entry.IsDirectory ) {
+ if ( (compressedSize != 0) || (size != 0) ) {
+ throw new ZipException("Directory cannot have size");
+ }
+ }
+
+ if ( !ZipNameTransform.IsValidName(localName, true) ) {
+ throw new ZipException("Name is invalid");
+ }
+
+ }
+
+ // Tests that apply to both data and header.
+
+ // Size can be verified only if it is known in the local header.
+ // it will always be known in the central header.
+ if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0 ||
+ (size != 0 || compressedSize != 0)) {
+
+ if (size != entry.Size) {
+ throw new ZipException(
+ string.Format("Size mismatch between central header({0}) and local header({1})",
+ entry.Size, size));
+ }
+
+ if (compressedSize != entry.CompressedSize) {
+ throw new ZipException(
+ string.Format("Compressed size mismatch between central header({0}) and local header({1})",
+ entry.CompressedSize, compressedSize));
+ }
+ }
+
+ int extraLength = storedNameLength + extraDataLength;
+ return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;
+ }
+ }
+
+ #endregion
+
+ #region Updating
+
+ const int DefaultBufferSize = 4096;
+
+ /// <summary>
+ /// The kind of update to apply.
+ /// </summary>
+ enum UpdateCommand
+ {
+ Copy, // Copy original file contents.
+ Modify, // Change encryption, compression, attributes, name, time etc, of an existing file.
+ Add, // Add a new file to the archive.
+ }
+
+ #region Properties
+ /// <summary>
+ /// Get / set the <see cref="INameTransform"/> to apply to names when updating.
+ /// </summary>
+ public INameTransform NameTransform
+ {
+ get {
+ return updateEntryFactory_.NameTransform;
+ }
+
+ set {
+ updateEntryFactory_.NameTransform = value;
+ }
+ }
+
+ /// <summary>
+ /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values
+ /// during updates.
+ /// </summary>
+ public IEntryFactory EntryFactory
+ {
+ get {
+ return updateEntryFactory_;
+ }
+
+ set {
+ if (value == null) {
+ updateEntryFactory_ = new ZipEntryFactory();
+ }
+ else {
+ updateEntryFactory_ = value;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Get /set the buffer size to be used when updating this zip file.
+ /// </summary>
+ public int BufferSize
+ {
+ get { return bufferSize_; }
+ set {
+ if ( value < 1024 ) {
+#if NETCF_1_0
+ throw new ArgumentOutOfRangeException("value");
+#else
+ throw new ArgumentOutOfRangeException("value", "cannot be below 1024");
+#endif
+ }
+
+ if ( bufferSize_ != value ) {
+ bufferSize_ = value;
+ copyBuffer_ = null;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Get a value indicating an update has <see cref="BeginUpdate()">been started</see>.
+ /// </summary>
+ public bool IsUpdating
+ {
+ get { return updates_ != null; }
+ }
+
+ /// <summary>
+ /// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.
+ /// </summary>
+ public UseZip64 UseZip64
+ {
+ get { return useZip64_; }
+ set { useZip64_ = value; }
+ }
+
+ #endregion
+
+ #region Immediate updating
+// TBD: Direct form of updating
+//
+// public void Update(IEntryMatcher deleteMatcher)
+// {
+// }
+//
+// public void Update(IScanner addScanner)
+// {
+// }
+ #endregion
+
+ #region Deferred Updating
+ /// <summary>
+ /// Begin updating this <see cref="ZipFile"/> archive.
+ /// </summary>
+ /// <param name="archiveStorage">The <see cref="IArchiveStorage">archive storage</see> for use during the update.</param>
+ /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param>
+ public void BeginUpdate(IArchiveStorage archiveStorage, IDynamicDataSource dataSource)
+ {
+ if ( IsEmbeddedArchive ) {
+ throw new ZipException ("Cannot update embedded/SFX archives");
+ }
+
+ if ( archiveStorage == null ) {
+ throw new ArgumentNullException("archiveStorage");
+ }
+
+ if ( dataSource == null ) {
+ throw new ArgumentNullException("dataSource");
+ }
+
+ archiveStorage_ = archiveStorage;
+ updateDataSource_ = dataSource;
+
+ // NOTE: the baseStream_ may not currently support writing or seeking.
+
+ updateIndex_ = new Dictionary<string, int>();
+
+ if ( entries_ != null ) {
+ updates_ = new List<ZipUpdate>(entries_.Length);
+ foreach(ZipEntry entry in entries_) {
+ ZipUpdate update = new ZipUpdate(entry);
+ updates_.Add(update);
+ int index = updates_.IndexOf(update);
+ updateIndex_.Add(entry.Name, index);
+ }
+ }
+ else {
+ updates_ = new List<ZipUpdate>();
+ }
+
+ updateCount_ = updates_.Count;
+
+ contentsEdited_ = false;
+ commentEdited_ = false;
+ newComment_ = null;
+ }
+
+ /// <summary>
+ /// Begin updating to this <see cref="ZipFile"/> archive.
+ /// </summary>
+ /// <param name="archiveStorage">The storage to use during the update.</param>
+ public void BeginUpdate(IArchiveStorage archiveStorage)
+ {
+ BeginUpdate(archiveStorage, new DynamicDiskDataSource());
+ }
+
+ /// <summary>
+ /// Begin updating this <see cref="ZipFile"/> archive.
+ /// </summary>
+ /// <seealso cref="BeginUpdate(IArchiveStorage)"/>
+ /// <seealso cref="CommitUpdate"></seealso>
+ /// <seealso cref="AbortUpdate"></seealso>
+ public void BeginUpdate()
+ {
+ if ( Name == null ) {
+ BeginUpdate(new MemoryArchiveStorage(), new DynamicDiskDataSource());
+ }
+ else {
+ BeginUpdate(new DiskArchiveStorage(this), new DynamicDiskDataSource());
+ }
+ }
+
+ /// <summary>
+ /// Commit current updates, updating this archive.
+ /// </summary>
+ /// <seealso cref="BeginUpdate()"></seealso>
+ /// <seealso cref="AbortUpdate"></seealso>
+ public void CommitUpdate()
+ {
+ CheckUpdating();
+
+ try
+ {
+ updateIndex_.Clear();
+ updateIndex_=null;
+
+ if( contentsEdited_ ) {
+ RunUpdates();
+ }
+ else if( commentEdited_ ) {
+ UpdateCommentOnly();
+ }
+ else {
+ // Create an empty archive if none existed originally.
+ if( (entries_!=null)&&(entries_.Length==0) ) {
+ byte[] theComment=(newComment_!=null)?newComment_.RawComment:ZipConstants.ConvertToArray(comment_);
+ using( ZipHelperStream zhs=new ZipHelperStream(baseStream_) ) {
+ zhs.WriteEndOfCentralDirectory(0, 0, 0, theComment);
+ }
+ }
+ }
+
+ }
+ finally {
+ PostUpdateCleanup();
+ }
+ }
+
+ /// <summary>
+ /// Abort updating leaving the archive unchanged.
+ /// </summary>
+ /// <seealso cref="BeginUpdate()"></seealso>
+ /// <seealso cref="CommitUpdate"></seealso>
+ public void AbortUpdate()
+ {
+ PostUpdateCleanup();
+ }
+
+ /// <summary>
+ /// Set the file comment to be recorded when the current update is <see cref="CommitUpdate">commited</see>.
+ /// </summary>
+ /// <param name="comment">The comment to record.</param>
+ public void SetComment(string comment)
+ {
+ CheckUpdating();
+
+ newComment_ = new ZipString(comment);
+
+ if ( newComment_.RawLength > 0xffff ) {
+ newComment_ = null;
+ throw new ZipException("Comment length exceeds maximum - 65535");
+ }
+
+ // We dont take account of the original and current comment appearing to be the same
+ // as encoding may be different.
+ commentEdited_ = true;
+ }
+
+ #endregion
+
+ #region Adding Entries
+
+ void AddUpdate(ZipUpdate update)
+ {
+ contentsEdited_ = true;
+
+ int index = FindExistingUpdate(update.Entry.Name);
+
+ if (index >= 0) {
+ if ( updates_[index] == null ) {
+ updateCount_ += 1;
+ }
+
+ // Direct replacement is faster than delete and add.
+ updates_[index] = update;
+ }
+ else {
+ updates_.Add(update);
+ index = updates_.IndexOf(update);
+ updateCount_ += 1;
+ updateIndex_.Add(update.Entry.Name, index);
+ }
+ }
+
+ /// <summary>
+ /// Add a new entry to the archive.
+ /// </summary>
+ /// <param name="fileName">The name of the file to add.</param>
+ /// <param name="compressionMethod">The compression method to use.</param>
+ /// <param name="useUnicodeText">Ensure Unicode text is used for name and comment for this entry.</param>
+ public void Add(string fileName, CompressionMethod compressionMethod, bool useUnicodeText )
+ {
+ if (fileName == null) {
+ throw new ArgumentNullException("fileName");
+ }
+
+ if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {
+ throw new ZipException("Compression method not supported");
+ }
+
+ CheckUpdating();
+ contentsEdited_ = true;
+
+ ZipEntry entry = EntryFactory.MakeFileEntry(fileName);
+ entry.IsUnicodeText = useUnicodeText;
+ entry.CompressionMethod = compressionMethod;
+
+ AddUpdate(new ZipUpdate(fileName, entry));
+ }
+
+ /// <summary>
+ /// Add a new entry to the archive.
+ /// </summary>
+ /// <param name="fileName">The name of the file to add.</param>
+ /// <param name="compressionMethod">The compression method to use.</param>
+ public void Add(string fileName, CompressionMethod compressionMethod)
+ {
+ if ( fileName == null ) {
+ throw new ArgumentNullException("fileName");
+ }
+
+ if ( !ZipEntry.IsCompressionMethodSupported(compressionMethod) ) {
+ throw new ZipException("Compression method not supported");
+ }
+
+ CheckUpdating();
+ contentsEdited_ = true;
+
+ ZipEntry entry = EntryFactory.MakeFileEntry(fileName);
+ entry.CompressionMethod = compressionMethod;
+ AddUpdate(new ZipUpdate(fileName, entry));
+ }
+
+ /// <summary>
+ /// Add a file to the archive.
+ /// </summary>
+ /// <param name="fileName">The name of the file to add.</param>
+ public void Add(string fileName)
+ {
+ if ( fileName == null ) {
+ throw new ArgumentNullException("fileName");
+ }
+
+ CheckUpdating();
+ AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));
+ }
+
+ /// <summary>
+ /// Add a file entry with data.
+ /// </summary>
+ /// <param name="dataSource">The source of the data for this entry.</param>
+ /// <param name="entryName">The name to give to the entry.</param>
+ public void Add(IStaticDataSource dataSource, string entryName)
+ {
+ if ( dataSource == null ) {
+ throw new ArgumentNullException("dataSource");
+ }
+
+ CheckUpdating();
+ AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName)));
+ }
+
+ /// <summary>
+ /// Add a file entry with data.
+ /// </summary>
+ /// <param name="dataSource">The source of the data for this entry.</param>
+ /// <param name="entryName">The name to give to the entry.</param>
+ /// <param name="compressionMethod">The compression method to use.</param>
+ public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
+ {
+ if ( dataSource == null ) {
+ throw new ArgumentNullException("dataSource");
+ }
+
+ CheckUpdating();
+
+ ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);
+ entry.CompressionMethod = compressionMethod;
+
+ AddUpdate(new ZipUpdate(dataSource, entry));
+ }
+
+ /// <summary>
+ /// Add a file entry with data.
+ /// </summary>
+ /// <param name="dataSource">The source of the data for this entry.</param>
+ /// <param name="entryName">The name to give to the entry.</param>
+ /// <param name="compressionMethod">The compression method to use.</param>
+ /// <param name="useUnicodeText">Ensure Unicode text is used for name and comments for this entry.</param>
+ public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod, bool useUnicodeText)
+ {
+ if (dataSource == null) {
+ throw new ArgumentNullException("dataSource");
+ }
+
+ CheckUpdating();
+
+ ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);
+ entry.IsUnicodeText = useUnicodeText;
+ entry.CompressionMethod = compressionMethod;
+
+ AddUpdate(new ZipUpdate(dataSource, entry));
+ }
+
+ /// <summary>
+ /// Add a <see cref="ZipEntry"/> that contains no data.
+ /// </summary>
+ /// <param name="entry">The entry to add.</param>
+ /// <remarks>This can be used to add directories, volume labels, or empty file entries.</remarks>
+ public void Add(ZipEntry entry)
+ {
+ if ( entry == null ) {
+ throw new ArgumentNullException("entry");
+ }
+
+ CheckUpdating();
+
+ if ( (entry.Size != 0) || (entry.CompressedSize != 0) ) {
+ throw new ZipException("Entry cannot have any data");
+ }
+
+ AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));
+ }
+
+ /// <summary>
+ /// Add a directory entry to the archive.
+ /// </summary>
+ /// <param name="directoryName">The directory to add.</param>
+ public void AddDirectory(string directoryName)
+ {
+ if ( directoryName == null ) {
+ throw new ArgumentNullException("directoryName");
+ }
+
+ CheckUpdating();
+
+ ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);
+ AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));
+ }
+
+ #endregion
+
+ #region Modifying Entries
+/* Modify not yet ready for public consumption.
+ Direct modification of an entry should not overwrite original data before its read.
+ Safe mode is trivial in this sense.
+ public void Modify(ZipEntry original, ZipEntry updated)
+ {
+ if ( original == null ) {
+ throw new ArgumentNullException("original");
+ }
+
+ if ( updated == null ) {
+ throw new ArgumentNullException("updated");
+ }
+
+ CheckUpdating();
+ contentsEdited_ = true;
+ updates_.Add(new ZipUpdate(original, updated));
+ }
+*/
+ #endregion
+
+ #region Deleting Entries
+ /// <summary>
+ /// Delete an entry by name
+ /// </summary>
+ /// <param name="fileName">The filename to delete</param>
+ /// <returns>True if the entry was found and deleted; false otherwise.</returns>
+ public bool Delete(string fileName)
+ {
+ CheckUpdating();
+
+ bool result = false;
+ int index = FindExistingUpdate(fileName);
+ if ( (index >= 0) && (updates_[index] != null) ) {
+ result = true;
+ contentsEdited_ = true;
+ updates_[index] = null;
+ updateCount_ -= 1;
+ }
+ else {
+ throw new ZipException("Cannot find entry to delete");
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Delete a <see cref="ZipEntry"/> from the archive.
+ /// </summary>
+ /// <param name="entry">The entry to delete.</param>
+ public void Delete(ZipEntry entry)
+ {
+ CheckUpdating();
+
+ int index = FindExistingUpdate(entry);
+ if ( index >= 0 ) {
+ contentsEdited_ = true;
+ updates_[index] = null;
+ updateCount_ -= 1;
+ }
+ else {
+ throw new ZipException("Cannot find entry to delete");
+ }
+ }
+
+ #endregion
+
+ #region Update Support
+ #region Writing Values/Headers
+ void WriteLEShort(int value)
+ {
+ baseStream_.WriteByte(( byte )(value & 0xff));
+ baseStream_.WriteByte(( byte )((value >> 8) & 0xff));
+ }
+
+ /// <summary>
+ /// Write an unsigned short in little endian byte order.
+ /// </summary>
+ void WriteLEUshort(ushort value)
+ {
+ baseStream_.WriteByte(( byte )(value & 0xff));
+ baseStream_.WriteByte(( byte )(value >> 8));
+ }
+
+ /// <summary>
+ /// Write an int in little endian byte order.
+ /// </summary>
+ void WriteLEInt(int value)
+ {
+ WriteLEShort(value & 0xffff);
+ WriteLEShort(value >> 16);
+ }
+
+ /// <summary>
+ /// Write an unsigned int in little endian byte order.
+ /// </summary>
+ void WriteLEUint(uint value)
+ {
+ WriteLEUshort((ushort)(value & 0xffff));
+ WriteLEUshort((ushort)(value >> 16));
+ }
+
+ /// <summary>
+ /// Write a long in little endian byte order.
+ /// </summary>
+ void WriteLeLong(long value)
+ {
+ WriteLEInt(( int )(value & 0xffffffff));
+ WriteLEInt(( int )(value >> 32));
+ }
+
+ void WriteLEUlong(ulong value)
+ {
+ WriteLEUint(( uint )(value & 0xffffffff));
+ WriteLEUint(( uint )(value >> 32));
+ }
+
+ void WriteLocalEntryHeader(ZipUpdate update)
+ {
+ ZipEntry entry = update.OutEntry;
+
+ // TODO: Local offset will require adjusting for multi-disk zip files.
+ entry.Offset = baseStream_.Position;
+
+ // TODO: Need to clear any entry flags that dont make sense or throw an exception here.
+ if (update.Command != UpdateCommand.Copy) {
+ if (entry.CompressionMethod == CompressionMethod.Deflated) {
+ if (entry.Size == 0) {
+ // No need to compress - no data.
+ entry.CompressedSize = entry.Size;
+ entry.Crc = 0;
+ entry.CompressionMethod = CompressionMethod.Stored;
+ }
+ }
+ else if (entry.CompressionMethod == CompressionMethod.Stored) {
+ entry.Flags &= ~(int)GeneralBitFlags.Descriptor;
+ }
+
+ if (HaveKeys) {
+ entry.IsCrypted = true;
+ if (entry.Crc < 0) {
+ entry.Flags |= (int)GeneralBitFlags.Descriptor;
+ }
+ }
+ else {
+ entry.IsCrypted = false;
+ }
+
+ switch (useZip64_) {
+ case UseZip64.Dynamic:
+ if (entry.Size < 0) {
+ entry.ForceZip64();
+ }
+ break;
+
+ case UseZip64.On:
+ entry.ForceZip64();
+ break;
+
+ case UseZip64.Off:
+ // Do nothing. The entry itself may be using Zip64 independantly.
+ break;
+ }
+ }
+
+ // Write the local file header
+ WriteLEInt(ZipConstants.LocalHeaderSignature);
+
+ WriteLEShort(entry.Version);
+ WriteLEShort(entry.Flags);
+
+ WriteLEShort((byte)entry.CompressionMethod);
+ WriteLEInt(( int )entry.DosTime);
+
+ if ( !entry.HasCrc ) {
+ // Note patch address for updating CRC later.
+ update.CrcPatchOffset = baseStream_.Position;
+ WriteLEInt(( int )0);
+ }
+ else {
+ WriteLEInt(unchecked(( int )entry.Crc));
+ }
+
+ if (entry.LocalHeaderRequiresZip64) {
+ WriteLEInt(-1);
+ WriteLEInt(-1);
+ }
+ else {
+ if ( (entry.CompressedSize < 0) || (entry.Size < 0) ) {
+ update.SizePatchOffset = baseStream_.Position;
+ }
+
+ WriteLEInt(( int )entry.CompressedSize);
+ WriteLEInt(( int )entry.Size);
+ }
+
+ byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
+
+ if ( name.Length > 0xFFFF ) {
+ throw new ZipException("Entry name too long.");
+ }
+
+ ZipExtraData ed = new ZipExtraData(entry.ExtraData);
+
+ if ( entry.LocalHeaderRequiresZip64 ) {
+ ed.StartNewEntry();
+
+ // Local entry header always includes size and compressed size.
+ // NOTE the order of these fields is reversed when compared to the normal headers!
+ ed.AddLeLong(entry.Size);
+ ed.AddLeLong(entry.CompressedSize);
+ ed.AddNewEntry(1);
+ }
+ else {
+ ed.Delete(1);
+ }
+
+ entry.ExtraData = ed.GetEntryData();
+
+ WriteLEShort(name.Length);
+ WriteLEShort(entry.ExtraData.Length);
+
+ if ( name.Length > 0 ) {
+ baseStream_.Write(name, 0, name.Length);
+ }
+
+ if ( entry.LocalHeaderRequiresZip64 ) {
+ if ( !ed.Find(1) ) {
+ throw new ZipException("Internal error cannot find extra data");
+ }
+
+ update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;
+ }
+
+ if ( entry.ExtraData.Length > 0 ) {
+ baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);
+ }
+ }
+
+ int WriteCentralDirectoryHeader(ZipEntry entry)
+ {
+ if ( entry.CompressedSize < 0 ) {
+ throw new ZipException("Attempt to write central directory entry with unknown csize");
+ }
+
+ if ( entry.Size < 0 ) {
+ throw new ZipException("Attempt to write central directory entry with unknown size");
+ }
+
+ if ( entry.Crc < 0 ) {
+ throw new ZipException("Attempt to write central directory entry with unknown crc");
+ }
+
+ // Write the central file header
+ WriteLEInt(ZipConstants.CentralHeaderSignature);
+
+ // Version made by
+ WriteLEShort(ZipConstants.VersionMadeBy);
+
+ // Version required to extract
+ WriteLEShort(entry.Version);
+
+ WriteLEShort(entry.Flags);
+
+ unchecked {
+ WriteLEShort((byte)entry.CompressionMethod);
+ WriteLEInt((int)entry.DosTime);
+ WriteLEInt((int)entry.Crc);
+ }
+
+ if ( (entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff) ) {
+ WriteLEInt(-1);
+ }
+ else {
+ WriteLEInt((int)(entry.CompressedSize & 0xffffffff));
+ }
+
+ if ( (entry.IsZip64Forced()) || (entry.Size >= 0xffffffff) ) {
+ WriteLEInt(-1);
+ }
+ else {
+ WriteLEInt((int)entry.Size);
+ }
+
+ byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
+
+ if ( name.Length > 0xFFFF ) {
+ throw new ZipException("Entry name is too long.");
+ }
+
+ WriteLEShort(name.Length);
+
+ // Central header extra data is different to local header version so regenerate.
+ ZipExtraData ed = new ZipExtraData(entry.ExtraData);
+
+ if ( entry.CentralHeaderRequiresZip64 ) {
+ ed.StartNewEntry();
+
+ if ( (entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On) )
+ {
+ ed.AddLeLong(entry.Size);
+ }
+
+ if ( (entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On) )
+ {
+ ed.AddLeLong(entry.CompressedSize);
+ }
+
+ if ( entry.Offset >= 0xffffffff ) {
+ ed.AddLeLong(entry.Offset);
+ }
+
+ // Number of disk on which this file starts isnt supported and is never written here.
+ ed.AddNewEntry(1);
+ }
+ else {
+ // Should have already be done when local header was added.
+ ed.Delete(1);
+ }
+
+ byte[] centralExtraData = ed.GetEntryData();
+
+ WriteLEShort(centralExtraData.Length);
+ WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);
+
+ WriteLEShort(0); // disk number
+ WriteLEShort(0); // internal file attributes
+
+ // External file attributes...
+ if ( entry.ExternalFileAttributes != -1 ) {
+ WriteLEInt(entry.ExternalFileAttributes);
+ }
+ else {
+ if ( entry.IsDirectory ) {
+ WriteLEUint(16);
+ }
+ else {
+ WriteLEUint(0);
+ }
+ }
+
+ if ( entry.Offset >= 0xffffffff ) {
+ WriteLEUint(0xffffffff);
+ }
+ else {
+ WriteLEUint((uint)(int)entry.Offset);
+ }
+
+ if ( name.Length > 0 ) {
+ baseStream_.Write(name, 0, name.Length);
+ }
+
+ if ( centralExtraData.Length > 0 ) {
+ baseStream_.Write(centralExtraData, 0, centralExtraData.Length);
+ }
+
+ byte[] rawComment = (entry.Comment != null) ? Encoding.UTF8.GetBytes(entry.Comment) : new byte[0];
+
+ if ( rawComment.Length > 0 ) {
+ baseStream_.Write(rawComment, 0, rawComment.Length);
+ }
+
+ return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;
+ }
+ #endregion
+ void PostUpdateCleanup()
+ {
+ if( archiveStorage_!=null ) {
+ archiveStorage_.Dispose();
+ archiveStorage_=null;
+ }
+
+ updateDataSource_=null;
+ updates_ = null;
+ updateIndex_ = null;
+ }
+
+ string GetTransformedFileName(string name)
+ {
+ return (NameTransform != null) ?
+ NameTransform.TransformFile(name) :
+ name;
+ }
+
+ string GetTransformedDirectoryName(string name)
+ {
+ return (NameTransform != null) ?
+ NameTransform.TransformDirectory(name) :
+ name;
+ }
+
+ /// <summary>
+ /// Get a raw memory buffer.
+ /// </summary>
+ /// <returns>Returns a raw memory buffer.</returns>
+ byte[] GetBuffer()
+ {
+ if ( copyBuffer_ == null ) {
+ copyBuffer_ = new byte[bufferSize_];
+ }
+ return copyBuffer_;
+ }
+
+ void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)
+ {
+ int bytesToCopy = GetDescriptorSize(update);
+
+ if ( bytesToCopy > 0 ) {
+ byte[] buffer = GetBuffer();
+
+ while ( bytesToCopy > 0 ) {
+ int readSize = Math.Min(buffer.Length, bytesToCopy);
+
+ int bytesRead = source.Read(buffer, 0, readSize);
+ if ( bytesRead > 0 ) {
+ dest.Write(buffer, 0, bytesRead);
+ bytesToCopy -= bytesRead;
+ }
+ else {
+ throw new ZipException("Unxpected end of stream");
+ }
+ }
+ }
+ }
+
+ void CopyBytes(ZipUpdate update, Stream destination, Stream source,
+ long bytesToCopy, bool updateCrc)
+ {
+ if ( destination == source ) {
+ throw new InvalidOperationException("Destination and source are the same");
+ }
+
+ // NOTE: Compressed size is updated elsewhere.
+ Crc32 crc = new Crc32();
+ byte[] buffer = GetBuffer();
+
+ long targetBytes = bytesToCopy;
+ long totalBytesRead = 0;
+
+ int bytesRead;
+ do {
+ int readSize = buffer.Length;
+
+ if ( bytesToCopy < readSize ) {
+ readSize = (int)bytesToCopy;
+ }
+
+ bytesRead = source.Read(buffer, 0, readSize);
+ if ( bytesRead > 0 ) {
+ if ( updateCrc ) {
+ crc.Update(buffer, 0, bytesRead);
+ }
+ destination.Write(buffer, 0, bytesRead);
+ bytesToCopy -= bytesRead;
+ totalBytesRead += bytesRead;
+ }
+ }
+ while ( (bytesRead > 0) && (bytesToCopy > 0) );
+
+ if ( totalBytesRead != targetBytes ) {
+ throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead));
+ }
+
+ if ( updateCrc ) {
+ update.OutEntry.Crc = crc.Value;
+ }
+ }
+
+ /// <summary>
+ /// Get the size of the source descriptor for a <see cref="ZipUpdate"/>.
+ /// </summary>
+ /// <param name="update">The update to get the size for.</param>
+ /// <returns>The descriptor size, zero if there isnt one.</returns>
+ int GetDescriptorSize(ZipUpdate update)
+ {
+ int result = 0;
+ if ( (update.Entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {
+ result = ZipConstants.DataDescriptorSize - 4;
+ if ( update.Entry.LocalHeaderRequiresZip64 ) {
+ result = ZipConstants.Zip64DataDescriptorSize - 4;
+ }
+ }
+ return result;
+ }
+
+ void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)
+ {
+ int bytesToCopy = GetDescriptorSize(update);
+
+ while ( bytesToCopy > 0 ) {
+ int readSize = (int)bytesToCopy;
+ byte[] buffer = GetBuffer();
+
+ stream.Position = sourcePosition;
+ int bytesRead = stream.Read(buffer, 0, readSize);
+ if ( bytesRead > 0 ) {
+ stream.Position = destinationPosition;
+ stream.Write(buffer, 0, bytesRead);
+ bytesToCopy -= bytesRead;
+ destinationPosition += bytesRead;
+ sourcePosition += bytesRead;
+ }
+ else {
+ throw new ZipException("Unxpected end of stream");
+ }
+ }
+ }
+
+ void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sourcePosition)
+ {
+ long bytesToCopy = update.Entry.CompressedSize;
+
+ // NOTE: Compressed size is updated elsewhere.
+ Crc32 crc = new Crc32();
+ byte[] buffer = GetBuffer();
+
+ long targetBytes = bytesToCopy;
+ long totalBytesRead = 0;
+
+ int bytesRead;
+ do
+ {
+ int readSize = buffer.Length;
+
+ if ( bytesToCopy < readSize ) {
+ readSize = (int)bytesToCopy;
+ }
+
+ stream.Position = sourcePosition;
+ bytesRead = stream.Read(buffer, 0, readSize);
+ if ( bytesRead > 0 ) {
+ if ( updateCrc ) {
+ crc.Update(buffer, 0, bytesRead);
+ }
+ stream.Position = destinationPosition;
+ stream.Write(buffer, 0, bytesRead);
+
+ destinationPosition += bytesRead;
+ sourcePosition += bytesRead;
+ bytesToCopy -= bytesRead;
+ totalBytesRead += bytesRead;
+ }
+ }
+ while ( (bytesRead > 0) && (bytesToCopy > 0) );
+
+ if ( totalBytesRead != targetBytes ) {
+ throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead));
+ }
+
+ if ( updateCrc ) {
+ update.OutEntry.Crc = crc.Value;
+ }
+ }
+
+ int FindExistingUpdate(ZipEntry entry)
+ {
+ int result = -1;
+ string convertedName = GetTransformedFileName(entry.Name);
+
+ if (updateIndex_.ContainsKey(convertedName)) {
+ result = (int)updateIndex_[convertedName];
+ }
+/*
+ // This is slow like the coming of the next ice age but takes less storage and may be useful
+ // for CF?
+ for (int index = 0; index < updates_.Count; ++index)
+ {
+ ZipUpdate zu = ( ZipUpdate )updates_[index];
+ if ( (zu.Entry.ZipFileIndex == entry.ZipFileIndex) &&
+ (string.Compare(convertedName, zu.Entry.Name, true, CultureInfo.InvariantCulture) == 0) ) {
+ result = index;
+ break;
+ }
+ }
+ */
+ return result;
+ }
+
+ int FindExistingUpdate(string fileName)
+ {
+ int result = -1;
+
+ string convertedName = GetTransformedFileName(fileName);
+
+ if (updateIndex_.ContainsKey(convertedName)) {
+ result = (int)updateIndex_[convertedName];
+ }
+
+/*
+ // This is slow like the coming of the next ice age but takes less storage and may be useful
+ // for CF?
+ for ( int index = 0; index < updates_.Count; ++index ) {
+ if ( string.Compare(convertedName, (( ZipUpdate )updates_[index]).Entry.Name,
+ true, CultureInfo.InvariantCulture) == 0 ) {
+ result = index;
+ break;
+ }
+ }
+ */
+
+ return result;
+ }
+
+ /// <summary>
+ /// Get an output stream for the specified <see cref="ZipEntry"/>
+ /// </summary>
+ /// <param name="entry">The entry to get an output stream for.</param>
+ /// <returns>The output stream obtained for the entry.</returns>
+ Stream GetOutputStream(ZipEntry entry)
+ {
+ Stream result = baseStream_;
+
+ if ( entry.IsCrypted == true ) {
+#if NETCF_1_0
+ throw new ZipException("Encryption not supported for Compact Framework 1.0");
+#else
+ result = CreateAndInitEncryptionStream(result, entry);
+#endif
+ }
+
+ switch ( entry.CompressionMethod ) {
+ case CompressionMethod.Stored:
+ result = new UncompressedStream(result);
+ break;
+
+ case CompressionMethod.Deflated:
+ DeflaterOutputStream dos = new DeflaterOutputStream(result, new Deflater(9, true));
+ dos.IsStreamOwner = false;
+ result = dos;
+ break;
+
+ default:
+ throw new ZipException("Unknown compression method " + entry.CompressionMethod);
+ }
+ return result;
+ }
+
+ void AddEntry(ZipFile workFile, ZipUpdate update)
+ {
+ Stream source = null;
+
+ if ( update.Entry.IsFile ) {
+ source = update.GetSource();
+
+ if ( source == null ) {
+ source = updateDataSource_.GetSource(update.Entry, update.Filename);
+ }
+ }
+
+ if ( source != null ) {
+ using ( source ) {
+ long sourceStreamLength = source.Length;
+ if ( update.OutEntry.Size < 0 ) {
+ update.OutEntry.Size = sourceStreamLength;
+ }
+ else {
+ // Check for errant entries.
+ if ( update.OutEntry.Size != sourceStreamLength ) {
+ throw new ZipException("Entry size/stream size mismatch");
+ }
+ }
+
+ workFile.WriteLocalEntryHeader(update);
+
+ long dataStart = workFile.baseStream_.Position;
+
+ using ( Stream output = workFile.GetOutputStream(update.OutEntry) ) {
+ CopyBytes(update, output, source, sourceStreamLength, true);
+ }
+
+ long dataEnd = workFile.baseStream_.Position;
+ update.OutEntry.CompressedSize = dataEnd - dataStart;
+
+ if ((update.OutEntry.Flags & (int)GeneralBitFlags.Descriptor) == (int)GeneralBitFlags.Descriptor)
+ {
+ ZipHelperStream helper = new ZipHelperStream(workFile.baseStream_);
+ helper.WriteDataDescriptor(update.OutEntry);
+ }
+ }
+ }
+ else {
+ workFile.WriteLocalEntryHeader(update);
+ update.OutEntry.CompressedSize = 0;
+ }
+
+ }
+
+ void ModifyEntry(ZipFile workFile, ZipUpdate update)
+ {
+ workFile.WriteLocalEntryHeader(update);
+ long dataStart = workFile.baseStream_.Position;
+
+ // TODO: This is slow if the changes don't effect the data!!
+ if ( update.Entry.IsFile && (update.Filename != null) ) {
+ using ( Stream output = workFile.GetOutputStream(update.OutEntry) ) {
+ using ( Stream source = this.GetInputStream(update.Entry) ) {
+ CopyBytes(update, output, source, source.Length, true);
+ }
+ }
+ }
+
+ long dataEnd = workFile.baseStream_.Position;
+ update.Entry.CompressedSize = dataEnd - dataStart;
+ }
+
+ void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)
+ {
+ bool skipOver = false;
+ if ( update.Entry.Offset == destinationPosition ) {
+ skipOver = true;
+ }
+
+ if ( !skipOver ) {
+ baseStream_.Position = destinationPosition;
+ workFile.WriteLocalEntryHeader(update);
+ destinationPosition = baseStream_.Position;
+ }
+
+ long sourcePosition = 0;
+
+ const int NameLengthOffset = 26;
+
+ // TODO: Add base for SFX friendly handling
+ long entryDataOffset = update.Entry.Offset + NameLengthOffset;
+
+ baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);
+
+ // Clumsy way of handling retrieving the original name and extra data length for now.
+ // TODO: Stop re-reading name and data length in CopyEntryDirect.
+ uint nameLength = ReadLEUshort();
+ uint extraLength = ReadLEUshort();
+
+ sourcePosition = baseStream_.Position + nameLength + extraLength;
+
+ if ( skipOver ) {
+ destinationPosition +=
+ (sourcePosition - entryDataOffset) + NameLengthOffset + // Header size
+ update.Entry.CompressedSize + GetDescriptorSize(update);
+ }
+ else {
+ if ( update.Entry.CompressedSize > 0 ) {
+ CopyEntryDataDirect(update, baseStream_, false, ref destinationPosition, ref sourcePosition );
+ }
+ CopyDescriptorBytesDirect(update, baseStream_, ref destinationPosition, sourcePosition);
+ }
+ }
+
+ void CopyEntry(ZipFile workFile, ZipUpdate update)
+ {
+ workFile.WriteLocalEntryHeader(update);
+
+ if ( update.Entry.CompressedSize > 0 ) {
+ const int NameLengthOffset = 26;
+
+ long entryDataOffset = update.Entry.Offset + NameLengthOffset;
+
+ // TODO: This wont work for SFX files!
+ baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);
+
+ uint nameLength = ReadLEUshort();
+ uint extraLength = ReadLEUshort();
+
+ baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);
+
+ CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);
+ }
+ CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);
+ }
+
+ void Reopen(Stream source)
+ {
+ if ( source == null ) {
+ throw new ZipException("Failed to reopen archive - no source");
+ }
+
+ isNewArchive_ = false;
+ baseStream_ = source;
+ ReadEntries();
+ }
+
+ void Reopen()
+ {
+ if (Name == null) {
+ throw new InvalidOperationException("Name is not known cannot Reopen");
+ }
+
+ Reopen(File.OpenRead(Name));
+ }
+
+ void UpdateCommentOnly()
+ {
+ long baseLength = baseStream_.Length;
+
+ ZipHelperStream updateFile = null;
+
+ if ( archiveStorage_.UpdateMode == FileUpdateMode.Safe ) {
+ Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);
+ updateFile = new ZipHelperStream(copyStream);
+ updateFile.IsStreamOwner = true;
+
+ baseStream_.Close();
+ baseStream_ = null;
+ }
+ else {
+ if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {
+ // TODO: archiveStorage wasnt originally intended for this use.
+ // Need to revisit this to tidy up handling as archive storage currently doesnt
+ // handle the original stream well.
+ // The problem is when using an existing zip archive with an in memory archive storage.
+ // The open stream wont support writing but the memory storage should open the same file not an in memory one.
+
+ // Need to tidy up the archive storage interface and contract basically.
+ baseStream_ = archiveStorage_.OpenForDirectUpdate(baseStream_);
+ updateFile = new ZipHelperStream(baseStream_);
+ }
+ else {
+ baseStream_.Close();
+ baseStream_ = null;
+ updateFile = new ZipHelperStream(Name);
+ }
+ }
+
+ using ( updateFile ) {
+ long locatedCentralDirOffset =
+ updateFile.LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,
+ baseLength, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);
+ if ( locatedCentralDirOffset < 0 ) {
+ throw new ZipException("Cannot find central directory");
+ }
+
+ const int CentralHeaderCommentSizeOffset = 16;
+ updateFile.Position += CentralHeaderCommentSizeOffset;
+
+ byte[] rawComment = newComment_.RawComment;
+
+ updateFile.WriteLEShort(rawComment.Length);
+ updateFile.Write(rawComment, 0, rawComment.Length);
+ updateFile.SetLength(updateFile.Position);
+ }
+
+ if ( archiveStorage_.UpdateMode == FileUpdateMode.Safe ) {
+ Reopen(archiveStorage_.ConvertTemporaryToFinal());
+ }
+ else {
+ ReadEntries();
+ }
+ }
+
+ /// <summary>
+ /// Class used to sort updates.
+ /// </summary>
+ class UpdateComparer : IComparer<ZipUpdate>
+ {
+ /// <summary>
+ /// Compares two objects and returns a value indicating whether one is
+ /// less than, equal to or greater than the other.
+ /// </summary>
+ /// <param name="x">First object to compare</param>
+ /// <param name="y">Second object to compare.</param>
+ /// <returns>Compare result.</returns>
+ public int Compare(
+ ZipUpdate x,
+ ZipUpdate y)
+ {
+ ZipUpdate zx = x as ZipUpdate;
+ ZipUpdate zy = y as ZipUpdate;
+
+ int result;
+
+ if (zx == null) {
+ if (zy == null) {
+ result = 0;
+ }
+ else {
+ result = -1;
+ }
+ }
+ else if (zy == null) {
+ result = 1;
+ }
+ else {
+ int xCmdValue = ((zx.Command == UpdateCommand.Copy) || (zx.Command == UpdateCommand.Modify)) ? 0 : 1;
+ int yCmdValue = ((zy.Command == UpdateCommand.Copy) || (zy.Command == UpdateCommand.Modify)) ? 0 : 1;
+
+ result = xCmdValue - yCmdValue;
+ if (result == 0) {
+ long offsetDiff = zx.Entry.Offset - zy.Entry.Offset;
+ if (offsetDiff < 0) {
+ result = -1;
+ }
+ else if (offsetDiff == 0) {
+ result = 0;
+ }
+ else {
+ result = 1;
+ }
+ }
+ }
+ return result;
+ }
+ }
+
+ void RunUpdates()
+ {
+ long sizeEntries = 0;
+ long endOfStream = 0;
+ bool allOk = true;
+ bool directUpdate = false;
+ long destinationPosition = 0; // NOT SFX friendly
+
+ ZipFile workFile;
+
+ if ( IsNewArchive ) {
+ workFile = this;
+ workFile.baseStream_.Position = 0;
+ directUpdate = true;
+ }
+ else if ( archiveStorage_.UpdateMode == FileUpdateMode.Direct ) {
+ workFile = this;
+ workFile.baseStream_.Position = 0;
+ directUpdate = true;
+
+ // Sort the updates by offset within copies/modifies, then adds.
+ // This ensures that data required by copies will not be overwritten.
+ updates_.Sort(new UpdateComparer());
+ }
+ else {
+ workFile = ZipFile.Create(archiveStorage_.GetTemporaryOutput());
+ workFile.UseZip64 = UseZip64;
+
+ if (key != null) {
+ workFile.key = (byte[])key.Clone();
+ }
+ }
+
+ try {
+ foreach ( ZipUpdate update in updates_ ) {
+ if (update != null) {
+ switch (update.Command) {
+ case UpdateCommand.Copy:
+ if (directUpdate) {
+ CopyEntryDirect(workFile, update, ref destinationPosition);
+ }
+ else {
+ CopyEntry(workFile, update);
+ }
+ break;
+
+ case UpdateCommand.Modify:
+ // TODO: Direct modifying of an entry will take some legwork.
+ ModifyEntry(workFile, update);
+ break;
+
+ case UpdateCommand.Add:
+ if (!IsNewArchive && directUpdate) {
+ workFile.baseStream_.Position = destinationPosition;
+ }
+
+ AddEntry(workFile, update);
+
+ if (directUpdate) {
+ destinationPosition = workFile.baseStream_.Position;
+ }
+ break;
+ }
+ }
+ }
+
+ if ( !IsNewArchive && directUpdate ) {
+ workFile.baseStream_.Position = destinationPosition;
+ }
+
+ long centralDirOffset = workFile.baseStream_.Position;
+
+ foreach ( ZipUpdate update in updates_ ) {
+ if (update != null) {
+ sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);
+ }
+ }
+
+ byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
+ using ( ZipHelperStream zhs = new ZipHelperStream(workFile.baseStream_) ) {
+ zhs.WriteEndOfCentralDirectory(updateCount_, sizeEntries, centralDirOffset, theComment);
+ }
+
+ endOfStream = workFile.baseStream_.Position;
+
+ // And now patch entries...
+ foreach ( ZipUpdate update in updates_ ) {
+ if (update != null)
+ {
+
+ // If the size of the entry is zero leave the crc as 0 as well.
+ // The calculated crc will be all bits on...
+ if ((update.CrcPatchOffset > 0) && (update.OutEntry.CompressedSize > 0)) {
+ workFile.baseStream_.Position = update.CrcPatchOffset;
+ workFile.WriteLEInt((int)update.OutEntry.Crc);
+ }
+
+ if (update.SizePatchOffset > 0) {
+ workFile.baseStream_.Position = update.SizePatchOffset;
+ if (update.OutEntry.LocalHeaderRequiresZip64) {
+ workFile.WriteLeLong(update.OutEntry.Size);
+ workFile.WriteLeLong(update.OutEntry.CompressedSize);
+ }
+ else {
+ workFile.WriteLEInt((int)update.OutEntry.CompressedSize);
+ workFile.WriteLEInt((int)update.OutEntry.Size);
+ }
+ }
+ }
+ }
+ }
+ catch(Exception) {
+ allOk = false;
+ }
+ finally {
+ if ( directUpdate ) {
+ if ( allOk ) {
+ workFile.baseStream_.Flush();
+ workFile.baseStream_.SetLength(endOfStream);
+ }
+ }
+ else {
+ workFile.Close();
+ }
+ }
+
+ if ( allOk ) {
+ if ( directUpdate ) {
+ isNewArchive_ = false;
+ workFile.baseStream_.Flush();
+ ReadEntries();
+ }
+ else {
+ baseStream_.Close();
+ Reopen(archiveStorage_.ConvertTemporaryToFinal());
+ }
+ }
+ else {
+ workFile.Close();
+ if ( !directUpdate && (workFile.Name != null) ) {
+ File.Delete(workFile.Name);
+ }
+ }
+ }
+
+ void CheckUpdating()
+ {
+ if ( updates_ == null ) {
+ throw new ZipException("Cannot update until BeginUpdate has been called");
+ }
+ }
+
+ #endregion
+
+ #region ZipUpdate class
+ /// <summary>
+ /// Represents a pending update to a Zip file.
+ /// </summary>
+ class ZipUpdate
+ {
+ #region Constructors
+ public ZipUpdate(string fileName, ZipEntry entry)
+ {
+ command_ = UpdateCommand.Add;
+ entry_ = entry;
+ filename_ = fileName;
+ }
+
+ [Obsolete]
+ public ZipUpdate(string fileName, string entryName, CompressionMethod compressionMethod)
+ {
+ command_ = UpdateCommand.Add;
+ entry_ = new ZipEntry(entryName);
+ entry_.CompressionMethod = compressionMethod;
+ filename_ = fileName;
+ }
+
+ [Obsolete]
+ public ZipUpdate(string fileName, string entryName)
+ : this(fileName, entryName, CompressionMethod.Deflated)
+ {
+ // Do nothing.
+ }
+
+ [Obsolete]
+ public ZipUpdate(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
+ {
+ command_ = UpdateCommand.Add;
+ entry_ = new ZipEntry(entryName);
+ entry_.CompressionMethod = compressionMethod;
+ dataSource_ = dataSource;
+ }
+
+ public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)
+ {
+ command_ = UpdateCommand.Add;
+ entry_ = entry;
+ dataSource_ = dataSource;
+ }
+
+ public ZipUpdate(ZipEntry original, ZipEntry updated)
+ {
+ throw new ZipException("Modify not currently supported");
+ /*
+ command_ = UpdateCommand.Modify;
+ entry_ = ( ZipEntry )original.Clone();
+ outEntry_ = ( ZipEntry )updated.Clone();
+ */
+ }
+
+ public ZipUpdate(UpdateCommand command, ZipEntry entry)
+ {
+ command_ = command;
+ entry_ = ( ZipEntry )entry.Clone();
+ }
+
+
+ /// <summary>
+ /// Copy an existing entry.
+ /// </summary>
+ /// <param name="entry">The existing entry to copy.</param>
+ public ZipUpdate(ZipEntry entry)
+ : this(UpdateCommand.Copy, entry)
+ {
+ // Do nothing.
+ }
+ #endregion
+
+ /// <summary>
+ /// Get the <see cref="ZipEntry"/> for this update.
+ /// </summary>
+ /// <remarks>This is the source or original entry.</remarks>
+ public ZipEntry Entry
+ {
+ get { return entry_; }
+ }
+
+ /// <summary>
+ /// Get the <see cref="ZipEntry"/> that will be written to the updated/new file.
+ /// </summary>
+ public ZipEntry OutEntry
+ {
+ get {
+ if ( outEntry_ == null ) {
+ outEntry_ = (ZipEntry)entry_.Clone();
+ }
+
+ return outEntry_;
+ }
+ }
+
+ /// <summary>
+ /// Get the command for this update.
+ /// </summary>
+ public UpdateCommand Command
+ {
+ get { return command_; }
+ }
+
+ /// <summary>
+ /// Get the filename if any for this update. Null if none exists.
+ /// </summary>
+ public string Filename
+ {
+ get { return filename_; }
+ }
+
+ /// <summary>
+ /// Get/set the location of the size patch for this update.
+ /// </summary>
+ public long SizePatchOffset
+ {
+ get { return sizePatchOffset_; }
+ set { sizePatchOffset_ = value; }
+ }
+
+ /// <summary>
+ /// Get /set the location of the crc patch for this update.
+ /// </summary>
+ public long CrcPatchOffset
+ {
+ get { return crcPatchOffset_; }
+ set { crcPatchOffset_ = value; }
+ }
+
+ public Stream GetSource()
+ {
+ Stream result = null;
+ if ( dataSource_ != null ) {
+ result = dataSource_.GetSource();
+ }
+
+ return result;
+ }
+
+ #region Instance Fields
+ ZipEntry entry_;
+ ZipEntry outEntry_;
+ UpdateCommand command_;
+ IStaticDataSource dataSource_;
+ string filename_;
+ long sizePatchOffset_ = -1;
+ long crcPatchOffset_ = -1;
+ #endregion
+ }
+
+ #endregion
+ #endregion
+
+ #region Disposing
+
+ #region IDisposable Members
+ void IDisposable.Dispose()
+ {
+ Close();
+ }
+ #endregion
+
+ void DisposeInternal(bool disposing)
+ {
+ if ( !isDisposed_ ) {
+ isDisposed_ = true;
+ entries_ = null;
+ if ( IsStreamOwner && (baseStream_ != null) ) {
+ lock(baseStream_) {
+ baseStream_.Close();
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Releases the unmanaged resources used by the this instance and optionally releases the managed resources.
+ /// </summary>
+ /// <param name="disposing">true to release both managed and unmanaged resources;
+ /// false to release only unmanaged resources.</param>
+ protected virtual void Dispose(bool disposing)
+ {
+ DisposeInternal(disposing);
+ }
+
+ #endregion
+
+ #region Internal routines
+ #region Reading
+ /// <summary>
+ /// Read an unsigned short in little endian byte order.
+ /// </summary>
+ /// <returns>Returns the value read.</returns>
+ /// <exception cref="EndOfStreamException">
+ /// The stream ends prematurely
+ /// </exception>
+ ushort ReadLEUshort()
+ {
+ int data1 = baseStream_.ReadByte();
+
+ if ( data1 < 0 ) {
+ throw new EndOfStreamException("End of stream");
+ }
+
+ int data2 = baseStream_.ReadByte();
+
+ if ( data2 < 0 ) {
+ throw new EndOfStreamException("End of stream");
+ }
+
+
+ return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));
+ }
+
+ /// <summary>
+ /// Read a uint in little endian byte order.
+ /// </summary>
+ /// <returns>Returns the value read.</returns>
+ /// <exception cref="IOException">
+ /// An i/o error occurs.
+ /// </exception>
+ /// <exception cref="System.IO.EndOfStreamException">
+ /// The file ends prematurely
+ /// </exception>
+ uint ReadLEUint()
+ {
+ return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));
+ }
+
+ ulong ReadLEUlong()
+ {
+ return ReadLEUint() | ((ulong)ReadLEUint() << 32);
+ }
+
+ #endregion
+ // NOTE this returns the offset of the first byte after the signature.
+ long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)
+ {
+ using ( ZipHelperStream les = new ZipHelperStream(baseStream_) ) {
+ return les.LocateBlockWithSignature(signature, endLocation, minimumBlockSize, maximumVariableData);
+ }
+ }
+
+ /// <summary>
+ /// Search for and read the central directory of a zip file filling the entries array.
+ /// </summary>
+ /// <exception cref="System.IO.IOException">
+ /// An i/o error occurs.
+ /// </exception>
+ /// <exception cref="ZipException">
+ /// The central directory is malformed or cannot be found
+ /// </exception>
+ void ReadEntries()
+ {
+ // Search for the End Of Central Directory. When a zip comment is
+ // present the directory will start earlier
+ //
+ // The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.
+ // This should be compatible with both SFX and ZIP files but has only been tested for Zip files
+ // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then
+ // this could be invalid.
+ // Could also speed this up by reading memory in larger blocks.
+
+ if (baseStream_.CanSeek == false) {
+ throw new ZipException("ZipFile stream must be seekable");
+ }
+
+ long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,
+ baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);
+
+ if (locatedEndOfCentralDir < 0) {
+ throw new ZipException("Cannot find central directory");
+ }
+
+ // Read end of central directory record
+ ushort thisDiskNumber = ReadLEUshort();
+ ushort startCentralDirDisk = ReadLEUshort();
+ ulong entriesForThisDisk = ReadLEUshort();
+ ulong entriesForWholeCentralDir = ReadLEUshort();
+ ulong centralDirSize = ReadLEUint();
+ long offsetOfCentralDir = ReadLEUint();
+ uint commentSize = ReadLEUshort();
+
+ if ( commentSize > 0 ) {
+ byte[] comment = new byte[commentSize];
+
+ StreamUtils.ReadFully(baseStream_, comment);
+ comment_ = ZipConstants.ConvertToString(comment);
+ }
+ else {
+ comment_ = string.Empty;
+ }
+
+ bool isZip64 = false;
+
+ // Check if zip64 header information is required.
+ if ( (thisDiskNumber == 0xffff) ||
+ (startCentralDirDisk == 0xffff) ||
+ (entriesForThisDisk == 0xffff) ||
+ (entriesForWholeCentralDir == 0xffff) ||
+ (centralDirSize == 0xffffffff) ||
+ (offsetOfCentralDir == 0xffffffff) ) {
+ isZip64 = true;
+
+ long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 0x1000);
+ if ( offset < 0 ) {
+ throw new ZipException("Cannot find Zip64 locator");
+ }
+
+ // number of the disk with the start of the zip64 end of central directory 4 bytes
+ // relative offset of the zip64 end of central directory record 8 bytes
+ // total number of disks 4 bytes
+ ReadLEUint(); // startDisk64 is not currently used
+ ulong offset64 = ReadLEUlong();
+ uint totalDisks = ReadLEUint();
+
+ baseStream_.Position = (long)offset64;
+ long sig64 = ReadLEUint();
+
+ if ( sig64 != ZipConstants.Zip64CentralFileHeaderSignature ) {
+ throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));
+ }
+
+ // NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12.
+ ulong recordSize = ( ulong )ReadLEUlong();
+ int versionMadeBy = ReadLEUshort();
+ int versionToExtract = ReadLEUshort();
+ uint thisDisk = ReadLEUint();
+ uint centralDirDisk = ReadLEUint();
+ entriesForThisDisk = ReadLEUlong();
+ entriesForWholeCentralDir = ReadLEUlong();
+ centralDirSize = ReadLEUlong();
+ offsetOfCentralDir = (long)ReadLEUlong();
+
+ // NOTE: zip64 extensible data sector (variable size) is ignored.
+ }
+
+ entries_ = new ZipEntry[entriesForThisDisk];
+
+ // SFX/embedded support, find the offset of the first entry vis the start of the stream
+ // This applies to Zip files that are appended to the end of an SFX stub.
+ // Or are appended as a resource to an executable.
+ // Zip files created by some archivers have the offsets altered to reflect the true offsets
+ // and so dont require any adjustment here...
+ // TODO: Difficulty with Zip64 and SFX offset handling needs resolution - maths?
+ if ( !isZip64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize)) ) {
+ offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir);
+ if (offsetOfFirstEntry <= 0) {
+ throw new ZipException("Invalid embedded zip archive");
+ }
+ }
+
+ baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);
+
+ for (ulong i = 0; i < entriesForThisDisk; i++) {
+ if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {
+ throw new ZipException("Wrong Central Directory signature");
+ }
+
+ int versionMadeBy = ReadLEUshort();
+ int versionToExtract = ReadLEUshort();
+ int bitFlags = ReadLEUshort();
+ int method = ReadLEUshort();
+ uint dostime = ReadLEUint();
+ uint crc = ReadLEUint();
+ long csize = (long)ReadLEUint();
+ long size = (long)ReadLEUint();
+ int nameLen = ReadLEUshort();
+ int extraLen = ReadLEUshort();
+ int commentLen = ReadLEUshort();
+
+ int diskStartNo = ReadLEUshort(); // Not currently used
+ int internalAttributes = ReadLEUshort(); // Not currently used
+
+ uint externalAttributes = ReadLEUint();
+ long offset = ReadLEUint();
+
+ byte[] buffer = new byte[Math.Max(nameLen, commentLen)];
+
+ StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);
+ string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);
+
+ ZipEntry entry = new ZipEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method);
+ entry.Crc = crc & 0xffffffffL;
+ entry.Size = size & 0xffffffffL;
+ entry.CompressedSize = csize & 0xffffffffL;
+ entry.Flags = bitFlags;
+ entry.DosTime = (uint)dostime;
+ entry.ZipFileIndex = (long)i;
+ entry.Offset = offset;
+ entry.ExternalFileAttributes = (int)externalAttributes;
+
+ if ((bitFlags & 8) == 0) {
+ entry.CryptoCheckValue = (byte)(crc >> 24);
+ }
+ else {
+ entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);
+ }
+
+ if (extraLen > 0) {
+ byte[] extra = new byte[extraLen];
+ StreamUtils.ReadFully(baseStream_, extra);
+ entry.ExtraData = extra;
+ }
+
+ entry.ProcessExtraData(false);
+
+ if (commentLen > 0) {
+ StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);
+ entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);
+ }
+
+ entries_[i] = entry;
+ }
+ }
+
+ /// <summary>
+ /// Locate the data for a given entry.
+ /// </summary>
+ /// <returns>
+ /// The start offset of the data.
+ /// </returns>
+ /// <exception cref="System.IO.EndOfStreamException">
+ /// The stream ends prematurely
+ /// </exception>
+ /// <exception cref="ZipException">
+ /// The local header signature is invalid, the entry and central header file name lengths are different
+ /// or the local and entry compression methods dont match
+ /// </exception>
+ long LocateEntry(ZipEntry entry)
+ {
+ return TestLocalHeader(entry, HeaderTest.Extract);
+ }
+
+#if !NETCF_1_0
+ Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
+ {
+ CryptoStream result = null;
+
+ if ( (entry.Version < ZipConstants.VersionStrongEncryption)
+ || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
+ PkzipClassicManaged classicManaged = new PkzipClassicManaged();
+
+ OnKeysRequired(entry.Name);
+ if (HaveKeys == false) {
+ throw new ZipException("No password available for encrypted stream");
+ }
+
+ result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, null), CryptoStreamMode.Read);
+ CheckClassicPassword(result, entry);
+ }
+ else {
+ throw new ZipException("Decryption method not supported");
+ }
+
+ return result;
+ }
+
+ Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
+ {
+ CryptoStream result = null;
+ if ( (entry.Version < ZipConstants.VersionStrongEncryption)
+ || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
+ PkzipClassicManaged classicManaged = new PkzipClassicManaged();
+
+ OnKeysRequired(entry.Name);
+ if (HaveKeys == false) {
+ throw new ZipException("No password available for encrypted stream");
+ }
+
+ // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream
+ // which doesnt do this.
+ result = new CryptoStream(new UncompressedStream(baseStream),
+ classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);
+
+ if ( (entry.Crc < 0) || (entry.Flags & 8) != 0) {
+ WriteEncryptionHeader(result, entry.DosTime << 16);
+ }
+ else {
+ WriteEncryptionHeader(result, entry.Crc);
+ }
+ }
+ return result;
+ }
+
+ static void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)
+ {
+ byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];
+ StreamUtils.ReadFully(classicCryptoStream, cryptbuffer);
+ if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) {
+ throw new ZipException("Invalid password");
+ }
+ }
+#endif
+
+ static void WriteEncryptionHeader(Stream stream, long crcValue)
+ {
+ byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize];
+ Random rnd = new Random();
+ rnd.NextBytes(cryptBuffer);
+ cryptBuffer[11] = (byte)(crcValue >> 24);
+ stream.Write(cryptBuffer, 0, cryptBuffer.Length);
+ }
+
+ #endregion
+
+ #region Instance Fields
+ bool isDisposed_;
+ string name_;
+ string comment_;
+ Stream baseStream_;
+ bool isStreamOwner;
+ long offsetOfFirstEntry;
+ ZipEntry[] entries_;
+ byte[] key;
+ bool isNewArchive_;
+
+ // Default is dynamic which is not backwards compatible and can cause problems
+ // with XP's built in compression which cant read Zip64 archives.
+ // However it does avoid the situation were a large file is added and cannot be completed correctly.
+ UseZip64 useZip64_ = UseZip64.Dynamic ;
+
+ #region Zip Update Instance Fields
+ List<ZipUpdate> updates_;
+ long updateCount_; // Count is managed manually as updates_ can contain nulls!
+ Dictionary<string, int> updateIndex_;
+ IArchiveStorage archiveStorage_;
+ IDynamicDataSource updateDataSource_;
+ bool contentsEdited_;
+ int bufferSize_ = DefaultBufferSize;
+ byte[] copyBuffer_;
+ ZipString newComment_;
+ bool commentEdited_;
+ IEntryFactory updateEntryFactory_ = new ZipEntryFactory();
+ string tempDirectory_ = string.Empty;
+ #endregion
+ #endregion
+
+ #region Support Classes
+ /// <summary>
+ /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.
+ /// </summary>
+ class ZipString
+ {
+ #region Constructors
+ /// <summary>
+ /// Initialise a <see cref="ZipString"/> with a string.
+ /// </summary>
+ /// <param name="comment">The textual string form.</param>
+ public ZipString(string comment)
+ {
+ comment_ = comment;
+ isSourceString_ = true;
+ }
+
+ /// <summary>
+ /// Initialise a <see cref="ZipString"/> using a string in its binary 'raw' form.
+ /// </summary>
+ /// <param name="rawString"></param>
+ public ZipString(byte[] rawString)
+ {
+ rawComment_ = rawString;
+ }
+ #endregion
+
+ /// <summary>
+ /// Get a value indicating the original source of data for this instance.
+ /// True if the source was a string; false if the source was binary data.
+ /// </summary>
+ public bool IsSourceString
+ {
+ get { return isSourceString_; }
+ }
+
+ /// <summary>
+ /// Get the length of the comment when represented as raw bytes.
+ /// </summary>
+ public int RawLength
+ {
+ get {
+ MakeBytesAvailable();
+ return rawComment_.Length;
+ }
+ }
+
+ /// <summary>
+ /// Get the comment in its 'raw' form as plain bytes.
+ /// </summary>
+ public byte[] RawComment
+ {
+ get {
+ MakeBytesAvailable();
+ return (byte[])rawComment_.Clone();
+ }
+ }
+
+ /// <summary>
+ /// Reset the comment to its initial state.
+ /// </summary>
+ public void Reset()
+ {
+ if ( isSourceString_ ) {
+ rawComment_ = null;
+ }
+ else {
+ comment_ = null;
+ }
+ }
+
+ void MakeTextAvailable()
+ {
+ if ( comment_ == null ) {
+ comment_ = ZipConstants.ConvertToString(rawComment_);
+ }
+ }
+
+ void MakeBytesAvailable()
+ {
+ if ( rawComment_ == null ) {
+ rawComment_ = ZipConstants.ConvertToArray(comment_);
+ }
+ }
+
+ /// <summary>
+ /// Implicit conversion of comment to a string.
+ /// </summary>
+ /// <param name="zipString">The <see cref="ZipString"/> to convert to a string.</param>
+ /// <returns>The textual equivalent for the input value.</returns>
+ static public implicit operator string(ZipString zipString)
+ {
+ zipString.MakeTextAvailable();
+ return zipString.comment_;
+ }
+
+ #region Instance Fields
+ string comment_;
+ byte[] rawComment_;
+ bool isSourceString_;
+ #endregion
+ }
+
+ /// <summary>
+ /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>
+ /// </summary>
+ class ZipEntryEnumerator : IEnumerator
+ {
+ #region Constructors
+ public ZipEntryEnumerator(ZipEntry[] entries)
+ {
+ array = entries;
+ }
+
+ #endregion
+ #region IEnumerator Members
+ public object Current
+ {
+ get {
+ return array[index];
+ }
+ }
+
+ public void Reset()
+ {
+ index = -1;
+ }
+
+ public bool MoveNext()
+ {
+ return (++index < array.Length);
+ }
+ #endregion
+ #region Instance Fields
+ ZipEntry[] array;
+ int index = -1;
+ #endregion
+ }
+
+ /// <summary>
+ /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data
+ /// to and flush, but cannot read, seek or do anything else to.
+ /// </summary>
+ class UncompressedStream : Stream
+ {
+ #region Constructors
+ public UncompressedStream(Stream baseStream)
+ {
+ baseStream_ = baseStream;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Close this stream instance.
+ /// </summary>
+ public override void Close()
+ {
+ // Do nothing
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the current stream supports reading.
+ /// </summary>
+ public override bool CanRead
+ {
+ get {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Write any buffered data to underlying storage.
+ /// </summary>
+ public override void Flush()
+ {
+ baseStream_.Flush();
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the current stream supports writing.
+ /// </summary>
+ public override bool CanWrite
+ {
+ get {
+ return baseStream_.CanWrite;
+ }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the current stream supports seeking.
+ /// </summary>
+ public override bool CanSeek
+ {
+ get {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Get the length in bytes of the stream.
+ /// </summary>
+ public override long Length
+ {
+ get {
+ return 0;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the position within the current stream.
+ /// </summary>
+ public override long Position
+ {
+ get {
+ return baseStream_.Position;
+ }
+
+ set
+ {
+ }
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ return 0;
+ }
+
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ return 0;
+ }
+
+ public override void SetLength(long value)
+ {
+ }
+
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ baseStream_.Write(buffer, offset, count);
+ }
+
+ #region Instance Fields
+ Stream baseStream_;
+ #endregion
+ }
+
+ /// <summary>
+ /// A <see cref="PartialInputStream"/> is an <see cref="InflaterInputStream"/>
+ /// whose data is only a part or subsection of a file.
+ /// </summary>
+ class PartialInputStream : InflaterInputStream
+ {
+ #region Constructors
+ /// <summary>
+ /// Initialise a new instance of the <see cref="PartialInputStream"/> class.
+ /// </summary>
+ /// <param name="baseStream">The underlying stream to use for IO.</param>
+ /// <param name="start">The start of the partial data.</param>
+ /// <param name="length">The length of the partial data.</param>
+ public PartialInputStream(Stream baseStream, long start, long length)
+ : base(baseStream)
+ {
+ baseStream_ = baseStream;
+ filepos_ = start;
+ end_ = start + length;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Skip the specified number of input bytes.
+ /// </summary>
+ /// <param name="count">The maximum number of input bytes to skip.</param>
+ /// <returns>The actuial number of input bytes skipped.</returns>
+ public long SkipBytes(long count)
+ {
+ if (count < 0) {
+#if NETCF_1_0
+ throw new ArgumentOutOfRangeException("count");
+#else
+ throw new ArgumentOutOfRangeException("count", "is less than zero");
+#endif
+ }
+
+ if (count > end_ - filepos_) {
+ count = end_ - filepos_;
+ }
+
+ filepos_ += count;
+ return count;
+ }
+
+ public override int Available
+ {
+ get {
+ long amount = end_ - filepos_;
+ if (amount > int.MaxValue) {
+ return int.MaxValue;
+ }
+
+ return (int) amount;
+ }
+ }
+
+ /// <summary>
+ /// Read a byte from this stream.
+ /// </summary>
+ /// <returns>Returns the byte read or -1 on end of stream.</returns>
+ public override int ReadByte()
+ {
+ if (filepos_ == end_) {
+ // -1 is the correct value at end of stream.
+ return -1;
+ }
+
+ lock( baseStream_ ) {
+ baseStream_.Seek(filepos_++, SeekOrigin.Begin);
+ return baseStream_.ReadByte();
+ }
+ }
+
+ /// <summary>
+ /// Close this <see cref="PartialInputStream">partial input stream</see>.
+ /// </summary>
+ /// <remarks>
+ /// The underlying stream is not closed. Close the parent ZipFile class to do that.
+ /// </remarks>
+ public override void Close()
+ {
+ // Do nothing at all!
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ if (count > end_ - filepos_) {
+ count = (int) (end_ - filepos_);
+ if (count == 0) {
+ return 0;
+ }
+ }
+
+ lock(baseStream_) {
+ baseStream_.Seek(filepos_, SeekOrigin.Begin);
+ int readCount = baseStream_.Read(buffer, offset, count);
+ if (readCount > 0) {
+ filepos_ += readCount;
+ }
+ return readCount;
+ }
+ }
+
+ #region Instance Fields
+ Stream baseStream_;
+ long filepos_;
+ long end_;
+ #endregion
+ }
+ #endregion
+ }
+
+ /// <summary>
+ /// Provides a static way to obtain a source of data for an entry.
+ /// </summary>
+ public interface IStaticDataSource
+ {
+ /// <summary>
+ /// Get a source of data by creating a new stream.
+ /// </summary>
+ /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>
+ /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>
+ Stream GetSource();
+ }
+
+ /// <summary>
+ /// Represents a source of data that can dynamically provide
+ /// multiple <see cref="Stream">data sources</see> based on the parameters passed.
+ /// </summary>
+ public interface IDynamicDataSource
+ {
+ /// <summary>
+ /// Get a data source.
+ /// </summary>
+ /// <param name="entry">The <see cref="ZipEntry"/> to get a source for.</param>
+ /// <param name="name">The name for data if known.</param>
+ /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>
+ /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>
+ Stream GetSource(ZipEntry entry, string name);
+ }
+
+ /// <summary>
+ /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.
+ /// </summary>
+ class StaticDiskDataSource : IStaticDataSource
+ {
+ /// <summary>
+ /// Initialise a new instnace of <see cref="StaticDiskDataSource"/>
+ /// </summary>
+ /// <param name="fileName">The name of the file to obtain data from.</param>
+ public StaticDiskDataSource(string fileName)
+ {
+ fileName_ = fileName;
+ }
+
+ #region IDataSource Members
+
+ /// <summary>
+ /// Get a <see cref="Stream"/> providing data.
+ /// </summary>
+ /// <returns>Returns a <see cref="Stream"/> provising data.</returns>
+ public Stream GetSource()
+ {
+ return File.OpenRead(fileName_);
+ }
+
+ #endregion
+ #region Instance Fields
+ string fileName_;
+ #endregion
+ }
+
+ /// <summary>
+ /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.
+ /// </summary>
+ class DynamicDiskDataSource : IDynamicDataSource
+ {
+ /// <summary>
+ /// Initialise a default instance of <see cref="DynamicDiskDataSource"/>.
+ /// </summary>
+ public DynamicDiskDataSource()
+ {
+ }
+
+ #region IDataSource Members
+ /// <summary>
+ /// Get a <see cref="Stream"/> providing data for an entry.
+ /// </summary>
+ /// <param name="entry">The entry to provide data for.</param>
+ /// <param name="name">The file name for data if known.</param>
+ /// <returns>Returns a stream providing data; or null if not available</returns>
+ public Stream GetSource(ZipEntry entry, string name)
+ {
+ Stream result = null;
+
+ if ( name != null ) {
+ result = File.OpenRead(name);
+ }
+
+ return result;
+ }
+
+ #endregion
+ }
+
+ /// <summary>
+ /// Defines facilities for data storage when updating Zip Archives.
+ /// </summary>
+ public interface IArchiveStorage
+ {
+ /// <summary>
+ /// Get the <see cref="FileUpdateMode"/> to apply during updates.
+ /// </summary>
+ FileUpdateMode UpdateMode { get; }
+
+ /// <summary>
+ /// Get an empty <see cref="Stream"/> that can be used for temporary output.
+ /// </summary>
+ /// <returns>Returns a temporary output <see cref="Stream"/></returns>
+ /// <seealso cref="ConvertTemporaryToFinal"></seealso>
+ Stream GetTemporaryOutput();
+
+ /// <summary>
+ /// Convert a temporary output stream to a final stream.
+ /// </summary>
+ /// <returns>The resulting final <see cref="Stream"/></returns>
+ /// <seealso cref="GetTemporaryOutput"/>
+ Stream ConvertTemporaryToFinal();
+
+ /// <summary>
+ /// Make a temporary copy of the original stream.
+ /// </summary>
+ /// <param name="stream">The <see cref="Stream"/> to copy.</param>
+ /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
+ Stream MakeTemporaryCopy(Stream stream);
+
+ /// <summary>
+ /// Return a stream suitable for performing direct updates on the original source.
+ /// </summary>
+ /// <param name="stream">The current stream.</param>
+ /// <returns>Returns a stream suitable for direct updating.</returns>
+ /// <remarks>This may be the current stream passed.</remarks>
+ Stream OpenForDirectUpdate(Stream stream);
+
+ /// <summary>
+ /// Dispose of this instance.
+ /// </summary>
+ void Dispose();
+ }
+
+ /// <summary>
+ /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.
+ /// </summary>
+ abstract public class BaseArchiveStorage : IArchiveStorage
+ {
+ #region Constructors
+ /// <summary>
+ /// Initializes a new instance of the <see cref="BaseArchiveStorage"/> class.
+ /// </summary>
+ /// <param name="updateMode">The update mode.</param>
+ public BaseArchiveStorage(FileUpdateMode updateMode)
+ {
+ updateMode_ = updateMode;
+ }
+ #endregion
+
+ #region IArchiveStorage Members
+
+ /// <summary>
+ /// Gets a temporary output <see cref="Stream"/>
+ /// </summary>
+ /// <returns>Returns the temporary output stream.</returns>
+ /// <seealso cref="ConvertTemporaryToFinal"></seealso>
+ public abstract Stream GetTemporaryOutput();
+
+ /// <summary>
+ /// Converts the temporary <see cref="Stream"/> to its final form.
+ /// </summary>
+ /// <returns>Returns a <see cref="Stream"/> that can be used to read
+ /// the final storage for the archive.</returns>
+ /// <seealso cref="GetTemporaryOutput"/>
+ public abstract Stream ConvertTemporaryToFinal();
+
+ /// <summary>
+ /// Make a temporary copy of a <see cref="Stream"/>.
+ /// </summary>
+ /// <param name="stream">The <see cref="Stream"/> to make a copy of.</param>
+ /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
+ public abstract Stream MakeTemporaryCopy(Stream stream);
+
+ /// <summary>
+ /// Return a stream suitable for performing direct updates on the original source.
+ /// </summary>
+ /// <param name="stream">The <see cref="Stream"/> to open for direct update.</param>
+ /// <returns>Returns a stream suitable for direct updating.</returns>
+ public abstract Stream OpenForDirectUpdate(Stream stream);
+
+ /// <summary>
+ /// Disposes this instance.
+ /// </summary>
+ public abstract void Dispose();
+
+ /// <summary>
+ /// Gets the update mode applicable.
+ /// </summary>
+ /// <value>The update mode.</value>
+ public FileUpdateMode UpdateMode
+ {
+ get {
+ return updateMode_;
+ }
+ }
+
+ #endregion
+
+ #region Instance Fields
+ FileUpdateMode updateMode_;
+ #endregion
+ }
+
+ /// <summary>
+ /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.
+ /// </summary>
+ public class DiskArchiveStorage : BaseArchiveStorage
+ {
+ #region Constructors
+ /// <summary>
+ /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.
+ /// </summary>
+ /// <param name="file">The file.</param>
+ /// <param name="updateMode">The update mode.</param>
+ public DiskArchiveStorage(ZipFile file, FileUpdateMode updateMode)
+ : base(updateMode)
+ {
+ if ( file.Name == null ) {
+ throw new ZipException("Cant handle non file archives");
+ }
+
+ fileName_ = file.Name;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.
+ /// </summary>
+ /// <param name="file">The file.</param>
+ public DiskArchiveStorage(ZipFile file)
+ : this(file, FileUpdateMode.Safe)
+ {
+ }
+ #endregion
+
+ #region IArchiveStorage Members
+
+ /// <summary>
+ /// Gets a temporary output <see cref="Stream"/> for performing updates on.
+ /// </summary>
+ /// <returns>Returns the temporary output stream.</returns>
+ public override Stream GetTemporaryOutput()
+ {
+ if ( temporaryName_ != null ) {
+ temporaryName_ = GetTempFileName(temporaryName_, true);
+ temporaryStream_ = File.OpenWrite(temporaryName_);
+ }
+ else {
+ // Determine where to place files based on internal strategy.
+ // Currently this is always done in system temp directory.
+ temporaryName_ = Path.GetTempFileName();
+ temporaryStream_ = File.OpenWrite(temporaryName_);
+ }
+
+ return temporaryStream_;
+ }
+
+ /// <summary>
+ /// Converts a temporary <see cref="Stream"/> to its final form.
+ /// </summary>
+ /// <returns>Returns a <see cref="Stream"/> that can be used to read
+ /// the final storage for the archive.</returns>
+ public override Stream ConvertTemporaryToFinal()
+ {
+ if ( temporaryStream_ == null ) {
+ throw new ZipException("No temporary stream has been created");
+ }
+
+ Stream result = null;
+
+ string moveTempName = GetTempFileName(fileName_, false);
+ bool newFileCreated = false;
+
+ try {
+ temporaryStream_.Close();
+ File.Move(fileName_, moveTempName);
+ File.Move(temporaryName_, fileName_);
+ newFileCreated = true;
+ File.Delete(moveTempName);
+
+ result = File.OpenRead(fileName_);
+ }
+ catch(Exception) {
+ result = null;
+
+ // Try to roll back changes...
+ if ( !newFileCreated ) {
+ File.Move(moveTempName, fileName_);
+ File.Delete(temporaryName_);
+ }
+
+ throw;
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Make a temporary copy of a stream.
+ /// </summary>
+ /// <param name="stream">The <see cref="Stream"/> to copy.</param>
+ /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
+ public override Stream MakeTemporaryCopy(Stream stream)
+ {
+ stream.Close();
+
+ temporaryName_ = GetTempFileName(fileName_, true);
+ File.Copy(fileName_, temporaryName_, true);
+
+ temporaryStream_ = new FileStream(temporaryName_,
+ FileMode.Open,
+ FileAccess.ReadWrite);
+ return temporaryStream_;
+ }
+
+ /// <summary>
+ /// Return a stream suitable for performing direct updates on the original source.
+ /// </summary>
+ /// <param name="current">The current stream.</param>
+ /// <returns>Returns a stream suitable for direct updating.</returns>
+ /// <remarks>If the <paramref name="current"/> stream is not null this is used as is.</remarks>
+ public override Stream OpenForDirectUpdate(Stream current)
+ {
+ Stream result;
+ if ((current == null) || !current.CanWrite)
+ {
+ if (current != null) {
+ current.Close();
+ }
+
+ result = new FileStream(fileName_,
+ FileMode.Open,
+ FileAccess.ReadWrite);
+ }
+ else
+ {
+ result = current;
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Disposes this instance.
+ /// </summary>
+ public override void Dispose()
+ {
+ if ( temporaryStream_ != null ) {
+ temporaryStream_.Close();
+ }
+ }
+
+ #endregion
+
+ #region Internal routines
+ string GetTempFileName(string original, bool makeTempFile)
+ {
+ string result = null;
+
+ if ( original == null ) {
+ result = Path.GetTempFileName();
+ }
+ else {
+ int counter = 0;
+ int suffixSeed = DateTime.Now.Second;
+
+ while ( result == null ) {
+ counter += 1;
+ string newName = string.Format("{0}.{1}{2}.tmp", original, suffixSeed, counter);
+ if ( !File.Exists(newName) ) {
+ if ( makeTempFile) {
+ try {
+ // Try and create the file.
+ using ( FileStream stream = File.Create(newName) ) {
+ }
+ result = newName;
+ }
+ catch {
+ suffixSeed = DateTime.Now.Second;
+ }
+ }
+ else {
+ result = newName;
+ }
+ }
+ }
+ }
+ return result;
+ }
+ #endregion
+
+ #region Instance Fields
+ Stream temporaryStream_;
+ string fileName_;
+ string temporaryName_;
+ #endregion
+ }
+
+ /// <summary>
+ /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.
+ /// </summary>
+ public class MemoryArchiveStorage : BaseArchiveStorage
+ {
+ #region Constructors
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.
+ /// </summary>
+ public MemoryArchiveStorage()
+ : base(FileUpdateMode.Direct)
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.
+ /// </summary>
+ /// <param name="updateMode">The <see cref="FileUpdateMode"/> to use</param>
+ /// <remarks>This constructor is for testing as memory streams dont really require safe mode.</remarks>
+ public MemoryArchiveStorage(FileUpdateMode updateMode)
+ : base(updateMode)
+ {
+ }
+
+ #endregion
+
+ #region Properties
+ /// <summary>
+ /// Get the stream returned by <see cref="ConvertTemporaryToFinal"/> if this was in fact called.
+ /// </summary>
+ public MemoryStream FinalStream
+ {
+ get { return finalStream_; }
+ }
+
+ #endregion
+
+ #region IArchiveStorage Members
+
+ /// <summary>
+ /// Gets the temporary output <see cref="Stream"/>
+ /// </summary>
+ /// <returns>Returns the temporary output stream.</returns>
+ public override Stream GetTemporaryOutput()
+ {
+ temporaryStream_ = new MemoryStream();
+ return temporaryStream_;
+ }
+
+ /// <summary>
+ /// Converts the temporary <see cref="Stream"/> to its final form.
+ /// </summary>
+ /// <returns>Returns a <see cref="Stream"/> that can be used to read
+ /// the final storage for the archive.</returns>
+ public override Stream ConvertTemporaryToFinal()
+ {
+ if ( temporaryStream_ == null ) {
+ throw new ZipException("No temporary stream has been created");
+ }
+
+ finalStream_ = new MemoryStream(temporaryStream_.ToArray());
+ return finalStream_;
+ }
+
+ /// <summary>
+ /// Make a temporary copy of the original stream.
+ /// </summary>
+ /// <param name="stream">The <see cref="Stream"/> to copy.</param>
+ /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>
+ public override Stream MakeTemporaryCopy(Stream stream)
+ {
+ temporaryStream_ = new MemoryStream();
+ stream.Position = 0;
+ StreamUtils.Copy(stream, temporaryStream_, new byte[4096]);
+ return temporaryStream_;
+ }
+
+ /// <summary>
+ /// Return a stream suitable for performing direct updates on the original source.
+ /// </summary>
+ /// <param name="stream">The original source stream</param>
+ /// <returns>Returns a stream suitable for direct updating.</returns>
+ /// <remarks>If the <paramref name="stream"/> passed is not null this is used;
+ /// otherwise a new <see cref="MemoryStream"/> is returned.</remarks>
+ public override Stream OpenForDirectUpdate(Stream stream)
+ {
+ Stream result;
+ if ((stream == null) || !stream.CanWrite) {
+
+ result = new MemoryStream();
+
+ if (stream != null) {
+ stream.Position = 0;
+ StreamUtils.Copy(stream, result, new byte[4096]);
+
+ stream.Close();
+ }
+ }
+ else {
+ result = stream;
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Disposes this instance.
+ /// </summary>
+ public override void Dispose()
+ {
+ if ( temporaryStream_ != null ) {
+ temporaryStream_.Close();
+ }
+ }
+
+ #endregion
+
+ #region Instance Fields
+ MemoryStream temporaryStream_;
+ MemoryStream finalStream_;
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+// ZipHelperStream.cs
+//
+// Copyright 2006, 2007 John Reilly
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+using System.Text;
+using ICSharpCode.SharpZipLib.Silverlight.Zip;
+
+namespace ICSharpCode.SharpZipLib.Zip
+{
+
+ /// <summary>
+ /// Holds data pertinent to a data descriptor.
+ /// </summary>
+ public class DescriptorData
+ {
+ /// <summary>
+ /// Get /set the compressed size of data.
+ /// </summary>
+ public long CompressedSize
+ {
+ get { return compressedSize; }
+ set { compressedSize = value; }
+ }
+
+ /// <summary>
+ /// Get / set the uncompressed size of data
+ /// </summary>
+ public long Size
+ {
+ get { return size; }
+ set { size = value; }
+ }
+
+ /// <summary>
+ /// Get /set the crc value.
+ /// </summary>
+ public long Crc
+ {
+ get { return crc; }
+ set { crc = (value & 0xffffffff); }
+ }
+
+ #region Instance Fields
+ long size;
+ long compressedSize;
+ long crc;
+ #endregion
+ }
+
+ class EntryPatchData
+ {
+ public long SizePatchOffset
+ {
+ get { return sizePatchOffset_; }
+ set { sizePatchOffset_ = value; }
+ }
+
+ public long CrcPatchOffset
+ {
+ get { return crcPatchOffset_; }
+ set { crcPatchOffset_ = value; }
+ }
+
+ #region Instance Fields
+ long sizePatchOffset_;
+ long crcPatchOffset_;
+ #endregion
+ }
+
+ /// <summary>
+ /// This class assists with writing/reading from Zip files.
+ /// </summary>
+ internal class ZipHelperStream : Stream
+ {
+ #region Constructors
+ /// <summary>
+ /// Initialise an instance of this class.
+ /// </summary>
+ /// <param name="name">The name of the file to open.</param>
+ public ZipHelperStream(string name)
+ {
+ stream_ = new FileStream(name, FileMode.Open, FileAccess.ReadWrite);
+ isOwner_ = true;
+ }
+
+ /// <summary>
+ /// Initialise a new instance of <see cref="ZipHelperStream"/>.
+ /// </summary>
+ /// <param name="stream">The stream to use.</param>
+ public ZipHelperStream(Stream stream)
+ {
+ stream_ = stream;
+ }
+ #endregion
+
+ /// <summary>
+ /// Get / set a value indicating wether the the underlying stream is owned or not.
+ /// </summary>
+ /// <remarks>If the stream is owned it is closed when this instance is closed.</remarks>
+ public bool IsStreamOwner
+ {
+ get { return isOwner_; }
+ set { isOwner_ = value; }
+ }
+
+ #region Base Stream Methods
+ public override bool CanRead
+ {
+ get { return stream_.CanRead; }
+ }
+
+ public override bool CanSeek
+ {
+ get { return stream_.CanSeek; }
+ }
+
+ public override bool CanTimeout
+ {
+ get { return stream_.CanTimeout; }
+ }
+
+ public override long Length
+ {
+ get { return stream_.Length; }
+ }
+
+ public override long Position
+ {
+ get { return stream_.Position; }
+ set { stream_.Position = value; }
+ }
+
+ public override bool CanWrite
+ {
+ get { return stream_.CanWrite; }
+ }
+
+ public override void Flush()
+ {
+ stream_.Flush();
+ }
+
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ return stream_.Seek(offset, origin);
+ }
+
+ public override void SetLength(long value)
+ {
+ stream_.SetLength(value);
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ return stream_.Read(buffer, offset, count);
+ }
+
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ stream_.Write(buffer, offset, count);
+ }
+
+ /// <summary>
+ /// Close the stream.
+ /// </summary>
+ /// <remarks>
+ /// The underlying stream is closed only if <see cref="IsStreamOwner"/> is true.
+ /// </remarks>
+ override public void Close()
+ {
+ Stream toClose = stream_;
+ stream_ = null;
+ if (isOwner_ && (toClose != null))
+ {
+ isOwner_ = false;
+ toClose.Close();
+ }
+ }
+ #endregion
+
+ // Write the local file header
+ // TODO: ZipHelperStream.WriteLocalHeader is not yet used and needs checking for ZipFile and ZipOuptutStream usage
+ void WriteLocalHeader(ZipEntry entry, EntryPatchData patchData)
+ {
+ CompressionMethod method = entry.CompressionMethod;
+ bool headerInfoAvailable = true; // How to get this?
+ bool patchEntryHeader = false;
+
+ WriteLEInt(ZipConstants.LocalHeaderSignature);
+
+ WriteLEShort(entry.Version);
+ WriteLEShort(entry.Flags);
+ WriteLEShort((byte)method);
+ WriteLEInt((int)entry.DosTime);
+
+ if (headerInfoAvailable == true) {
+ WriteLEInt((int)entry.Crc);
+ if ( entry.LocalHeaderRequiresZip64 ) {
+ WriteLEInt(-1);
+ WriteLEInt(-1);
+ }
+ else {
+ WriteLEInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.CompressedSize);
+ WriteLEInt((int)entry.Size);
+ }
+ } else {
+ if (patchData != null) {
+ patchData.CrcPatchOffset = stream_.Position;
+ }
+ WriteLEInt(0); // Crc
+
+ if ( patchData != null ) {
+ patchData.SizePatchOffset = stream_.Position;
+ }
+
+ // For local header both sizes appear in Zip64 Extended Information
+ if ( entry.LocalHeaderRequiresZip64 && patchEntryHeader ) {
+ WriteLEInt(-1);
+ WriteLEInt(-1);
+ }
+ else {
+ WriteLEInt(0); // Compressed size
+ WriteLEInt(0); // Uncompressed size
+ }
+ }
+
+ byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
+
+ if (name.Length > 0xFFFF) {
+ throw new ZipException("Entry name too long.");
+ }
+
+ ZipExtraData ed = new ZipExtraData(entry.ExtraData);
+
+ if (entry.LocalHeaderRequiresZip64 && (headerInfoAvailable || patchEntryHeader)) {
+ ed.StartNewEntry();
+ if (headerInfoAvailable) {
+ ed.AddLeLong(entry.Size);
+ ed.AddLeLong(entry.CompressedSize);
+ }
+ else {
+ ed.AddLeLong(-1);
+ ed.AddLeLong(-1);
+ }
+ ed.AddNewEntry(1);
+
+ if ( !ed.Find(1) ) {
+ throw new ZipException("Internal error cant find extra data");
+ }
+
+ if ( patchData != null ) {
+ patchData.SizePatchOffset = ed.CurrentReadIndex;
+ }
+ }
+ else {
+ ed.Delete(1);
+ }
+
+ byte[] extra = ed.GetEntryData();
+
+ WriteLEShort(name.Length);
+ WriteLEShort(extra.Length);
+
+ if ( name.Length > 0 ) {
+ stream_.Write(name, 0, name.Length);
+ }
+
+ if ( entry.LocalHeaderRequiresZip64 && patchEntryHeader ) {
+ patchData.SizePatchOffset += stream_.Position;
+ }
+
+ if ( extra.Length > 0 ) {
+ stream_.Write(extra, 0, extra.Length);
+ }
+ }
+
+ /// <summary>
+ /// Locates a block with the desired <paramref name="signature"/>.
+ /// </summary>
+ /// <param name="signature">The signature to find.</param>
+ /// <param name="endLocation">Location, marking the end of block.</param>
+ /// <param name="minimumBlockSize">Minimum size of the block.</param>
+ /// <param name="maximumVariableData">The maximum variable data.</param>
+ /// <returns>Eeturns the offset of the first byte after the signature; -1 if not found</returns>
+ public long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)
+ {
+ long pos = endLocation - minimumBlockSize;
+ if ( pos < 0 ) {
+ return -1;
+ }
+
+ long giveUpMarker = Math.Max(pos - maximumVariableData, 0);
+
+ // TODO: This loop could be optimised for speed.
+ do {
+ if ( pos < giveUpMarker ) {
+ return -1;
+ }
+ Seek(pos--, SeekOrigin.Begin);
+ } while ( ReadLEInt() != signature );
+
+ return Position;
+ }
+
+ /// <summary>
+ /// Write Zip64 end of central directory records (File header and locator).
+ /// </summary>
+ /// <param name="noOfEntries">The number of entries in the central directory.</param>
+ /// <param name="sizeEntries">The size of entries in the central directory.</param>
+ /// <param name="centralDirOffset">The offset of the dentral directory.</param>
+ public void WriteZip64EndOfCentralDirectory(long noOfEntries, long sizeEntries, long centralDirOffset)
+ {
+ long centralSignatureOffset = stream_.Position;
+ WriteLEInt(ZipConstants.Zip64CentralFileHeaderSignature);
+ WriteLELong(44); // Size of this record (total size of remaining fields in header or full size - 12)
+ WriteLEShort(ZipConstants.VersionMadeBy); // Version made by
+ WriteLEShort(ZipConstants.VersionZip64); // Version to extract
+ WriteLEInt(0); // Number of this disk
+ WriteLEInt(0); // number of the disk with the start of the central directory
+ WriteLELong(noOfEntries); // No of entries on this disk
+ WriteLELong(noOfEntries); // Total No of entries in central directory
+ WriteLELong(sizeEntries); // Size of the central directory
+ WriteLELong(centralDirOffset); // offset of start of central directory
+ // zip64 extensible data sector not catered for here (variable size)
+
+ // Write the Zip64 end of central directory locator
+ WriteLEInt(ZipConstants.Zip64CentralDirLocatorSignature);
+
+ // no of the disk with the start of the zip64 end of central directory
+ WriteLEInt(0);
+
+ // relative offset of the zip64 end of central directory record
+ WriteLELong(centralSignatureOffset);
+
+ // total number of disks
+ WriteLEInt(1);
+ }
+
+ /// <summary>
+ /// Write the required records to end the central directory.
+ /// </summary>
+ /// <param name="noOfEntries">The number of entries in the directory.</param>
+ /// <param name="sizeEntries">The size of the entries in the directory.</param>
+ /// <param name="startOfCentralDirectory">The start of the central directory.</param>
+ /// <param name="comment">The archive comment. (This can be null).</param>
+ public void WriteEndOfCentralDirectory(long noOfEntries, long sizeEntries,
+ long startOfCentralDirectory, byte[] comment)
+ {
+
+ if ( (noOfEntries >= 0xffff) ||
+ (startOfCentralDirectory >= 0xffffffff) ||
+ (sizeEntries >= 0xffffffff) ) {
+ WriteZip64EndOfCentralDirectory(noOfEntries, sizeEntries, startOfCentralDirectory);
+ }
+
+ WriteLEInt(ZipConstants.EndOfCentralDirectorySignature);
+
+ // TODO: ZipFile Multi disk handling not done
+ WriteLEShort(0); // number of this disk
+ WriteLEShort(0); // no of disk with start of central dir
+
+
+ // Number of entries
+ if ( noOfEntries >= 0xffff ) {
+ WriteLEUshort(0xffff); // Zip64 marker
+ WriteLEUshort(0xffff);
+ }
+ else {
+ WriteLEShort(( short )noOfEntries); // entries in central dir for this disk
+ WriteLEShort(( short )noOfEntries); // total entries in central directory
+ }
+
+ // Size of the central directory
+ if ( sizeEntries >= 0xffffffff ) {
+ WriteLEUint(0xffffffff); // Zip64 marker
+ }
+ else {
+ WriteLEInt(( int )sizeEntries);
+ }
+
+
+ // offset of start of central directory
+ if ( startOfCentralDirectory >= 0xffffffff ) {
+ WriteLEUint(0xffffffff); // Zip64 marker
+ }
+ else {
+ WriteLEInt(( int )startOfCentralDirectory);
+ }
+
+ int commentLength = (comment != null) ? comment.Length : 0;
+
+ if ( commentLength > 0xffff ) {
+ throw new ZipException(string.Format("Comment length({0}) is too long can only be 64K", commentLength));
+ }
+
+ WriteLEShort(commentLength);
+
+ if ( commentLength > 0 ) {
+ Write(comment, 0, comment.Length);
+ }
+ }
+
+ #region LE value reading/writing
+ /// <summary>
+ /// Read an unsigned short in little endian byte order.
+ /// </summary>
+ /// <returns>Returns the value read.</returns>
+ /// <exception cref="IOException">
+ /// An i/o error occurs.
+ /// </exception>
+ /// <exception cref="EndOfStreamException">
+ /// The file ends prematurely
+ /// </exception>
+ public int ReadLEShort()
+ {
+ int byteValue1 = stream_.ReadByte();
+
+ if (byteValue1 < 0) {
+ throw new EndOfStreamException();
+ }
+
+ int byteValue2 = stream_.ReadByte();
+ if (byteValue2 < 0) {
+ throw new EndOfStreamException();
+ }
+
+ return byteValue1 | (byteValue2 << 8);
+ }
+
+ /// <summary>
+ /// Read an int in little endian byte order.
+ /// </summary>
+ /// <returns>Returns the value read.</returns>
+ /// <exception cref="IOException">
+ /// An i/o error occurs.
+ /// </exception>
+ /// <exception cref="System.IO.EndOfStreamException">
+ /// The file ends prematurely
+ /// </exception>
+ public int ReadLEInt()
+ {
+ return ReadLEShort() | (ReadLEShort() << 16);
+ }
+
+ /// <summary>
+ /// Read a long in little endian byte order.
+ /// </summary>
+ /// <returns>The value read.</returns>
+ public long ReadLELong()
+ {
+ return (uint)ReadLEInt() | ((long)ReadLEInt() << 32);
+ }
+
+ /// <summary>
+ /// Write an unsigned short in little endian byte order.
+ /// </summary>
+ /// <param name="value">The value to write.</param>
+ public void WriteLEShort(int value)
+ {
+ stream_.WriteByte(( byte )(value & 0xff));
+ stream_.WriteByte(( byte )((value >> 8) & 0xff));
+ }
+
+ /// <summary>
+ /// Write a ushort in little endian byte order.
+ /// </summary>
+ /// <param name="value">The value to write.</param>
+ public void WriteLEUshort(ushort value)
+ {
+ stream_.WriteByte(( byte )(value & 0xff));
+ stream_.WriteByte(( byte )(value >> 8));
+ }
+
+ /// <summary>
+ /// Write an int in little endian byte order.
+ /// </summary>
+ /// <param name="value">The value to write.</param>
+ public void WriteLEInt(int value)
+ {
+ WriteLEShort(value);
+ WriteLEShort(value >> 16);
+ }
+
+ /// <summary>
+ /// Write a uint in little endian byte order.
+ /// </summary>
+ /// <param name="value">The value to write.</param>
+ public void WriteLEUint(uint value)
+ {
+ WriteLEUshort(( ushort )(value & 0xffff));
+ WriteLEUshort(( ushort )(value >> 16));
+ }
+
+ /// <summary>
+ /// Write a long in little endian byte order.
+ /// </summary>
+ /// <param name="value">The value to write.</param>
+ public void WriteLELong(long value)
+ {
+ WriteLEInt(( int )value);
+ WriteLEInt(( int )(value >> 32));
+ }
+
+ /// <summary>
+ /// Write a ulong in little endian byte order.
+ /// </summary>
+ /// <param name="value">The value to write.</param>
+ public void WriteLEUlong(ulong value)
+ {
+ WriteLEUint(( uint )(value & 0xffffffff));
+ WriteLEUint(( uint )(value >> 32));
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Write a data descriptor.
+ /// </summary>
+ /// <param name="entry">The entry to write a descriptor for.</param>
+ /// <returns>Returns the number of descriptor bytes written.</returns>
+ public int WriteDataDescriptor(ZipEntry entry)
+ {
+ if (entry == null) {
+ throw new ArgumentNullException("entry");
+ }
+
+ int result=0;
+
+ // Add data descriptor if flagged as required
+ if ((entry.Flags & (int)GeneralBitFlags.Descriptor) != 0)
+ {
+ // The signature is not PKZIP originally but is now described as optional
+ // in the PKZIP Appnote documenting trhe format.
+ WriteLEInt(ZipConstants.DataDescriptorSignature);
+ WriteLEInt(unchecked((int)(entry.Crc)));
+
+ result+=8;
+
+ if (entry.LocalHeaderRequiresZip64)
+ {
+ WriteLELong(entry.CompressedSize);
+ WriteLELong(entry.Size);
+ result+=16;
+ }
+ else
+ {
+ WriteLEInt((int)entry.CompressedSize);
+ WriteLEInt((int)entry.Size);
+ result+=8;
+ }
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Read data descriptor at the end of compressed data.
+ /// </summary>
+ /// <param name="zip64">if set to <c>true</c> [zip64].</param>
+ /// <param name="data">The data to fill in.</param>
+ /// <returns>Returns the number of bytes read in the descriptor.</returns>
+ public void ReadDataDescriptor(bool zip64, DescriptorData data)
+ {
+ int intValue = ReadLEInt();
+
+ // In theory this may not be a descriptor according to PKZIP appnote.
+ // In practise its always there.
+ if (intValue != ZipConstants.DataDescriptorSignature) {
+ throw new ZipException("Data descriptor signature not found");
+ }
+
+ data.Crc = ReadLEInt();
+
+ if (zip64) {
+ data.CompressedSize = ReadLELong();
+ data.Size = ReadLELong();
+ }
+ else {
+ data.CompressedSize = ReadLEInt();
+ data.Size = ReadLEInt();
+ }
+ }
+
+ #region Instance Fields
+ bool isOwner_;
+ Stream stream_;
+ #endregion
+ }
+}
--- /dev/null
+// ZipInputStream.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+using ICSharpCode.SharpZipLib.Silverlight.Checksums;
+using ICSharpCode.SharpZipLib.Silverlight.Encryption;
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression;
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression.Streams;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip
+{
+ /// <summary>
+ /// This is an InflaterInputStream that reads the files baseInputStream an zip archive
+ /// one after another. It has a special method to get the zip entry of
+ /// the next file. The zip entry contains information about the file name
+ /// size, compressed size, Crc, etc.
+ /// It includes support for Stored and Deflated entries.
+ /// <br/>
+ /// <br/>Author of the original java version : Jochen Hoenicke
+ /// </summary>
+ ///
+ /// <example> This sample shows how to read a zip file
+ /// <code lang="C#">
+ /// using System;
+ /// using System.Text;
+ /// using System.IO;
+ ///
+ /// using ICSharpCode.SharpZipLib.Zip;
+ ///
+ /// class MainClass
+ /// {
+ /// public static void Main(string[] args)
+ /// {
+ /// using ( ZipInputStream s = new ZipInputStream(File.OpenRead(args[0]))) {
+ ///
+ /// ZipEntry theEntry;
+ /// while ((theEntry = s.GetNextEntry()) != null) {
+ /// int size = 2048;
+ /// byte[] data = new byte[2048];
+ ///
+ /// Console.Write("Show contents (y/n) ?");
+ /// if (Console.ReadLine() == "y") {
+ /// while (true) {
+ /// size = s.Read(data, 0, data.Length);
+ /// if (size > 0) {
+ /// Console.Write(new ASCIIEncoding().GetString(data, 0, size));
+ /// } else {
+ /// break;
+ /// }
+ /// }
+ /// }
+ /// }
+ /// }
+ /// }
+ /// }
+ /// </code>
+ /// </example>
+ public class ZipInputStream : InflaterInputStream
+ {
+ #region Instance Fields
+
+ // Delegate for reading bytes from a stream.
+
+ private Crc32 crc = new Crc32();
+ private ZipEntry entry;
+
+ private int flags;
+
+ /// <summary>
+ /// The current reader this instance.
+ /// </summary>
+ private ReaderDelegate internalReader;
+
+ private int method;
+
+ private string password;
+ private long size;
+
+ private delegate int ReaderDelegate(byte[] b, int offset, int length);
+
+ #endregion
+
+ #region Constructors
+
+ /// <summary>
+ /// Creates a new Zip input stream, for reading a zip archive.
+ /// </summary>
+ /// <param name="baseInputStream">The underlying <see cref="Stream"/> providing data.</param>
+ public ZipInputStream(Stream baseInputStream)
+ : base(baseInputStream, new Inflater(true))
+ {
+ internalReader = ReadingNotAvailable;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Optional password used for encryption when non-null
+ /// </summary>
+ /// <value>A password for all encrypted <see cref="ZipEntry">entries </see> in this <see cref="ZipInputStream"/></value>
+ public string Password
+ {
+ get { return password; }
+ set { password = value; }
+ }
+
+
+ /// <summary>
+ /// Gets a value indicating if there is a current entry and it can be decompressed
+ /// </summary>
+ /// <remarks>
+ /// The entry can only be decompressed if the library supports the zip features required to extract it.
+ /// See the <see cref="ZipEntry.Version">ZipEntry Version</see> property for more details.
+ /// </remarks>
+ public bool CanDecompressEntry
+ {
+ get { return (entry != null) && entry.CanDecompress; }
+ }
+
+ /// <summary>
+ /// Returns 1 if there is an entry available
+ /// Otherwise returns 0.
+ /// </summary>
+ public override int Available
+ {
+ get { return entry != null ? 1 : 0; }
+ }
+
+ /// <summary>
+ /// Returns the current size that can be read from the current entry if available
+ /// </summary>
+ /// <exception cref="ZipException">Thrown if the entry size is not known.</exception>
+ /// <exception cref="InvalidOperationException">Thrown if no entry is currently available.</exception>
+ public override long Length
+ {
+ get
+ {
+ if (entry != null)
+ {
+ if (entry.Size >= 0)
+ {
+ return entry.Size;
+ }
+ else
+ {
+ throw new ZipException("Length not available for the current entry");
+ }
+ }
+ else
+ {
+ throw new InvalidOperationException("No current entry");
+ }
+ }
+ }
+
+ /// <summary>
+ /// Advances to the next entry in the archive
+ /// </summary>
+ /// <returns>
+ /// The next <see cref="ZipEntry">entry</see> in the archive or null if there are no more entries.
+ /// </returns>
+ /// <remarks>
+ /// If the previous entry is still open <see cref="CloseEntry">CloseEntry</see> is called.
+ /// </remarks>
+ /// <exception cref="InvalidOperationException">
+ /// Input stream is closed
+ /// </exception>
+ /// <exception cref="ZipException">
+ /// Password is not set, password is invalid, compression method is invalid,
+ /// version required to extract is not supported
+ /// </exception>
+ public ZipEntry GetNextEntry()
+ {
+ if (crc == null)
+ {
+ throw new InvalidOperationException("Closed.");
+ }
+
+ if (entry != null)
+ {
+ CloseEntry();
+ }
+
+ var header = inputBuffer.ReadLeInt();
+
+ if (header == ZipConstants.CentralHeaderSignature ||
+ header == ZipConstants.EndOfCentralDirectorySignature ||
+ header == ZipConstants.CentralHeaderDigitalSignature ||
+ header == ZipConstants.ArchiveExtraDataSignature ||
+ header == ZipConstants.Zip64CentralFileHeaderSignature)
+ {
+ // No more individual entries exist
+ Close();
+ return null;
+ }
+
+ // -jr- 07-Dec-2003 Ignore spanning temporary signatures if found
+ // Spanning signature is same as descriptor signature and is untested as yet.
+ if ((header == ZipConstants.SpanningTempSignature) || (header == ZipConstants.SpanningSignature))
+ {
+ header = inputBuffer.ReadLeInt();
+ }
+
+ if (header != ZipConstants.LocalHeaderSignature)
+ {
+ throw new ZipException("Wrong Local header signature: 0x" + String.Format("{0:X}", header));
+ }
+
+ var versionRequiredToExtract = (short) inputBuffer.ReadLeShort();
+
+ flags = inputBuffer.ReadLeShort();
+ method = inputBuffer.ReadLeShort();
+ var dostime = (uint) inputBuffer.ReadLeInt();
+ var crc2 = inputBuffer.ReadLeInt();
+ csize = inputBuffer.ReadLeInt();
+ size = inputBuffer.ReadLeInt();
+ var nameLen = inputBuffer.ReadLeShort();
+ var extraLen = inputBuffer.ReadLeShort();
+
+ var isCrypted = (flags & 1) == 1;
+
+ var buffer = new byte[nameLen];
+ inputBuffer.ReadRawBuffer(buffer);
+
+ var name = ZipConstants.ConvertToStringExt(flags, buffer);
+
+ entry = new ZipEntry(name, versionRequiredToExtract);
+ entry.Flags = flags;
+
+ entry.CompressionMethod = (CompressionMethod) method;
+
+ if ((flags & 8) == 0)
+ {
+ entry.Crc = crc2 & 0xFFFFFFFFL;
+ entry.Size = size & 0xFFFFFFFFL;
+ entry.CompressedSize = csize & 0xFFFFFFFFL;
+
+ entry.CryptoCheckValue = (byte) ((crc2 >> 24) & 0xff);
+ }
+ else
+ {
+ // This allows for GNU, WinZip and possibly other archives, the PKZIP spec
+ // says these values are zero under these circumstances.
+ if (crc2 != 0)
+ {
+ entry.Crc = crc2 & 0xFFFFFFFFL;
+ }
+
+ if (size != 0)
+ {
+ entry.Size = size & 0xFFFFFFFFL;
+ }
+
+ if (csize != 0)
+ {
+ entry.CompressedSize = csize & 0xFFFFFFFFL;
+ }
+
+ entry.CryptoCheckValue = (byte) ((dostime >> 8) & 0xff);
+ }
+
+ entry.DosTime = dostime;
+
+ // If local header requires Zip64 is true then the extended header should contain
+ // both values.
+
+ // Handle extra data if present. This can set/alter some fields of the entry.
+ if (extraLen > 0)
+ {
+ var extra = new byte[extraLen];
+ inputBuffer.ReadRawBuffer(extra);
+ entry.ExtraData = extra;
+ }
+
+ entry.ProcessExtraData(true);
+ if (entry.CompressedSize >= 0)
+ {
+ csize = entry.CompressedSize;
+ }
+
+ if (entry.Size >= 0)
+ {
+ size = entry.Size;
+ }
+
+ if (method == (int) CompressionMethod.Stored &&
+ (!isCrypted && csize != size || (isCrypted && csize - ZipConstants.CryptoHeaderSize != size)))
+ {
+ throw new ZipException("Stored, but compressed != uncompressed");
+ }
+
+ // Determine how to handle reading of data if this is attempted.
+ if (entry.IsCompressionMethodSupported())
+ {
+ internalReader = InitialRead;
+ }
+ else
+ {
+ internalReader = ReadingNotSupported;
+ }
+
+ return entry;
+ }
+
+ /// <summary>
+ /// Read data descriptor at the end of compressed data.
+ /// </summary>
+ private void ReadDataDescriptor()
+ {
+ if (inputBuffer.ReadLeInt() != ZipConstants.DataDescriptorSignature)
+ {
+ throw new ZipException("Data descriptor signature not found");
+ }
+
+ entry.Crc = inputBuffer.ReadLeInt() & 0xFFFFFFFFL;
+
+ if (entry.LocalHeaderRequiresZip64)
+ {
+ csize = inputBuffer.ReadLeLong();
+ size = inputBuffer.ReadLeLong();
+ }
+ else
+ {
+ csize = inputBuffer.ReadLeInt();
+ size = inputBuffer.ReadLeInt();
+ }
+ entry.CompressedSize = csize;
+ entry.Size = size;
+ }
+
+ /// <summary>
+ /// Complete cleanup as the final part of closing.
+ /// </summary>
+ /// <param name="testCrc">True if the crc value should be tested</param>
+ private void CompleteCloseEntry(bool testCrc)
+ {
+ StopDecrypting();
+
+ if ((flags & 8) != 0)
+ {
+ ReadDataDescriptor();
+ }
+
+ size = 0;
+
+ if (testCrc &&
+ ((crc.Value & 0xFFFFFFFFL) != entry.Crc) && (entry.Crc != -1))
+ {
+ throw new ZipException("CRC mismatch");
+ }
+
+ crc.Reset();
+
+ if (method == (int) CompressionMethod.Deflated)
+ {
+ inf.Reset();
+ }
+ entry = null;
+ }
+
+ /// <summary>
+ /// Closes the current zip entry and moves to the next one.
+ /// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The stream is closed
+ /// </exception>
+ /// <exception cref="ZipException">
+ /// The Zip stream ends early
+ /// </exception>
+ public void CloseEntry()
+ {
+ if (crc == null)
+ {
+ throw new InvalidOperationException("Closed");
+ }
+
+ if (entry == null)
+ {
+ return;
+ }
+
+ if (method == (int) CompressionMethod.Deflated)
+ {
+ if ((flags & 8) != 0)
+ {
+ // We don't know how much we must skip, read until end.
+ var tmp = new byte[2048];
+
+ // Read will close this entry
+ while (Read(tmp, 0, tmp.Length) > 0)
+ {
+ }
+ return;
+ }
+
+ csize -= inf.TotalIn;
+ inputBuffer.Available += inf.RemainingInput;
+ }
+
+ if ((inputBuffer.Available > csize) && (csize >= 0))
+ {
+ inputBuffer.Available = (int) (inputBuffer.Available - csize);
+ }
+ else
+ {
+ csize -= inputBuffer.Available;
+ inputBuffer.Available = 0;
+ while (csize != 0)
+ {
+ var skipped = (int) base.Skip(csize & 0xFFFFFFFFL);
+
+ if (skipped <= 0)
+ {
+ throw new ZipException("Zip archive ends early.");
+ }
+
+ csize -= skipped;
+ }
+ }
+
+ CompleteCloseEntry(false);
+ }
+
+ /// <summary>
+ /// Reads a byte from the current zip entry.
+ /// </summary>
+ /// <returns>
+ /// The byte or -1 if end of stream is reached.
+ /// </returns>
+ public override int ReadByte()
+ {
+ var b = new byte[1];
+ if (Read(b, 0, 1) <= 0)
+ {
+ return -1;
+ }
+ return b[0] & 0xff;
+ }
+
+ /// <summary>
+ /// Handle attempts to read by throwing an <see cref="InvalidOperationException"/>.
+ /// </summary>
+ /// <param name="destination">The destination array to store data in.</param>
+ /// <param name="offset">The offset at which data read should be stored.</param>
+ /// <param name="count">The maximum number of bytes to read.</param>
+ /// <returns>Returns the number of bytes actually read.</returns>
+ private int ReadingNotAvailable(byte[] destination, int offset, int count)
+ {
+ throw new InvalidOperationException("Unable to read from this stream");
+ }
+
+ /// <summary>
+ /// Handle attempts to read from this entry by throwing an exception
+ /// </summary>
+ private int ReadingNotSupported(byte[] destination, int offset, int count)
+ {
+ throw new ZipException("The compression method for this entry is not supported");
+ }
+
+ /// <summary>
+ /// Perform the initial read on an entry which may include
+ /// reading encryption headers and setting up inflation.
+ /// </summary>
+ /// <param name="destination">The destination to fill with data read.</param>
+ /// <param name="offset">The offset to start reading at.</param>
+ /// <param name="count">The maximum number of bytes to read.</param>
+ /// <returns>The actual number of bytes read.</returns>
+ private int InitialRead(byte[] destination, int offset, int count)
+ {
+ if (!CanDecompressEntry)
+ {
+ throw new ZipException("Library cannot extract this entry. Version required is (" + entry.Version + ")");
+ }
+
+ // Handle encryption if required.
+ if (entry.IsCrypted)
+ {
+ if (password == null)
+ {
+ throw new ZipException("No password set.");
+ }
+
+ // Generate and set crypto transform...
+ var managed = new PkzipClassicManaged();
+ var key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(password));
+
+ inputBuffer.CryptoTransform = managed.CreateDecryptor(key, null);
+
+ var cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];
+ inputBuffer.ReadClearTextBuffer(cryptbuffer, 0, ZipConstants.CryptoHeaderSize);
+
+ if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue)
+ {
+ throw new ZipException("Invalid password");
+ }
+
+ if (csize >= ZipConstants.CryptoHeaderSize)
+ {
+ csize -= ZipConstants.CryptoHeaderSize;
+ }
+ else if ((entry.Flags & (int) GeneralBitFlags.Descriptor) == 0)
+ {
+ throw new ZipException(string.Format("Entry compressed size {0} too small for encryption", csize));
+ }
+ }
+ else
+ {
+ inputBuffer.CryptoTransform = null;
+ }
+
+ if ((method == (int) CompressionMethod.Deflated) && (inputBuffer.Available > 0))
+ {
+ inputBuffer.SetInflaterInput(inf);
+ }
+
+ internalReader = BodyRead;
+ return BodyRead(destination, offset, count);
+ }
+
+ /// <summary>
+ /// Read a block of bytes from the stream.
+ /// </summary>
+ /// <param name="buffer">The destination for the bytes.</param>
+ /// <param name="offset">The index to start storing data.</param>
+ /// <param name="count">The number of bytes to attempt to read.</param>
+ /// <returns>Returns the number of bytes read.</returns>
+ /// <remarks>Zero bytes read means end of stream.</remarks>
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ if (buffer == null)
+ {
+ throw new ArgumentNullException("buffer");
+ }
+
+ if (offset < 0)
+ {
+ throw new ArgumentOutOfRangeException("offset", "Cannot be negative");
+ }
+
+ if (count < 0)
+ {
+ throw new ArgumentOutOfRangeException("count", "Cannot be negative");
+ }
+
+ if ((buffer.Length - offset) < count)
+ {
+ throw new ArgumentException("Invalid offset/count combination");
+ }
+
+ return internalReader(buffer, offset, count);
+ }
+
+ /// <summary>
+ /// Reads a block of bytes from the current zip entry.
+ /// </summary>
+ /// <returns>
+ /// The number of bytes read (this may be less than the length requested, even before the end of stream), or 0 on end of stream.
+ /// </returns>
+ /// <exception name="IOException">
+ /// An i/o error occured.
+ /// </exception>
+ /// <exception cref="ZipException">
+ /// The deflated stream is corrupted.
+ /// </exception>
+ /// <exception cref="InvalidOperationException">
+ /// The stream is not open.
+ /// </exception>
+ private int BodyRead(byte[] buffer, int offset, int count)
+ {
+ if (crc == null)
+ {
+ throw new InvalidOperationException("Closed");
+ }
+
+ if ((entry == null) || (count <= 0))
+ {
+ return 0;
+ }
+
+ if (offset + count > buffer.Length)
+ {
+ throw new ArgumentException("Offset + count exceeds buffer size");
+ }
+
+ var finished = false;
+
+ switch (method)
+ {
+ case (int) CompressionMethod.Deflated:
+ count = base.Read(buffer, offset, count);
+ if (count <= 0)
+ {
+ if (!inf.IsFinished)
+ {
+ throw new ZipException("Inflater not finished!");
+ }
+ inputBuffer.Available = inf.RemainingInput;
+
+ if ((flags & 8) == 0 && (inf.TotalIn != csize || inf.TotalOut != size))
+ {
+ throw new ZipException("Size mismatch: " + csize + ";" + size + " <-> " + inf.TotalIn + ";" +
+ inf.TotalOut);
+ }
+ inf.Reset();
+ finished = true;
+ }
+ break;
+
+ case (int) CompressionMethod.Stored:
+ if ((count > csize) && (csize >= 0))
+ {
+ count = (int) csize;
+ }
+
+ if (count > 0)
+ {
+ count = inputBuffer.ReadClearTextBuffer(buffer, offset, count);
+ if (count > 0)
+ {
+ csize -= count;
+ size -= count;
+ }
+ }
+
+ if (csize == 0)
+ {
+ finished = true;
+ }
+ else
+ {
+ if (count < 0)
+ {
+ throw new ZipException("EOF in stored block");
+ }
+ }
+ break;
+ }
+
+ if (count > 0)
+ {
+ crc.Update(buffer, offset, count);
+ }
+
+ if (finished)
+ {
+ CompleteCloseEntry(true);
+ }
+
+ return count;
+ }
+
+ /// <summary>
+ /// Closes the zip input stream
+ /// </summary>
+ public override void Close()
+ {
+ internalReader = ReadingNotAvailable;
+ crc = null;
+ entry = null;
+
+ base.Close();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// ZipNameTransform.cs
+//
+// Copyright 2005 John Reilly
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+
+using System;
+using System.IO;
+using System.Text;
+using ICSharpCode.SharpZipLib.Silverlight.Core;
+using ICSharpCode.SharpZipLib.Silverlight.Zip;
+
+namespace ICSharpCode.SharpZipLib.Zip
+{
+ /// <summary>
+ /// ZipNameTransform transforms names as per the Zip file naming convention.
+ /// </summary>
+ /// <remarks>The use of absolute names is supported although its use is not valid
+ /// according to Zip naming conventions, and should not be used if maximum compatability is desired.</remarks>
+ public class ZipNameTransform : INameTransform
+ {
+ #region Constructors
+ /// <summary>
+ /// Initialize a new instance of <see cref="ZipNameTransform"></see>
+ /// </summary>
+ public ZipNameTransform()
+ {
+ }
+
+ /// <summary>
+ /// Initialize a new instance of <see cref="ZipNameTransform"></see>
+ /// </summary>
+ /// <param name="trimPrefix">The string to trim from front of paths if found.</param>
+ public ZipNameTransform(string trimPrefix)
+ {
+ TrimPrefix = trimPrefix;
+ }
+ #endregion
+
+ /// <summary>
+ /// Static constructor.
+ /// </summary>
+ static ZipNameTransform()
+ {
+ var invalidPathChars = Path.GetInvalidPathChars();
+ var howMany = invalidPathChars.Length + 2;
+
+ InvalidEntryCharsRelaxed = new char[howMany];
+ Array.Copy(invalidPathChars, 0, InvalidEntryCharsRelaxed, 0, invalidPathChars.Length);
+ InvalidEntryCharsRelaxed[howMany - 1] = '*';
+ InvalidEntryCharsRelaxed[howMany - 2] = '?';
+
+ howMany = invalidPathChars.Length + 4;
+ InvalidEntryChars = new char[howMany];
+ Array.Copy(invalidPathChars, 0, InvalidEntryChars, 0, invalidPathChars.Length);
+ InvalidEntryChars[howMany - 1] = ':';
+ InvalidEntryChars[howMany - 2] = '\\';
+ InvalidEntryChars[howMany - 3] = '*';
+ InvalidEntryChars[howMany - 4] = '?';
+
+ }
+
+ /// <summary>
+ /// Transform a directory name according to the Zip file naming conventions.
+ /// </summary>
+ /// <param name="name">The directory name to transform.</param>
+ /// <returns>The transformed name.</returns>
+ public string TransformDirectory(string name)
+ {
+ name = TransformFile(name);
+ if (name.Length > 0) {
+ if ( !name.EndsWith("/") ) {
+ name += "/";
+ }
+ }
+ else {
+ throw new ZipException("Cannot have an empty directory name");
+ }
+ return name;
+ }
+
+ /// <summary>
+ /// Transform a windows file name according to the Zip file naming conventions.
+ /// </summary>
+ /// <param name="name">The file name to transform.</param>
+ /// <returns>The transformed name.</returns>
+ public string TransformFile(string name)
+ {
+ if (name != null) {
+ string lowerName = name.ToLower();
+ if ( (trimPrefix_ != null) && (lowerName.IndexOf(trimPrefix_) == 0) ) {
+ name = name.Substring(trimPrefix_.Length);
+ }
+
+ // The following can throw exceptions when the name contains invalid characters
+ if (Path.IsPathRooted(name) == true) {
+ // NOTE:
+ // for UNC names... \\machine\share\zoom\beet.txt gives \zoom\beet.txt
+ name = name.Substring(Path.GetPathRoot(name).Length);
+ }
+
+ name = name.Replace(@"\", "/");
+
+ while ( (name.Length > 0) && (name[0] == '/')) {
+ name = name.Remove(0, 1);
+ }
+
+ name = MakeValidName(name, '_');
+ }
+ else {
+ name = string.Empty;
+ }
+ return name;
+ }
+
+ /// <summary>
+ /// Get/set the path prefix to be trimmed from paths if present.
+ /// </summary>
+ /// <remarks>The prefix is trimmed before any conversion from
+ /// a windows path is done.</remarks>
+ public string TrimPrefix
+ {
+ get { return trimPrefix_; }
+ set {
+ trimPrefix_ = value;
+ if (trimPrefix_ != null) {
+ trimPrefix_ = trimPrefix_.ToLower();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Force a name to be valid by replacing invalid characters with a fixed value
+ /// </summary>
+ /// <param name="name">The name to force valid</param>
+ /// <param name="replacement">The replacement character to use.</param>
+ /// <returns>Returns a valid name</returns>
+ static string MakeValidName(string name, char replacement)
+ {
+ int index = name.IndexOfAny(InvalidEntryChars);
+ if (index > 0) {
+ StringBuilder builder = new StringBuilder(name);
+
+ while (index >= 0 ) {
+ builder[index] = replacement;
+
+ if (index >= name.Length) {
+ index = -1;
+ }
+ else {
+ index = name.IndexOfAny(InvalidEntryChars, index + 1);
+ }
+ }
+ name = builder.ToString();
+ }
+ return name;
+ }
+
+ /// <summary>
+ /// Test a name to see if it is a valid name for a zip entry.
+ /// </summary>
+ /// <param name="name">The name to test.</param>
+ /// <param name="relaxed">If true checking is relaxed about windows file names and absolute paths.</param>
+ /// <returns>Returns true if the name is a valid zip name; false otherwise.</returns>
+ /// <remarks>Zip path names are actually in Unix format, and should only contain relative paths.
+ /// This means that any path stored should not contain a drive or
+ /// device letter, or a leading slash. All slashes should forward slashes '/'.
+ /// An empty name is valid for a file where the input comes from standard input.
+ /// A null name is not considered valid.
+ /// </remarks>
+ public static bool IsValidName(string name, bool relaxed)
+ {
+ bool result = (name != null);
+
+ if ( result ) {
+ if ( relaxed ) {
+ result = name.IndexOfAny(InvalidEntryCharsRelaxed) < 0;
+ }
+ else {
+ result =
+ (name.IndexOfAny(InvalidEntryChars) < 0) &&
+ (name.IndexOf('/') != 0);
+ }
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Test a name to see if it is a valid name for a zip entry.
+ /// </summary>
+ /// <param name="name">The name to test.</param>
+ /// <returns>Returns true if the name is a valid zip name; false otherwise.</returns>
+ /// <remarks>Zip path names are actually in unix format,
+ /// and should only contain relative paths if a path is present.
+ /// This means that the path stored should not contain a drive or
+ /// device letter, or a leading slash. All slashes should forward slashes '/'.
+ /// An empty name is valid where the input comes from standard input.
+ /// A null name is not considered valid.
+ /// </remarks>
+ public static bool IsValidName(string name)
+ {
+ bool result =
+ (name != null) &&
+ (name.IndexOfAny(InvalidEntryChars) < 0) &&
+ (name.IndexOf('/') != 0)
+ ;
+ return result;
+ }
+
+ #region Instance Fields
+ string trimPrefix_;
+ #endregion
+
+ #region Class Fields
+ static readonly char[] InvalidEntryChars;
+ static readonly char[] InvalidEntryCharsRelaxed;
+ #endregion
+ }
+}
--- /dev/null
+// ZipOutputStream.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using ICSharpCode.SharpZipLib.Silverlight.Checksums;
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression;
+using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression.Streams;
+using ICSharpCode.SharpZipLib.Zip;
+
+namespace ICSharpCode.SharpZipLib.Silverlight.Zip
+{
+ /// <summary>
+ /// This is a DeflaterOutputStream that writes the files into a zip
+ /// archive one after another. It has a special method to start a new
+ /// zip entry. The zip entries contains information about the file name
+ /// size, compressed size, CRC, etc.
+ ///
+ /// It includes support for Stored and Deflated entries.
+ /// This class is not thread safe.
+ /// <br/>
+ /// <br/>Author of the original java version : Jochen Hoenicke
+ /// </summary>
+ /// <example> This sample shows how to create a zip file
+ /// <code>
+ /// using System;
+ /// using System.IO;
+ ///
+ /// using ICSharpCode.SharpZipLib.Core;
+ /// using ICSharpCode.SharpZipLib.Zip;
+ ///
+ /// class MainClass
+ /// {
+ /// public static void Main(string[] args)
+ /// {
+ /// string[] filenames = Directory.GetFiles(args[0]);
+ /// byte[] buffer = new byte[4096];
+ ///
+ /// using ( ZipOutputStream s = new ZipOutputStream(File.Create(args[1])) ) {
+ ///
+ /// s.SetLevel(9); // 0 - store only to 9 - means best compression
+ ///
+ /// foreach (string file in filenames) {
+ /// ZipEntry entry = new ZipEntry(file);
+ /// s.PutNextEntry(entry);
+ ///
+ /// using (FileStream fs = File.OpenRead(file)) {
+ /// StreamUtils.Copy(fs, s, buffer);
+ /// }
+ /// }
+ /// }
+ /// }
+ /// }
+ /// </code>
+ /// </example>
+ public class ZipOutputStream : DeflaterOutputStream
+ {
+ #region Constructors
+
+ /// <summary>
+ /// Creates a new Zip output stream, writing a zip archive.
+ /// </summary>
+ /// <param name="baseOutputStream">
+ /// The output stream to which the archive contents are written.
+ /// </param>
+ public ZipOutputStream(Stream baseOutputStream)
+ : base(baseOutputStream, new Deflater(Deflater.DEFAULT_COMPRESSION, true))
+ {
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Gets a flag value of true if the central header has been added for this archive; false if it has not been added.
+ /// </summary>
+ /// <remarks>No further entries can be added once this has been done.</remarks>
+ public bool IsFinished
+ {
+ get { return entries == null; }
+ }
+
+ /// <summary>
+ /// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.
+ /// </summary>
+ /// <remarks>Older archivers may not understand Zip64 extensions.
+ /// If backwards compatability is an issue be careful when adding <see cref="ZipEntry.Size">entries</see> to an archive.
+ /// Setting this property to off is workable but less desirable as in those circumstances adding a file
+ /// larger then 4GB will fail.</remarks>
+ public UseZip64 UseZip64
+ {
+ get { return useZip64_; }
+ set { useZip64_ = value; }
+ }
+
+ /// <summary>
+ /// Set the zip file comment.
+ /// </summary>
+ /// <param name="comment">
+ /// The comment text for the entire archive.
+ /// </param>
+ /// <exception name ="ArgumentOutOfRangeException">
+ /// The converted comment is longer than 0xffff bytes.
+ /// </exception>
+ public void SetComment(string comment)
+ {
+ // TODO: Its not yet clear how to handle unicode comments here.
+ var commentBytes = ZipConstants.ConvertToArray(comment);
+ if (commentBytes.Length > 0xffff)
+ {
+ throw new ArgumentOutOfRangeException("comment");
+ }
+ zipComment = commentBytes;
+ }
+
+ /// <summary>
+ /// Sets the compression level. The new level will be activated
+ /// immediately.
+ /// </summary>
+ /// <param name="level">The new compression level (1 to 9).</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// Level specified is not supported.
+ /// </exception>
+ /// <see cref="Deflater"/>
+ public void SetLevel(int level)
+ {
+ deflater_.SetLevel(level);
+ defaultCompressionLevel = level;
+ }
+
+ /// <summary>
+ /// Get the current deflater compression level
+ /// </summary>
+ /// <returns>The current compression level</returns>
+ public int GetLevel()
+ {
+ return deflater_.GetLevel();
+ }
+
+ /// <summary>
+ /// Write an unsigned short in little endian byte order.
+ /// </summary>
+ private void WriteLeShort(int value)
+ {
+ unchecked
+ {
+ baseOutputStream_.WriteByte((byte) (value & 0xff));
+ baseOutputStream_.WriteByte((byte) ((value >> 8) & 0xff));
+ }
+ }
+
+ /// <summary>
+ /// Write an int in little endian byte order.
+ /// </summary>
+ private void WriteLeInt(int value)
+ {
+ unchecked
+ {
+ WriteLeShort(value);
+ WriteLeShort(value >> 16);
+ }
+ }
+
+ /// <summary>
+ /// Write an int in little endian byte order.
+ /// </summary>
+ private void WriteLeLong(long value)
+ {
+ unchecked
+ {
+ WriteLeInt((int) value);
+ WriteLeInt((int) (value >> 32));
+ }
+ }
+
+ /// <summary>
+ /// Starts a new Zip entry. It automatically closes the previous
+ /// entry if present.
+ /// All entry elements bar name are optional, but must be correct if present.
+ /// If the compression method is stored and the output is not patchable
+ /// the compression for that entry is automatically changed to deflate level 0
+ /// </summary>
+ /// <param name="entry">
+ /// the entry.
+ /// </param>
+ /// <exception cref="System.ArgumentNullException">
+ /// if entry passed is null.
+ /// </exception>
+ /// <exception cref="System.IO.IOException">
+ /// if an I/O error occured.
+ /// </exception>
+ /// <exception cref="System.InvalidOperationException">
+ /// if stream was finished
+ /// </exception>
+ /// <exception cref="ZipException">
+ /// Too many entries in the Zip file<br/>
+ /// Entry name is too long<br/>
+ /// Finish has already been called<br/>
+ /// </exception>
+ public void PutNextEntry(ZipEntry entry)
+ {
+ if (entry == null)
+ {
+ throw new ArgumentNullException("entry");
+ }
+
+ if (entries == null)
+ {
+ throw new InvalidOperationException("ZipOutputStream was finished");
+ }
+
+ if (curEntry != null)
+ {
+ CloseEntry();
+ }
+
+ if (entries.Count == int.MaxValue)
+ {
+ throw new ZipException("Too many entries for Zip file");
+ }
+
+ var method = entry.CompressionMethod;
+ var compressionLevel = defaultCompressionLevel;
+
+ // Clear flags that the library manages internally
+ entry.Flags &= (int) GeneralBitFlags.UnicodeText;
+ patchEntryHeader = false;
+ var headerInfoAvailable = true;
+
+ if (method == CompressionMethod.Stored)
+ {
+ // Cant store values in a data descriptor as you cant extract stored files
+ // if the length isnt known.
+ entry.Flags &= ~8;
+ if (entry.CompressedSize >= 0)
+ {
+ if (entry.Size < 0)
+ {
+ entry.Size = entry.CompressedSize;
+ }
+ else if (entry.Size != entry.CompressedSize)
+ {
+ throw new ZipException("Method STORED, but compressed size != size");
+ }
+ }
+ else
+ {
+ if (entry.Size >= 0)
+ {
+ entry.CompressedSize = entry.Size;
+ }
+ }
+
+ if (entry.Size < 0 || entry.Crc < 0)
+ {
+ if (CanPatchEntries)
+ {
+ headerInfoAvailable = false;
+ }
+ else
+ {
+ // Can't patch entries so storing is not possible.
+ method = CompressionMethod.Deflated;
+ compressionLevel = 0;
+ }
+ }
+ }
+
+ if (method == CompressionMethod.Deflated)
+ {
+ if (entry.Size == 0)
+ {
+ // No need to compress - no data.
+ entry.CompressedSize = entry.Size;
+ entry.Crc = 0;
+ method = CompressionMethod.Stored;
+ }
+ else if ((entry.CompressedSize < 0) || (entry.Size < 0) || (entry.Crc < 0))
+ {
+ headerInfoAvailable = false;
+ }
+ }
+
+ if (headerInfoAvailable == false)
+ {
+ if (CanPatchEntries == false)
+ {
+ // Only way to record size and compressed size is to append a data descriptor
+ // after compressed data.
+ entry.Flags |= 8;
+ }
+ else
+ {
+ patchEntryHeader = true;
+ }
+ }
+
+ if (Password != null)
+ {
+ entry.IsCrypted = true;
+ if (entry.Crc < 0)
+ {
+ // Need to append a data descriptor as the crc isnt available for use
+ // with encryption, the date is used instead. Setting the flag
+ // indicates this to the decompressor.
+ entry.Flags |= 8;
+ }
+ }
+
+ entry.Offset = _offset;
+ entry.CompressionMethod = method;
+
+ curMethod = method;
+ sizePatchPos = -1;
+
+ if ((useZip64_ == UseZip64.On) || ((entry.Size < 0) && (useZip64_ == UseZip64.Dynamic)))
+ {
+ entry.ForceZip64();
+ }
+
+ // Write the local file header
+ WriteLeInt(ZipConstants.LocalHeaderSignature);
+
+ WriteLeShort(entry.Version);
+ WriteLeShort(entry.Flags);
+ WriteLeShort((byte) method);
+ WriteLeInt((int) entry.DosTime);
+
+ // TODO: Refactor header writing. Its done in several places.
+ if (headerInfoAvailable)
+ {
+ WriteLeInt((int) entry.Crc);
+ if (entry.LocalHeaderRequiresZip64)
+ {
+ WriteLeInt(-1);
+ WriteLeInt(-1);
+ }
+ else
+ {
+ WriteLeInt(entry.IsCrypted
+ ? (int) entry.CompressedSize + ZipConstants.CryptoHeaderSize
+ : (int) entry.CompressedSize);
+ WriteLeInt((int) entry.Size);
+ }
+ }
+ else
+ {
+ if (patchEntryHeader)
+ {
+ crcPatchPos = baseOutputStream_.Position;
+ }
+ WriteLeInt(0); // Crc
+
+ if (patchEntryHeader)
+ {
+ sizePatchPos = baseOutputStream_.Position;
+ }
+
+ // For local header both sizes appear in Zip64 Extended Information
+ if (entry.LocalHeaderRequiresZip64 && patchEntryHeader)
+ {
+ WriteLeInt(-1);
+ WriteLeInt(-1);
+ }
+ else
+ {
+ WriteLeInt(0); // Compressed size
+ WriteLeInt(0); // Uncompressed size
+ }
+ }
+
+ var name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
+
+ if (name.Length > 0xFFFF)
+ {
+ throw new ZipException("Entry name too long.");
+ }
+
+ var ed = new ZipExtraData(entry.ExtraData);
+
+ if (entry.LocalHeaderRequiresZip64 && (headerInfoAvailable || patchEntryHeader))
+ {
+ ed.StartNewEntry();
+ if (headerInfoAvailable)
+ {
+ ed.AddLeLong(entry.Size);
+ ed.AddLeLong(entry.CompressedSize);
+ }
+ else
+ {
+ ed.AddLeLong(-1);
+ ed.AddLeLong(-1);
+ }
+ ed.AddNewEntry(1);
+
+ if (!ed.Find(1))
+ {
+ throw new ZipException("Internal error cant find extra data");
+ }
+
+ if (patchEntryHeader)
+ {
+ sizePatchPos = ed.CurrentReadIndex;
+ }
+ }
+ else
+ {
+ ed.Delete(1);
+ }
+
+ var extra = ed.GetEntryData();
+
+ WriteLeShort(name.Length);
+ WriteLeShort(extra.Length);
+
+ if (name.Length > 0)
+ {
+ baseOutputStream_.Write(name, 0, name.Length);
+ }
+
+ if (entry.LocalHeaderRequiresZip64 && patchEntryHeader)
+ {
+ sizePatchPos += baseOutputStream_.Position;
+ }
+
+ if (extra.Length > 0)
+ {
+ baseOutputStream_.Write(extra, 0, extra.Length);
+ }
+
+ _offset += ZipConstants.LocalHeaderBaseSize + name.Length + extra.Length;
+
+ // Activate the entry.
+ curEntry = entry;
+ crc.Reset();
+ if (method == CompressionMethod.Deflated)
+ {
+ deflater_.Reset();
+ deflater_.SetLevel(compressionLevel);
+ }
+ size = 0;
+
+ if (entry.IsCrypted)
+ {
+ if (entry.Crc < 0)
+ {
+ // so testing Zip will says its ok
+ WriteEncryptionHeader(entry.DosTime << 16);
+ }
+ else
+ {
+ WriteEncryptionHeader(entry.Crc);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Closes the current entry, updating header and footer information as required
+ /// </summary>
+ /// <exception cref="System.IO.IOException">
+ /// An I/O error occurs.
+ /// </exception>
+ /// <exception cref="System.InvalidOperationException">
+ /// No entry is active.
+ /// </exception>
+ public void CloseEntry()
+ {
+ if (curEntry == null)
+ {
+ throw new InvalidOperationException("No open entry");
+ }
+
+ // First finish the deflater, if appropriate
+ if (curMethod == CompressionMethod.Deflated)
+ {
+ base.Finish();
+ }
+
+ var csize = (curMethod == CompressionMethod.Deflated) ? deflater_.TotalOut : size;
+
+ if (curEntry.Size < 0)
+ {
+ curEntry.Size = size;
+ }
+ else if (curEntry.Size != size)
+ {
+ throw new ZipException("size was " + size + ", but I expected " + curEntry.Size);
+ }
+
+ if (curEntry.CompressedSize < 0)
+ {
+ curEntry.CompressedSize = csize;
+ }
+ else if (curEntry.CompressedSize != csize)
+ {
+ throw new ZipException("compressed size was " + csize + ", but I expected " + curEntry.CompressedSize);
+ }
+
+ if (curEntry.Crc < 0)
+ {
+ curEntry.Crc = crc.Value;
+ }
+ else if (curEntry.Crc != crc.Value)
+ {
+ throw new ZipException("crc was " + crc.Value + ", but I expected " + curEntry.Crc);
+ }
+
+ _offset += csize;
+
+ if (curEntry.IsCrypted)
+ {
+ curEntry.CompressedSize += ZipConstants.CryptoHeaderSize;
+ }
+
+ // Patch the header if possible
+ if (patchEntryHeader)
+ {
+ patchEntryHeader = false;
+
+ var curPos = baseOutputStream_.Position;
+ baseOutputStream_.Seek(crcPatchPos, SeekOrigin.Begin);
+ WriteLeInt((int) curEntry.Crc);
+
+ if (curEntry.LocalHeaderRequiresZip64)
+ {
+ if (sizePatchPos == -1)
+ {
+ throw new ZipException("Entry requires zip64 but this has been turned off");
+ }
+
+ baseOutputStream_.Seek(sizePatchPos, SeekOrigin.Begin);
+ WriteLeLong(curEntry.Size);
+ WriteLeLong(curEntry.CompressedSize);
+ }
+ else
+ {
+ WriteLeInt((int) curEntry.CompressedSize);
+ WriteLeInt((int) curEntry.Size);
+ }
+ baseOutputStream_.Seek(curPos, SeekOrigin.Begin);
+ }
+
+ // Add data descriptor if flagged as required
+ if ((curEntry.Flags & 8) != 0)
+ {
+ WriteLeInt(ZipConstants.DataDescriptorSignature);
+ WriteLeInt(unchecked((int) curEntry.Crc));
+
+ if (curEntry.LocalHeaderRequiresZip64)
+ {
+ WriteLeLong(curEntry.CompressedSize);
+ WriteLeLong(curEntry.Size);
+ _offset += ZipConstants.Zip64DataDescriptorSize;
+ }
+ else
+ {
+ WriteLeInt((int) curEntry.CompressedSize);
+ WriteLeInt((int) curEntry.Size);
+ _offset += ZipConstants.DataDescriptorSize;
+ }
+ }
+
+ entries.Add(curEntry);
+ curEntry = null;
+ }
+
+ private void WriteEncryptionHeader(long crcValue)
+ {
+ _offset += ZipConstants.CryptoHeaderSize;
+
+ InitializePassword(Password);
+
+ var cryptBuffer = new byte[ZipConstants.CryptoHeaderSize];
+ var rnd = new Random();
+ rnd.NextBytes(cryptBuffer);
+ cryptBuffer[11] = (byte) (crcValue >> 24);
+
+ EncryptBlock(cryptBuffer, 0, cryptBuffer.Length);
+ baseOutputStream_.Write(cryptBuffer, 0, cryptBuffer.Length);
+ }
+
+ /// <summary>
+ /// Writes the given buffer to the current entry.
+ /// </summary>
+ /// <param name="buffer">The buffer containing data to write.</param>
+ /// <param name="offset">The offset of the first byte to write.</param>
+ /// <param name="count">The number of bytes to write.</param>
+ /// <exception cref="ZipException">Archive size is invalid</exception>
+ /// <exception cref="System.InvalidOperationException">No entry is active.</exception>
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ if (curEntry == null)
+ {
+ throw new InvalidOperationException("No open entry.");
+ }
+
+ if (buffer == null)
+ {
+ throw new ArgumentNullException("buffer");
+ }
+
+ if (offset < 0)
+ {
+ throw new ArgumentOutOfRangeException("offset", "Cannot be negative");
+ }
+
+ if (count < 0)
+ {
+ throw new ArgumentOutOfRangeException("count", "Cannot be negative");
+ }
+
+ if ((buffer.Length - offset) < count)
+ {
+ throw new ArgumentException("Invalid offset/count combination");
+ }
+
+ crc.Update(buffer, offset, count);
+ size += count;
+
+ switch (curMethod)
+ {
+ case CompressionMethod.Deflated:
+ base.Write(buffer, offset, count);
+ break;
+
+ case CompressionMethod.Stored:
+ if (Password != null)
+ {
+ CopyAndEncrypt(buffer, offset, count);
+ }
+ else
+ {
+ baseOutputStream_.Write(buffer, offset, count);
+ }
+ break;
+ }
+ }
+
+ private void CopyAndEncrypt(byte[] buffer, int offset, int count)
+ {
+ const int CopyBufferSize = 4096;
+ var localBuffer = new byte[CopyBufferSize];
+ while (count > 0)
+ {
+ var bufferCount = (count < CopyBufferSize) ? count : CopyBufferSize;
+
+ Array.Copy(buffer, offset, localBuffer, 0, bufferCount);
+ EncryptBlock(localBuffer, 0, bufferCount);
+ baseOutputStream_.Write(localBuffer, 0, bufferCount);
+ count -= bufferCount;
+ offset += bufferCount;
+ }
+ }
+
+ /// <summary>
+ /// Finishes the stream. This will write the central directory at the
+ /// end of the zip file and flush the stream.
+ /// </summary>
+ /// <remarks>
+ /// This is automatically called when the stream is closed.
+ /// </remarks>
+ /// <exception cref="System.IO.IOException">
+ /// An I/O error occurs.
+ /// </exception>
+ /// <exception cref="ZipException">
+ /// Comment exceeds the maximum length<br/>
+ /// Entry name exceeds the maximum length
+ /// </exception>
+ public override void Finish()
+ {
+ if (entries == null)
+ {
+ return;
+ }
+
+ if (curEntry != null)
+ {
+ CloseEntry();
+ }
+
+ long numEntries = entries.Count;
+ long sizeEntries = 0;
+
+ foreach (var entry in entries)
+ {
+ WriteLeInt(ZipConstants.CentralHeaderSignature);
+ WriteLeShort(ZipConstants.VersionMadeBy);
+ WriteLeShort(entry.Version);
+ WriteLeShort(entry.Flags);
+ WriteLeShort((short) entry.CompressionMethod);
+ WriteLeInt((int) entry.DosTime);
+ WriteLeInt((int) entry.Crc);
+
+ if (entry.IsZip64Forced() ||
+ (entry.CompressedSize >= uint.MaxValue))
+ {
+ WriteLeInt(-1);
+ }
+ else
+ {
+ WriteLeInt((int) entry.CompressedSize);
+ }
+
+ if (entry.IsZip64Forced() ||
+ (entry.Size >= uint.MaxValue))
+ {
+ WriteLeInt(-1);
+ }
+ else
+ {
+ WriteLeInt((int) entry.Size);
+ }
+
+ var name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
+
+ if (name.Length > 0xffff)
+ {
+ throw new ZipException("Name too long.");
+ }
+
+ var ed = new ZipExtraData(entry.ExtraData);
+
+ if (entry.CentralHeaderRequiresZip64)
+ {
+ ed.StartNewEntry();
+ if (entry.IsZip64Forced() ||
+ (entry.Size >= 0xffffffff))
+ {
+ ed.AddLeLong(entry.Size);
+ }
+
+ if (entry.IsZip64Forced() ||
+ (entry.CompressedSize >= 0xffffffff))
+ {
+ ed.AddLeLong(entry.CompressedSize);
+ }
+
+ if (entry.Offset >= 0xffffffff)
+ {
+ ed.AddLeLong(entry.Offset);
+ }
+
+ ed.AddNewEntry(1);
+ }
+ else
+ {
+ ed.Delete(1);
+ }
+
+ var extra = ed.GetEntryData();
+
+ var entryComment =
+ (entry.Comment != null)
+ ?
+ ZipConstants.ConvertToArray(entry.Flags, entry.Comment)
+ :
+ new byte[0];
+
+ if (entryComment.Length > 0xffff)
+ {
+ throw new ZipException("Comment too long.");
+ }
+
+ WriteLeShort(name.Length);
+ WriteLeShort(extra.Length);
+ WriteLeShort(entryComment.Length);
+ WriteLeShort(0); // disk number
+ WriteLeShort(0); // internal file attributes
+ // external file attributes
+
+ if (entry.ExternalFileAttributes != -1)
+ {
+ WriteLeInt(entry.ExternalFileAttributes);
+ }
+ else
+ {
+ if (entry.IsDirectory)
+ {
+ // mark entry as directory (from nikolam.AT.perfectinfo.com)
+ WriteLeInt(16);
+ }
+ else
+ {
+ WriteLeInt(0);
+ }
+ }
+
+ if (entry.Offset >= uint.MaxValue)
+ {
+ WriteLeInt(-1);
+ }
+ else
+ {
+ WriteLeInt((int) entry.Offset);
+ }
+
+ if (name.Length > 0)
+ {
+ baseOutputStream_.Write(name, 0, name.Length);
+ }
+
+ if (extra.Length > 0)
+ {
+ baseOutputStream_.Write(extra, 0, extra.Length);
+ }
+
+ if (entryComment.Length > 0)
+ {
+ baseOutputStream_.Write(entryComment, 0, entryComment.Length);
+ }
+
+ sizeEntries += ZipConstants.CentralHeaderBaseSize + name.Length + extra.Length + entryComment.Length;
+ }
+
+ using (var zhs = new ZipHelperStream(baseOutputStream_))
+ {
+ zhs.WriteEndOfCentralDirectory(numEntries, sizeEntries, _offset, zipComment);
+ }
+
+ entries = null;
+ }
+
+ #region Instance Fields
+
+ /// <summary>
+ /// Used to track the crc of data added to entries.
+ /// </summary>
+ private readonly Crc32 crc = new Crc32();
+
+ /// <summary>
+ /// Position to patch crc
+ /// </summary>
+ private long crcPatchPos = -1;
+
+ /// <summary>
+ /// The current entry being added.
+ /// </summary>
+ private ZipEntry curEntry;
+
+ private CompressionMethod curMethod = CompressionMethod.Deflated;
+ private int defaultCompressionLevel = Deflater.DEFAULT_COMPRESSION;
+
+ /// <summary>
+ /// The entries for the archive.
+ /// </summary>
+ private List<ZipEntry> entries = new List<ZipEntry>();
+
+ /// <summary>
+ /// Offset to be recorded for each entry in the central header.
+ /// </summary>
+ private long _offset;
+
+ /// <summary>
+ /// Flag indicating that header patching is required for the current entry.
+ /// </summary>
+ private bool patchEntryHeader;
+
+ /// <summary>
+ /// Used to track the size of data for an entry during writing.
+ /// </summary>
+ private long size;
+
+ /// <summary>
+ /// Position to patch size.
+ /// </summary>
+ private long sizePatchPos = -1;
+
+ // Default is dynamic which is not backwards compatible and can cause problems
+ // with XP's built in compression which cant read Zip64 archives.
+ // However it does avoid the situation were a large file is added and cannot be completed correctly.
+ // NOTE: Setting the size for entries before they are added is the best solution!
+ private UseZip64 useZip64_ = UseZip64.Dynamic;
+
+ /// <summary>
+ /// Comment for the entire archive recorded in central header.
+ /// </summary>
+ private byte[] zipComment = new byte[0];
+
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{487B7E3C-9689-47BC-8785-73CCD92A3749}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Hammock.ClientProfile</RootNamespace>
+ <AssemblyName>Hammock.ClientProfile</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <TargetFrameworkProfile>Client</TargetFrameworkProfile>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\bin\lib\4.0\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;NET40,ClientProfiles</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\bin\lib\net40-client\</OutputPath>
+ <DefineConstants>TRACE;NET40,ClientProfiles</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup>
+ <SignAssembly>true</SignAssembly>
+ </PropertyGroup>
+ <PropertyGroup>
+ <AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\..\net35\Hammock\Attributes\INamedAttribute.cs">
+ <Link>Attributes\INamedAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\IValidatingAttribute.cs">
+ <Link>Attributes\IValidatingAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\EntityAttribute.cs">
+ <Link>Attributes\Specialized\EntityAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\HeaderAttribute.cs">
+ <Link>Attributes\Specialized\HeaderAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\ParameterAttribute.cs">
+ <Link>Attributes\Specialized\ParameterAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\UserAgentAttribute.cs">
+ <Link>Attributes\Specialized\UserAgentAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\BooleanToIntegerAttribute.cs">
+ <Link>Attributes\Validation\BooleanToIntegerAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\DateTimeFormatAttribute.cs">
+ <Link>Attributes\Validation\DateTimeFormatAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\RequiredAttribute.cs">
+ <Link>Attributes\Validation\RequiredAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\SpecificationAttribute.cs">
+ <Link>Attributes\Validation\SpecificationAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\ValidationAttribute.cs">
+ <Link>Attributes\Validation\ValidationAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\Basic\BasicAuthCredentials.cs">
+ <Link>Authentication\Basic\BasicAuthCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\IWebCredentials.cs">
+ <Link>Authentication\IWebCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthCredentials.cs">
+ <Link>Authentication\OAuth\OAuthCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthParameterHandling.cs">
+ <Link>Authentication\OAuth\OAuthParameterHandling.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthSignatureMethod.cs">
+ <Link>Authentication\OAuth\OAuthSignatureMethod.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthToken.cs">
+ <Link>Authentication\OAuth\OAuthToken.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthTools.cs">
+ <Link>Authentication\OAuth\OAuthTools.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthType.cs">
+ <Link>Authentication\OAuth\OAuthType.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWebQuery.cs">
+ <Link>Authentication\OAuth\OAuthWebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWebQueryInfo.cs">
+ <Link>Authentication\OAuth\OAuthWebQueryInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWorkflow.cs">
+ <Link>Authentication\OAuth\OAuthWorkflow.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\AspNetCache.cs">
+ <Link>Caching\AspNetCache.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheFactory.cs">
+ <Link>Caching\CacheFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheMode.cs">
+ <Link>Caching\CacheMode.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheOptions.cs">
+ <Link>Caching\CacheOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\ICache.cs">
+ <Link>Caching\ICache.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\IDependencyCache.cs">
+ <Link>Caching\IDependencyCache.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\SimpleCache.cs">
+ <Link>Caching\SimpleCache.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\CollectionExtensions.cs">
+ <Link>Extensions\CollectionExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\FormatExtensions.cs">
+ <Link>Extensions\FormatExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\OAuthExtensions.cs">
+ <Link>Extensions\OAuthExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\ObjectExtensions.cs">
+ <Link>Extensions\ObjectExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\ReflectionExtensions.cs">
+ <Link>Extensions\ReflectionExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\SpecificationExtensions.cs">
+ <Link>Extensions\SpecificationExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\StringExtensions.cs">
+ <Link>Extensions\StringExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\TimeExtensions.cs">
+ <Link>Extensions\TimeExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\WebExtensions.cs">
+ <Link>Extensions\WebExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\IRestClient.cs">
+ <Link>IRestClient.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Model\PropertyChangedBase.cs">
+ <Link>Model\PropertyChangedBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestBase.cs">
+ <Link>RestBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestCallback.cs">
+ <Link>RestCallback.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestClient.cs">
+ <Link>RestClient.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestRequest.cs">
+ <Link>RestRequest.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestResponse.cs">
+ <Link>RestResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\ConnectionClosed.cs">
+ <Link>Retries\ConnectionClosed.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\IRetryCondition.cs">
+ <Link>Retries\IRetryCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\IRetryCustomCondition.cs">
+ <Link>Retries\IRetryCustomCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\NetworkError.cs">
+ <Link>Retries\NetworkError.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryCondition.cs">
+ <Link>Retries\RetryCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryCustomCondition.cs">
+ <Link>Retries\RetryCustomCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryErrorCondition.cs">
+ <Link>Retries\RetryErrorCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryPolicy.cs">
+ <Link>Retries\RetryPolicy.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryResultCondition.cs">
+ <Link>Retries\RetryResultCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\Timeout.cs">
+ <Link>Retries\Timeout.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\DefaultJsonSerializer.cs">
+ <Link>Serialization\DefaultJsonSerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\HammockXmlSerializer.cs">
+ <Link>Serialization\HammockXmlSerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\IDeserializer.cs">
+ <Link>Serialization\IDeserializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\ISerializer.cs">
+ <Link>Serialization\ISerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\JsonParser.cs">
+ <Link>Serialization\JsonParser.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\Utf8Serializer.cs">
+ <Link>Serialization\Utf8Serializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\AndSpecification.cs">
+ <Link>Specifications\AndSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\CompositeSpecificationBase.cs">
+ <Link>Specifications\CompositeSpecificationBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\HammockSpecification.cs">
+ <Link>Specifications\HammockSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\ISpecification.cs">
+ <Link>Specifications\ISpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\NotSpecification.cs">
+ <Link>Specifications\NotSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\OrSpecification.cs">
+ <Link>Specifications\OrSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Streaming\StreamOptions.cs">
+ <Link>Streaming\StreamOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\IRateLimitingRule.cs">
+ <Link>Tasks\IRateLimitingRule.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\IRateLimitStatus.cs">
+ <Link>Tasks\IRateLimitStatus.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITaskOptions.cs">
+ <Link>Tasks\ITaskOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITaskState.cs">
+ <Link>Tasks\ITaskState.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITimedTask.cs">
+ <Link>Tasks\ITimedTask.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\RateLimitingRule.cs">
+ <Link>Tasks\RateLimitingRule.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\RateLimitType.cs">
+ <Link>Tasks\RateLimitType.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TaskOptions.cs">
+ <Link>Tasks\TaskOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TaskState.cs">
+ <Link>Tasks\TaskState.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TimedTask.cs">
+ <Link>Tasks\TimedTask.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Validation\ValidationException.cs">
+ <Link>Validation\ValidationException.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Validation\ValidEmailSpecification.cs">
+ <Link>Validation\ValidEmailSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\BasicAuthWebQuery.cs">
+ <Link>Web\BasicAuthWebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\GetOrDelete.cs">
+ <Link>Web\GetOrDelete.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\HttpCookieParameter.cs">
+ <Link>Web\HttpCookieParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\HttpPostParameter.cs">
+ <Link>Web\HttpPostParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\HttpPostParameterType.cs">
+ <Link>Web\HttpPostParameterType.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\IWebQueryInfo.cs">
+ <Link>Web\IWebQueryInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\IMockable.cs">
+ <Link>Web\Mocks\IMockable.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\IWebResponse.cs">
+ <Link>Web\Mocks\IWebResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockHttpWebRequest.cs">
+ <Link>Web\Mocks\MockHttpWebRequest.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockHttpWebResponse.cs">
+ <Link>Web\Mocks\MockHttpWebResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockWebRequestFactory.cs">
+ <Link>Web\Mocks\MockWebRequestFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Pair.cs">
+ <Link>Web\Pair.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\PostOrPut.cs">
+ <Link>Web\PostOrPut.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Triplet.cs">
+ <Link>Web\Triplet.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebCallback.cs">
+ <Link>Web\WebCallback.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebEntity.cs">
+ <Link>Web\WebEntity.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebHeader.cs">
+ <Link>Web\WebHeader.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebHeaderCollection.cs">
+ <Link>Web\WebHeaderCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebMethod.cs">
+ <Link>Web\WebMethod.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebPair.cs">
+ <Link>Web\WebPair.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebPairCollection.cs">
+ <Link>Web\WebPairCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebParameter.cs">
+ <Link>Web\WebParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebParameterCollection.cs">
+ <Link>Web\WebParameterCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQuery.Async.cs">
+ <Link>Web\WebQuery.Async.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQuery.cs">
+ <Link>Web\WebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryAsyncResult.cs">
+ <Link>Web\WebQueryAsyncResult.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryRequestEventArgs.cs">
+ <Link>Web\WebQueryRequestEventArgs.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryResponseEventArgs.cs">
+ <Link>Web\WebQueryResponseEventArgs.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryResult.cs">
+ <Link>Web\WebQueryResult.cs</Link>
+ </Compile>
+ <Compile Include="Mono\HttpUtility.cs" />
+ <Compile Include="Mono\WebHeaderCollection.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\net35\Hammock\Attributes\Specialized\_Specialized.cd">
+ <Link>Attributes\Specialized\_Specialized.cd</Link>
+ </None>
+ <None Include="..\..\net35\Hammock\Attributes\Validation\_Validation.cd">
+ <Link>Attributes\Validation\_Validation.cd</Link>
+ </None>
+ <None Include="..\..\net35\Hammock\Authentication\OAuth\_OAuth.cd">
+ <Link>Authentication\OAuth\_OAuth.cd</Link>
+ </None>
+ <None Include="..\..\net35\Hammock\Authentication\_Authentication.cd">
+ <Link>Authentication\_Authentication.cd</Link>
+ </None>
+ <None Include="..\..\net35\Hammock\Caching\_Caching.cd">
+ <Link>Caching\_Caching.cd</Link>
+ </None>
+ <None Include="..\..\net35\Hammock\Tasks\_Tasks.cd">
+ <Link>Tasks\_Tasks.cd</Link>
+ </None>
+ <None Include="..\..\net35\Hammock\Web\Mocks\_Mocks.cd">
+ <Link>Web\Mocks\_Mocks.cd</Link>
+ </None>
+ <None Include="..\..\net35\Hammock\Web\_Web.cd">
+ <Link>Web\_Web.cd</Link>
+ </None>
+ <None Include="..\..\net35\Hammock\_Hammock.cd">
+ <Link>_Hammock.cd</Link>
+ </None>
+ <None Include="key.snk" />
+ </ItemGroup>
+ <ItemGroup />
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
\ No newline at end of file
--- /dev/null
+//
+// System.Web.HttpUtility
+//
+// Authors:
+// Patrik Torstensson (Patrik.Torstensson@labs2.com)
+// Wictor Wilén (decode/encode functions) (wictor@ibizkit.se)
+// Tim Coleman (tim@timcoleman.com)
+// Gonzalo Paniagua Javier (gonzalo@ximian.com)
+//
+// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+
+using System.Collections;
+using System.Collections.Specialized;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+namespace System.Compat.Web
+{
+ public sealed class HttpUtility
+ {
+ #region Fields
+
+ private static Hashtable entities;
+ private static readonly object lock_ = new object();
+
+ #endregion // Fields
+
+ private static Hashtable Entities
+ {
+ get
+ {
+ lock (lock_)
+ {
+ if (entities == null)
+ {
+ InitEntities();
+ }
+
+ return entities;
+ }
+ }
+ }
+
+ #region Constructors
+
+ private static void InitEntities()
+ {
+ // Build the hash table of HTML entity references. This list comes
+ // from the HTML 4.01 W3C recommendation.
+ entities = new Hashtable
+ {
+ {"nbsp", '\u00A0'},
+ {"iexcl", '\u00A1'},
+ {"cent", '\u00A2'},
+ {"pound", '\u00A3'},
+ {"curren", '\u00A4'},
+ {"yen", '\u00A5'},
+ {"brvbar", '\u00A6'},
+ {"sect", '\u00A7'},
+ {"uml", '\u00A8'},
+ {"copy", '\u00A9'},
+ {"ordf", '\u00AA'},
+ {"laquo", '\u00AB'},
+ {"not", '\u00AC'},
+ {"shy", '\u00AD'},
+ {"reg", '\u00AE'},
+ {"macr", '\u00AF'},
+ {"deg", '\u00B0'},
+ {"plusmn", '\u00B1'},
+ {"sup2", '\u00B2'},
+ {"sup3", '\u00B3'},
+ {"acute", '\u00B4'},
+ {"micro", '\u00B5'},
+ {"para", '\u00B6'},
+ {"middot", '\u00B7'},
+ {"cedil", '\u00B8'},
+ {"sup1", '\u00B9'},
+ {"ordm", '\u00BA'},
+ {"raquo", '\u00BB'},
+ {"frac14", '\u00BC'},
+ {"frac12", '\u00BD'},
+ {"frac34", '\u00BE'},
+ {"iquest", '\u00BF'},
+ {"Agrave", '\u00C0'},
+ {"Aacute", '\u00C1'},
+ {"Acirc", '\u00C2'},
+ {"Atilde", '\u00C3'},
+ {"Auml", '\u00C4'},
+ {"Aring", '\u00C5'},
+ {"AElig", '\u00C6'},
+ {"Ccedil", '\u00C7'},
+ {"Egrave", '\u00C8'},
+ {"Eacute", '\u00C9'},
+ {"Ecirc", '\u00CA'},
+ {"Euml", '\u00CB'},
+ {"Igrave", '\u00CC'},
+ {"Iacute", '\u00CD'},
+ {"Icirc", '\u00CE'},
+ {"Iuml", '\u00CF'},
+ {"ETH", '\u00D0'},
+ {"Ntilde", '\u00D1'},
+ {"Ograve", '\u00D2'},
+ {"Oacute", '\u00D3'},
+ {"Ocirc", '\u00D4'},
+ {"Otilde", '\u00D5'},
+ {"Ouml", '\u00D6'},
+ {"times", '\u00D7'},
+ {"Oslash", '\u00D8'},
+ {"Ugrave", '\u00D9'},
+ {"Uacute", '\u00DA'},
+ {"Ucirc", '\u00DB'},
+ {"Uuml", '\u00DC'},
+ {"Yacute", '\u00DD'},
+ {"THORN", '\u00DE'},
+ {"szlig", '\u00DF'},
+ {"agrave", '\u00E0'},
+ {"aacute", '\u00E1'},
+ {"acirc", '\u00E2'},
+ {"atilde", '\u00E3'},
+ {"auml", '\u00E4'},
+ {"aring", '\u00E5'},
+ {"aelig", '\u00E6'},
+ {"ccedil", '\u00E7'},
+ {"egrave", '\u00E8'},
+ {"eacute", '\u00E9'},
+ {"ecirc", '\u00EA'},
+ {"euml", '\u00EB'},
+ {"igrave", '\u00EC'},
+ {"iacute", '\u00ED'},
+ {"icirc", '\u00EE'},
+ {"iuml", '\u00EF'},
+ {"eth", '\u00F0'},
+ {"ntilde", '\u00F1'},
+ {"ograve", '\u00F2'},
+ {"oacute", '\u00F3'},
+ {"ocirc", '\u00F4'},
+ {"otilde", '\u00F5'},
+ {"ouml", '\u00F6'},
+ {"divide", '\u00F7'},
+ {"oslash", '\u00F8'},
+ {"ugrave", '\u00F9'},
+ {"uacute", '\u00FA'},
+ {"ucirc", '\u00FB'},
+ {"uuml", '\u00FC'},
+ {"yacute", '\u00FD'},
+ {"thorn", '\u00FE'},
+ {"yuml", '\u00FF'},
+ {"fnof", '\u0192'},
+ {"Alpha", '\u0391'},
+ {"Beta", '\u0392'},
+ {"Gamma", '\u0393'},
+ {"Delta", '\u0394'},
+ {"Epsilon", '\u0395'},
+ {"Zeta", '\u0396'},
+ {"Eta", '\u0397'},
+ {"Theta", '\u0398'},
+ {"Iota", '\u0399'},
+ {"Kappa", '\u039A'},
+ {"Lambda", '\u039B'},
+ {"Mu", '\u039C'},
+ {"Nu", '\u039D'},
+ {"Xi", '\u039E'},
+ {"Omicron", '\u039F'},
+ {"Pi", '\u03A0'},
+ {"Rho", '\u03A1'},
+ {"Sigma", '\u03A3'},
+ {"Tau", '\u03A4'},
+ {"Upsilon", '\u03A5'},
+ {"Phi", '\u03A6'},
+ {"Chi", '\u03A7'},
+ {"Psi", '\u03A8'},
+ {"Omega", '\u03A9'},
+ {"alpha", '\u03B1'},
+ {"beta", '\u03B2'},
+ {"gamma", '\u03B3'},
+ {"delta", '\u03B4'},
+ {"epsilon", '\u03B5'},
+ {"zeta", '\u03B6'},
+ {"eta", '\u03B7'},
+ {"theta", '\u03B8'},
+ {"iota", '\u03B9'},
+ {"kappa", '\u03BA'},
+ {"lambda", '\u03BB'},
+ {"mu", '\u03BC'},
+ {"nu", '\u03BD'},
+ {"xi", '\u03BE'},
+ {"omicron", '\u03BF'},
+ {"pi", '\u03C0'},
+ {"rho", '\u03C1'},
+ {"sigmaf", '\u03C2'},
+ {"sigma", '\u03C3'},
+ {"tau", '\u03C4'},
+ {"upsilon", '\u03C5'},
+ {"phi", '\u03C6'},
+ {"chi", '\u03C7'},
+ {"psi", '\u03C8'},
+ {"omega", '\u03C9'},
+ {"thetasym", '\u03D1'},
+ {"upsih", '\u03D2'},
+ {"piv", '\u03D6'},
+ {"bull", '\u2022'},
+ {"hellip", '\u2026'},
+ {"prime", '\u2032'},
+ {"Prime", '\u2033'},
+ {"oline", '\u203E'},
+ {"frasl", '\u2044'},
+ {"weierp", '\u2118'},
+ {"image", '\u2111'},
+ {"real", '\u211C'},
+ {"trade", '\u2122'},
+ {"alefsym", '\u2135'},
+ {"larr", '\u2190'},
+ {"uarr", '\u2191'},
+ {"rarr", '\u2192'},
+ {"darr", '\u2193'},
+ {"harr", '\u2194'},
+ {"crarr", '\u21B5'},
+ {"lArr", '\u21D0'},
+ {"uArr", '\u21D1'},
+ {"rArr", '\u21D2'},
+ {"dArr", '\u21D3'},
+ {"hArr", '\u21D4'},
+ {"forall", '\u2200'},
+ {"part", '\u2202'},
+ {"exist", '\u2203'},
+ {"empty", '\u2205'},
+ {"nabla", '\u2207'},
+ {"isin", '\u2208'},
+ {"notin", '\u2209'},
+ {"ni", '\u220B'},
+ {"prod", '\u220F'},
+ {"sum", '\u2211'},
+ {"minus", '\u2212'},
+ {"lowast", '\u2217'},
+ {"radic", '\u221A'},
+ {"prop", '\u221D'},
+ {"infin", '\u221E'},
+ {"ang", '\u2220'},
+ {"and", '\u2227'},
+ {"or", '\u2228'},
+ {"cap", '\u2229'},
+ {"cup", '\u222A'},
+ {"int", '\u222B'},
+ {"there4", '\u2234'},
+ {"sim", '\u223C'},
+ {"cong", '\u2245'},
+ {"asymp", '\u2248'},
+ {"ne", '\u2260'},
+ {"equiv", '\u2261'},
+ {"le", '\u2264'},
+ {"ge", '\u2265'},
+ {"sub", '\u2282'},
+ {"sup", '\u2283'},
+ {"nsub", '\u2284'},
+ {"sube", '\u2286'},
+ {"supe", '\u2287'},
+ {"oplus", '\u2295'},
+ {"otimes", '\u2297'},
+ {"perp", '\u22A5'},
+ {"sdot", '\u22C5'},
+ {"lceil", '\u2308'},
+ {"rceil", '\u2309'},
+ {"lfloor", '\u230A'},
+ {"rfloor", '\u230B'},
+ {"lang", '\u2329'},
+ {"rang", '\u232A'},
+ {"loz", '\u25CA'},
+ {"spades", '\u2660'},
+ {"clubs", '\u2663'},
+ {"hearts", '\u2665'},
+ {"diams", '\u2666'},
+ {"quot", '\u0022'},
+ {"amp", '\u0026'},
+ {"lt", '\u003C'},
+ {"gt", '\u003E'},
+ {"OElig", '\u0152'},
+ {"oelig", '\u0153'},
+ {"Scaron", '\u0160'},
+ {"scaron", '\u0161'},
+ {"Yuml", '\u0178'},
+ {"circ", '\u02C6'},
+ {"tilde", '\u02DC'},
+ {"ensp", '\u2002'},
+ {"emsp", '\u2003'},
+ {"thinsp", '\u2009'},
+ {"zwnj", '\u200C'},
+ {"zwj", '\u200D'},
+ {"lrm", '\u200E'},
+ {"rlm", '\u200F'},
+ {"ndash", '\u2013'},
+ {"mdash", '\u2014'},
+ {"lsquo", '\u2018'},
+ {"rsquo", '\u2019'},
+ {"sbquo", '\u201A'},
+ {"ldquo", '\u201C'},
+ {"rdquo", '\u201D'},
+ {"bdquo", '\u201E'},
+ {"dagger", '\u2020'},
+ {"Dagger", '\u2021'},
+ {"permil", '\u2030'},
+ {"lsaquo", '\u2039'},
+ {"rsaquo", '\u203A'},
+ {"euro", '\u20AC'}
+ };
+ }
+
+ #endregion // Constructors
+
+ #region Methods
+
+ private static readonly char[] hexChars = "0123456789abcdef".ToCharArray();
+
+ public static void HtmlAttributeEncode(string s, TextWriter output)
+ {
+ output.Write(HtmlAttributeEncode(s));
+ }
+
+ public static string HtmlAttributeEncode(string s)
+ {
+ if (null == s)
+ {
+ return null;
+ }
+
+ var needEncode = false;
+ for (var i = 0; i < s.Length; i++)
+ {
+ if (s[i] == '&' || s[i] == '"' || s[i] == '<')
+ {
+ needEncode = true;
+ break;
+ }
+ }
+
+ if (!needEncode)
+ {
+ return s;
+ }
+
+ var output = new StringBuilder();
+ var len = s.Length;
+ for (var i = 0; i < len; i++)
+ {
+ switch (s[i])
+ {
+ case '&':
+ output.Append("&");
+ break;
+ case '"':
+ output.Append(""");
+ break;
+ case '<':
+ output.Append("<");
+ break;
+ default:
+ output.Append(s[i]);
+ break;
+ }
+ }
+
+ return output.ToString();
+ }
+
+ public static string UrlDecode(string str)
+ {
+ return UrlDecode(str, Encoding.UTF8);
+ }
+
+ private static char[] GetChars(MemoryStream b, Encoding e)
+ {
+ return e.GetChars(b.GetBuffer(), 0, (int) b.Length);
+ }
+
+ public static string UrlDecode(string s, Encoding e)
+ {
+ if (null == s)
+ {
+ return null;
+ }
+
+ if (s.IndexOf('%') == -1 && s.IndexOf('+') == -1)
+ {
+ return s;
+ }
+
+ if (e == null)
+ {
+ e = Encoding.UTF8;
+ }
+
+ var output = new StringBuilder();
+ long len = s.Length;
+ var bytes = new MemoryStream();
+
+ for (var i = 0; i < len; i++)
+ {
+ if (s[i] == '%' && i + 2 < len && s[i + 1] != '%')
+ {
+ int xchar;
+ if (s[i + 1] == 'u' && i + 5 < len)
+ {
+ if (bytes.Length > 0)
+ {
+ output.Append(GetChars(bytes, e));
+ bytes.SetLength(0);
+ }
+
+ xchar = GetChar(s, i + 2, 4);
+ if (xchar != -1)
+ {
+ output.Append((char) xchar);
+ i += 5;
+ }
+ else
+ {
+ output.Append('%');
+ }
+ }
+ else if ((xchar = GetChar(s, i + 1, 2)) != -1)
+ {
+ bytes.WriteByte((byte) xchar);
+ i += 2;
+ }
+ else
+ {
+ output.Append('%');
+ }
+ continue;
+ }
+
+ if (bytes.Length > 0)
+ {
+ output.Append(GetChars(bytes, e));
+ bytes.SetLength(0);
+ }
+
+ if (s[i] == '+')
+ {
+ output.Append(' ');
+ }
+ else
+ {
+ output.Append(s[i]);
+ }
+ }
+
+ if (bytes.Length > 0)
+ {
+ output.Append(GetChars(bytes, e));
+ }
+
+ return output.ToString();
+ }
+
+ public static string UrlDecode(byte[] bytes, Encoding e)
+ {
+ return bytes == null ? null : UrlDecode(bytes, 0, bytes.Length, e);
+ }
+
+ private static int GetInt(byte b)
+ {
+ var c = (char) b;
+ if (c >= '0' && c <= '9')
+ {
+ return c - '0';
+ }
+
+ if (c >= 'a' && c <= 'f')
+ {
+ return c - 'a' + 10;
+ }
+
+ if (c >= 'A' && c <= 'F')
+ {
+ return c - 'A' + 10;
+ }
+
+ return -1;
+ }
+
+ private static int GetChar(byte[] bytes, int offset, int length)
+ {
+ var value = 0;
+ var end = length + offset;
+ for (var i = offset; i < end; i++)
+ {
+ var current = GetInt(bytes[i]);
+ if (current == -1)
+ {
+ return -1;
+ }
+ value = (value << 4) + current;
+ }
+
+ return value;
+ }
+
+ private static int GetChar(string str, int offset, int length)
+ {
+ var val = 0;
+ var end = length + offset;
+ for (var i = offset; i < end; i++)
+ {
+ var c = str[i];
+ if (c > 127)
+ {
+ return -1;
+ }
+
+ var current = GetInt((byte) c);
+ if (current == -1)
+ {
+ return -1;
+ }
+ val = (val << 4) + current;
+ }
+
+ return val;
+ }
+
+ public static string UrlDecode(byte[] bytes, int offset, int count, Encoding e)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+ if (count == 0)
+ {
+ return String.Empty;
+ }
+
+ if (bytes == null)
+ {
+ throw new ArgumentNullException("bytes");
+ }
+
+ if (offset < 0 || offset > bytes.Length)
+ {
+ throw new ArgumentOutOfRangeException("offset");
+ }
+
+ if (count < 0 || offset + count > bytes.Length)
+ {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ var output = new StringBuilder();
+ var acc = new MemoryStream();
+
+ var end = count + offset;
+ for (var i = offset; i < end; i++)
+ {
+ if (bytes[i] == '%' && i + 2 < count && bytes[i + 1] != '%')
+ {
+ int xchar;
+ if (bytes[i + 1] == (byte) 'u' && i + 5 < end)
+ {
+ if (acc.Length > 0)
+ {
+ output.Append(GetChars(acc, e));
+ acc.SetLength(0);
+ }
+ xchar = GetChar(bytes, i + 2, 4);
+ if (xchar != -1)
+ {
+ output.Append((char) xchar);
+ i += 5;
+ continue;
+ }
+ }
+ else if ((xchar = GetChar(bytes, i + 1, 2)) != -1)
+ {
+ acc.WriteByte((byte) xchar);
+ i += 2;
+ continue;
+ }
+ }
+
+ if (acc.Length > 0)
+ {
+ output.Append(GetChars(acc, e));
+ acc.SetLength(0);
+ }
+
+ if (bytes[i] == '+')
+ {
+ output.Append(' ');
+ }
+ else
+ {
+ output.Append((char) bytes[i]);
+ }
+ }
+
+ if (acc.Length > 0)
+ {
+ output.Append(GetChars(acc, e));
+ }
+
+ return output.ToString();
+ }
+
+ public static byte[] UrlDecodeToBytes(byte[] bytes)
+ {
+ return bytes == null ? null : UrlDecodeToBytes(bytes, 0, bytes.Length);
+ }
+
+ public static byte[] UrlDecodeToBytes(string str)
+ {
+ return UrlDecodeToBytes(str, Encoding.UTF8);
+ }
+
+ public static byte[] UrlDecodeToBytes(string str, Encoding e)
+ {
+ if (str == null)
+ {
+ return null;
+ }
+
+ if (e == null)
+ {
+ throw new ArgumentNullException("e");
+ }
+
+ return UrlDecodeToBytes(e.GetBytes(str));
+ }
+
+ public static byte[] UrlDecodeToBytes(byte[] bytes, int offset, int count)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+ if (count == 0)
+ {
+ return new byte[0];
+ }
+
+ var len = bytes.Length;
+ if (offset < 0 || offset >= len)
+ {
+ throw new ArgumentOutOfRangeException("offset");
+ }
+
+ if (count < 0 || offset > len - count)
+ {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ var result = new MemoryStream();
+ var end = offset + count;
+ for (var i = offset; i < end; i++)
+ {
+ var c = (char) bytes[i];
+ if (c == '+')
+ {
+ c = ' ';
+ }
+ else if (c == '%' && i < end - 2)
+ {
+ var xchar = GetChar(bytes, i + 1, 2);
+ if (xchar != -1)
+ {
+ c = (char) xchar;
+ i += 2;
+ }
+ }
+ result.WriteByte((byte) c);
+ }
+
+ return result.ToArray();
+ }
+
+ public static string UrlEncode(string str)
+ {
+ return UrlEncode(str, Encoding.UTF8);
+ }
+
+ public static string UrlEncode(string s, Encoding Enc)
+ {
+ if (s == null)
+ {
+ return null;
+ }
+
+ if (s == "")
+ {
+ return "";
+ }
+
+ var needEncode = false;
+ var len = s.Length;
+ for (var i = 0; i < len; i++)
+ {
+ var c = s[i];
+ if ((c < '0') || (c < 'A' && c > '9') || (c > 'Z' && c < 'a') || (c > 'z'))
+ {
+ if (NotEncoded(c))
+ {
+ continue;
+ }
+
+ needEncode = true;
+ break;
+ }
+ }
+
+ if (!needEncode)
+ {
+ return s;
+ }
+
+ // avoided GetByteCount call
+ var bytes = new byte[Enc.GetMaxByteCount(s.Length)];
+ var realLen = Enc.GetBytes(s, 0, s.Length, bytes, 0);
+ return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, 0, realLen), 0, realLen);
+ }
+
+ public static string UrlEncode(byte[] bytes)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ if (bytes.Length == 0)
+ {
+ return "";
+ }
+
+ return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, 0, bytes.Length), 0, bytes.Length);
+ }
+
+ public static string UrlEncode(byte[] bytes, int offset, int count)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ if (bytes.Length == 0)
+ {
+ return "";
+ }
+
+ return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, offset, count), offset, count);
+ }
+
+ public static byte[] UrlEncodeToBytes(string str)
+ {
+ return UrlEncodeToBytes(str, Encoding.UTF8);
+ }
+
+ public static byte[] UrlEncodeToBytes(string str, Encoding e)
+ {
+ if (str == null)
+ {
+ return null;
+ }
+
+ if (str == "")
+ {
+ return new byte[0];
+ }
+
+ var bytes = e.GetBytes(str);
+ return UrlEncodeToBytes(bytes, 0, bytes.Length);
+ }
+
+ public static byte[] UrlEncodeToBytes(byte[] bytes)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ if (bytes.Length == 0)
+ {
+ return new byte[0];
+ }
+
+ return UrlEncodeToBytes(bytes, 0, bytes.Length);
+ }
+
+ private static bool NotEncoded(char c)
+ {
+ return (c == '!' || c == '\'' || c == '(' || c == ')' || c == '*' || c == '-' || c == '.' || c == '_');
+ }
+
+ private static void UrlEncodeChar(char c, Stream result, bool isUnicode)
+ {
+ if (c > 255)
+ {
+ //FIXME: what happens when there is an internal error?
+ //if (!isUnicode)
+ // throw new ArgumentOutOfRangeException ("c", c, "c must be less than 256");
+ int i = c;
+
+ result.WriteByte((byte) '%');
+ result.WriteByte((byte) 'u');
+ var idx = i >> 12;
+ result.WriteByte((byte) hexChars[idx]);
+ idx = (i >> 8) & 0x0F;
+ result.WriteByte((byte) hexChars[idx]);
+ idx = (i >> 4) & 0x0F;
+ result.WriteByte((byte) hexChars[idx]);
+ idx = i & 0x0F;
+ result.WriteByte((byte) hexChars[idx]);
+ return;
+ }
+
+ if (c > ' ' && NotEncoded(c))
+ {
+ result.WriteByte((byte) c);
+ return;
+ }
+ if (c == ' ')
+ {
+ result.WriteByte((byte) '+');
+ return;
+ }
+ if ((c < '0') ||
+ (c < 'A' && c > '9') ||
+ (c > 'Z' && c < 'a') ||
+ (c > 'z'))
+ {
+ if (isUnicode && c > 127)
+ {
+ result.WriteByte((byte) '%');
+ result.WriteByte((byte) 'u');
+ result.WriteByte((byte) '0');
+ result.WriteByte((byte) '0');
+ }
+ else
+ {
+ result.WriteByte((byte) '%');
+ }
+
+ var idx = (c) >> 4;
+ result.WriteByte((byte) hexChars[idx]);
+ idx = (c) & 0x0F;
+ result.WriteByte((byte) hexChars[idx]);
+ }
+ else
+ {
+ result.WriteByte((byte) c);
+ }
+ }
+
+ public static byte[] UrlEncodeToBytes(byte[] bytes, int offset, int count)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ var len = bytes.Length;
+ if (len == 0)
+ {
+ return new byte[0];
+ }
+
+ if (offset < 0 || offset >= len)
+ {
+ throw new ArgumentOutOfRangeException("offset");
+ }
+
+ if (count < 0 || count > len - offset)
+ {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ var result = new MemoryStream(count);
+ var end = offset + count;
+ for (var i = offset; i < end; i++)
+ {
+ UrlEncodeChar((char) bytes[i], result, false);
+ }
+
+ return result.ToArray();
+ }
+
+ public static string UrlEncodeUnicode(string str)
+ {
+ if (str == null)
+ {
+ return null;
+ }
+
+ var bytes = UrlEncodeUnicodeToBytes(str);
+ return Encoding.ASCII.GetString(bytes, 0, bytes.Length);
+ }
+
+ public static byte[] UrlEncodeUnicodeToBytes(string str)
+ {
+ if (str == null)
+ {
+ return null;
+ }
+
+ if (str == "")
+ {
+ return new byte[0];
+ }
+
+ var result = new MemoryStream(str.Length);
+ foreach (var c in str)
+ {
+ UrlEncodeChar(c, result, true);
+ }
+ return result.ToArray();
+ }
+
+ /// <summary>
+ /// Decodes an HTML-encoded string and returns the decoded string.
+ /// </summary>
+ /// <param name="s">The HTML string to decode. </param>
+ /// <returns>The decoded text.</returns>
+ public static string HtmlDecode(string s)
+ {
+ if (s == null)
+ {
+ throw new ArgumentNullException("s");
+ }
+
+ if (s.IndexOf('&') == -1)
+ {
+ return s;
+ }
+
+ var entity = new StringBuilder();
+ var output = new StringBuilder();
+ var len = s.Length;
+ // 0 -> nothing,
+ // 1 -> right after '&'
+ // 2 -> between '&' and ';' but no '#'
+ // 3 -> '#' found after '&' and getting numbers
+ var state = 0;
+ var number = 0;
+ var have_trailing_digits = false;
+
+ for (var i = 0; i < len; i++)
+ {
+ var c = s[i];
+ if (state == 0)
+ {
+ if (c == '&')
+ {
+ entity.Append(c);
+ state = 1;
+ }
+ else
+ {
+ output.Append(c);
+ }
+ continue;
+ }
+
+ if (c == '&')
+ {
+ state = 1;
+ if (have_trailing_digits)
+ {
+ entity.Append(number.ToString(CultureInfo.InvariantCulture));
+ have_trailing_digits = false;
+ }
+
+ output.Append(entity.ToString());
+ entity.Length = 0;
+ entity.Append('&');
+ continue;
+ }
+
+ if (state == 1)
+ {
+ if (c == ';')
+ {
+ state = 0;
+ output.Append(entity.ToString());
+ output.Append(c);
+ entity.Length = 0;
+ }
+ else
+ {
+ number = 0;
+ state = c != '#' ? 2 : 3;
+ entity.Append(c);
+ }
+ }
+ else if (state == 2)
+ {
+ entity.Append(c);
+ if (c == ';')
+ {
+ var key = entity.ToString();
+ if (key.Length > 1 && Entities.ContainsKey(key.Substring(1, key.Length - 2)))
+ {
+ key = Entities[key.Substring(1, key.Length - 2)].ToString();
+ }
+
+ output.Append(key);
+ state = 0;
+ entity.Length = 0;
+ }
+ }
+ else if (state == 3)
+ {
+ if (c == ';')
+ {
+ if (number > 65535)
+ {
+ output.Append("&#");
+ output.Append(number.ToString(CultureInfo.InvariantCulture));
+ output.Append(";");
+ }
+ else
+ {
+ output.Append((char) number);
+ }
+ state = 0;
+ entity.Length = 0;
+ have_trailing_digits = false;
+ }
+ else if (Char.IsDigit(c))
+ {
+ number = number*10 + (c - '0');
+ have_trailing_digits = true;
+ }
+ else
+ {
+ state = 2;
+ if (have_trailing_digits)
+ {
+ entity.Append(number.ToString(CultureInfo.InvariantCulture));
+ have_trailing_digits = false;
+ }
+ entity.Append(c);
+ }
+ }
+ }
+
+ if (entity.Length > 0)
+ {
+ output.Append(entity.ToString());
+ }
+ else if (have_trailing_digits)
+ {
+ output.Append(number.ToString(CultureInfo.InvariantCulture));
+ }
+ return output.ToString();
+ }
+
+ /// <summary>
+ /// Decodes an HTML-encoded string and sends the resulting output to a TextWriter output stream.
+ /// </summary>
+ /// <param name="s">The HTML string to decode</param>
+ /// <param name="output">The TextWriter output stream containing the decoded string. </param>
+ public static void HtmlDecode(string s, TextWriter output)
+ {
+ if (s != null)
+ {
+ output.Write(HtmlDecode(s));
+ }
+ }
+
+ /// <summary>
+ /// HTML-encodes a string and returns the encoded string.
+ /// </summary>
+ /// <param name="s">The text string to encode. </param>
+ /// <returns>The HTML-encoded text.</returns>
+ public static string HtmlEncode(string s)
+ {
+ if (s == null)
+ {
+ return null;
+ }
+
+ var needEncode = false;
+ for (var i = 0; i < s.Length; i++)
+ {
+ var c = s[i];
+ if (c == '&' || c == '"' || c == '<' || c == '>' || c > 159)
+ {
+ needEncode = true;
+ break;
+ }
+ }
+
+ if (!needEncode)
+ {
+ return s;
+ }
+
+ var output = new StringBuilder();
+
+ var len = s.Length;
+ for (var i = 0; i < len; i++)
+ {
+ switch (s[i])
+ {
+ case '&':
+ output.Append("&");
+ break;
+ case '>':
+ output.Append(">");
+ break;
+ case '<':
+ output.Append("<");
+ break;
+ case '"':
+ output.Append(""");
+ break;
+ default:
+ // MS starts encoding with &# from 160 and stops at 255.
+ // We don't do that. One reason is the 65308/65310 unicode
+ // characters that look like '<' and '>'.
+#if TARGET_JVM
+ if (s [i] > 159 && s [i] < 256) {
+#else
+ if (s[i] > 159)
+ {
+#endif
+ output.Append("&#");
+ output.Append(((int) s[i]).ToString(CultureInfo.InvariantCulture));
+ output.Append(";");
+ }
+ else
+ {
+ output.Append(s[i]);
+ }
+ break;
+ }
+ }
+ return output.ToString();
+ }
+
+ /// <summary>
+ /// HTML-encodes a string and sends the resulting output to a TextWriter output stream.
+ /// </summary>
+ /// <param name="s">The string to encode. </param>
+ /// <param name="output">The TextWriter output stream containing the encoded string. </param>
+ public static void HtmlEncode(string s, TextWriter output)
+ {
+ if (s != null)
+ {
+ output.Write(HtmlEncode(s));
+ }
+ }
+
+ public static string UrlPathEncode(string s)
+ {
+ if (string.IsNullOrEmpty(s))
+ return s;
+
+ var result = new MemoryStream();
+ var length = s.Length;
+ for (var i = 0; i < length; i++)
+ {
+ UrlPathEncodeChar(s[i], result);
+ }
+
+ var bytes = result.ToArray();
+ return Encoding.ASCII.GetString(bytes, 0, bytes.Length);
+ }
+
+ private static void UrlPathEncodeChar(char c, Stream result)
+ {
+ if (c < 33 || c > 126)
+ {
+ var bIn = Encoding.UTF8.GetBytes(c.ToString());
+ for (var i = 0; i < bIn.Length; i++)
+ {
+ result.WriteByte((byte) '%');
+ var idx = bIn[i] >> 4;
+ result.WriteByte((byte) hexChars[idx]);
+ idx = bIn[i] & 0x0F;
+ result.WriteByte((byte) hexChars[idx]);
+ }
+ }
+ else if (c == ' ')
+ {
+ result.WriteByte((byte) '%');
+ result.WriteByte((byte) '2');
+ result.WriteByte((byte) '0');
+ }
+ else
+ result.WriteByte((byte) c);
+ }
+
+ public static NameValueCollection ParseQueryString(string query)
+ {
+ return ParseQueryString(query, Encoding.UTF8);
+ }
+
+ public static NameValueCollection ParseQueryString(string query, Encoding encoding)
+ {
+ if (query == null)
+ throw new ArgumentNullException("query");
+ if (encoding == null)
+ throw new ArgumentNullException("encoding");
+ if (query.Length == 0 || (query.Length == 1 && query[0] == '?'))
+ return new NameValueCollection();
+ if (query[0] == '?')
+ query = query.Substring(1);
+
+ var result = new NameValueCollection();
+ ParseQueryString(query, encoding, result);
+ return result;
+ }
+
+ internal static void ParseQueryString(string query, Encoding encoding, NameValueCollection result)
+ {
+ if (query.Length == 0)
+ {
+ return;
+ }
+
+ var decoded = HtmlDecode(query);
+ var decodedLength = decoded.Length;
+ var namePos = 0;
+ var first = true;
+ while (namePos <= decodedLength)
+ {
+ int valuePos = -1, valueEnd = -1;
+ for (var q = namePos; q < decodedLength; q++)
+ {
+ if (valuePos == -1 && decoded[q] == '=')
+ {
+ valuePos = q + 1;
+ }
+ else if (decoded[q] == '&')
+ {
+ valueEnd = q;
+ break;
+ }
+ }
+
+ if (first)
+ {
+ first = false;
+ if (decoded[namePos] == '?')
+ {
+ namePos++;
+ }
+ }
+
+ string name;
+ if (valuePos == -1)
+ {
+ name = null;
+ valuePos = namePos;
+ }
+ else
+ {
+ name = UrlDecode(decoded.Substring(namePos, valuePos - namePos - 1), encoding);
+ }
+ if (valueEnd < 0)
+ {
+ namePos = -1;
+ valueEnd = decoded.Length;
+ }
+ else
+ {
+ namePos = valueEnd + 1;
+ }
+ var value = UrlDecode(decoded.Substring(valuePos, valueEnd - valuePos), encoding);
+
+ result.Add(name, value);
+ if (namePos == -1)
+ {
+ break;
+ }
+ }
+ }
+
+ #endregion // Methods
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// System.Net.WebHeaderCollection
+//
+// Authors:
+// Lawrence Pit (loz@cable.a2000.nl)
+// Gonzalo Paniagua Javier (gonzalo@ximian.com)
+// Miguel de Icaza (miguel@novell.com)
+//
+// Copyright 2003 Ximian, Inc. (http://www.ximian.com)
+// Copyright 2007 Novell, Inc. (http://www.novell.com)
+//
+//
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Net;
+using System.Runtime.InteropServices;
+using System.Text;
+
+// See RFC 2068 par 4.2 Message Headers
+
+namespace Mono.Net
+{
+ [Serializable]
+ [ComVisible(true)]
+ public class WebHeaderCollection : NameValueCollection
+ {
+ private static readonly Hashtable _restricted;
+ private static readonly Hashtable _multiValue;
+
+ private static readonly char[] tspecials =
+ new[]
+ {
+ '(', ')', '<', '>', '@',
+ ',', ';', ':', '\\', '"',
+ '/', '[', ']', '?', '=',
+ '{', '}', ' ', '\t'
+ };
+
+ private readonly bool internallyCreated;
+
+ // Static Initializer
+
+ static WebHeaderCollection()
+ {
+ // the list of restricted header names as defined
+ // by the ms.net spec
+ _restricted = new Hashtable(StringComparer.InvariantCultureIgnoreCase)
+ {
+ {"accept", true},
+ {"connection", true},
+ {"content-length", true},
+ {"content-type", true},
+ {"date", true},
+ {"expect", true},
+ {"host", true},
+ {"if-modified-since", true},
+ {"range", true},
+ {"referer", true},
+ {"transfer-encoding", true},
+ {"user-agent", true}
+ };
+
+ // see par 14 of RFC 2068 to see which header names
+ // accept multiple values each separated by a comma
+ _multiValue = new Hashtable(StringComparer.InvariantCultureIgnoreCase)
+ {
+ {"accept", true},
+ {"accept-charset", true},
+ {"accept-encoding", true},
+ {"accept-language", true},
+ {"accept-ranges", true},
+ {"allow", true},
+ {"authorization", true},
+ {"cache-control", true},
+ {"connection", true},
+ {"content-encoding", true},
+ {"content-language", true},
+ {"expect", true},
+ {"if-match", true},
+ {"if-none-match", true},
+ {"proxy-authenticate", true},
+ {"public", true},
+ {"range", true},
+ {"transfer-encoding", true},
+ {"upgrade", true},
+ {"vary", true},
+ {"via", true},
+ {"warning", true},
+ {"www-authenticate", true},
+ {"set-cookie", true},
+ {"set-cookie2", true}
+ };
+
+ // Extra
+ }
+
+ // Constructors
+
+ public WebHeaderCollection()
+ {
+ }
+
+ internal WebHeaderCollection(bool internallyCreated)
+ {
+ this.internallyCreated = internallyCreated;
+ }
+
+ public override string[] AllKeys
+ {
+ get { return (base.AllKeys); }
+ }
+
+ public override int Count
+ {
+ get { return (base.Count); }
+ }
+
+ public override KeysCollection Keys
+ {
+ get { return (base.Keys); }
+ }
+
+ public string this[HttpRequestHeader hrh]
+ {
+ get { return Get(RequestHeaderToString(hrh)); }
+
+ set { Add(RequestHeaderToString(hrh), value); }
+ }
+
+ public string this[HttpResponseHeader hrh]
+ {
+ get { return Get(ResponseHeaderToString(hrh)); }
+
+ set { Add(ResponseHeaderToString(hrh), value); }
+ }
+
+ // Methods
+
+ public void Add(string header)
+ {
+ if (header == null)
+ throw new ArgumentNullException("header");
+ var pos = header.IndexOf(':');
+ if (pos == -1)
+ throw new ArgumentException("no colon found", "header");
+ Add(header.Substring(0, pos),
+ header.Substring(pos + 1));
+ }
+
+ public override void Add(string name, string value)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+ if (internallyCreated && IsRestricted(name))
+ throw new ArgumentException("This header must be modified with the appropiate property.");
+ AddWithoutValidate(name, value);
+ }
+
+ protected void AddWithoutValidate(string headerName, string headerValue)
+ {
+ if (!IsHeaderName(headerName))
+ throw new ArgumentException("invalid header name: " + headerName, "headerName");
+ headerValue = headerValue == null ? String.Empty : headerValue.Trim();
+ if (!IsHeaderValue(headerValue))
+ throw new ArgumentException("invalid header value: " + headerValue, "headerValue");
+ base.Add(headerName, headerValue);
+ }
+
+ public override string[] GetValues(string header)
+ {
+ if (header == null)
+ throw new ArgumentNullException("header");
+
+ var values = base.GetValues(header);
+ if (values == null || values.Length == 0)
+ return null;
+
+ /*
+ if (IsMultiValue (header)) {
+ values = GetMultipleValues (values);
+ }
+ */
+
+ return values;
+ }
+
+ public override string[] GetValues(int index)
+ {
+ var values = base.GetValues(index);
+ if (values == null || values.Length == 0)
+ {
+ return (null);
+ }
+
+ return (values);
+ }
+
+ /* Now i wonder why this is here...
+ static string [] GetMultipleValues (string [] values)
+ {
+ ArrayList mvalues = new ArrayList (values.Length);
+ StringBuilder sb = null;
+ for (int i = 0; i < values.Length; ++i) {
+ string val = values [i];
+ if (val.IndexOf (',') == -1) {
+ mvalues.Add (val);
+ continue;
+ }
+
+ if (sb == null)
+ sb = new StringBuilder ();
+
+ bool quote = false;
+ for (int k = 0; k < val.Length; k++) {
+ char c = val [k];
+ if (c == '"') {
+ quote = !quote;
+ } else if (!quote && c == ',') {
+ mvalues.Add (sb.ToString ().Trim ());
+ sb.Length = 0;
+ continue;
+ }
+ sb.Append (c);
+ }
+
+ if (sb.Length > 0) {
+ mvalues.Add (sb.ToString ().Trim ());
+ sb.Length = 0;
+ }
+ }
+
+ return (string []) mvalues.ToArray (typeof (string));
+ }
+ */
+
+ public static bool IsRestricted(string headerName)
+ {
+ if (headerName == null)
+ throw new ArgumentNullException("headerName");
+
+ if (headerName == "") // MS throw nullexception here!
+ throw new ArgumentException("empty string", "headerName");
+
+ return _restricted.ContainsKey(headerName);
+ }
+
+ public static bool IsRestricted(string headerName, bool response)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void Remove(string name)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+ if (internallyCreated && IsRestricted(name))
+ throw new ArgumentException("restricted header");
+ base.Remove(name);
+ }
+
+ public override void Set(string name, string value)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+ if (internallyCreated && IsRestricted(name))
+ throw new ArgumentException("restricted header");
+ if (!IsHeaderName(name))
+ throw new ArgumentException("invalid header name");
+ value = value == null ? String.Empty : value.Trim();
+ if (!IsHeaderValue(value))
+ throw new ArgumentException("invalid header value");
+ base.Set(name, value);
+ }
+
+ public byte[] ToByteArray()
+ {
+ return Encoding.UTF8.GetBytes(ToString());
+ }
+
+ public override string ToString()
+ {
+ var sb = new StringBuilder();
+
+ var count = base.Count;
+ for (var i = 0; i < count; i++)
+ sb.Append(GetKey(i))
+ .Append(": ")
+ .Append(Get(i))
+ .Append("\r\n");
+
+ return sb.Append("\r\n").ToString();
+ }
+
+ public override string Get(int index)
+ {
+ return (base.Get(index));
+ }
+
+ public override string Get(string name)
+ {
+ return (base.Get(name));
+ }
+
+ public override string GetKey(int index)
+ {
+ return (base.GetKey(index));
+ }
+
+ public void Add(HttpRequestHeader header, string value)
+ {
+ Add(RequestHeaderToString(header), value);
+ }
+
+ public void Remove(HttpRequestHeader header)
+ {
+ Remove(RequestHeaderToString(header));
+ }
+
+ public void Set(HttpRequestHeader header, string value)
+ {
+ Set(RequestHeaderToString(header), value);
+ }
+
+ public void Add(HttpResponseHeader header, string value)
+ {
+ Add(ResponseHeaderToString(header), value);
+ }
+
+ public void Remove(HttpResponseHeader header)
+ {
+ Remove(ResponseHeaderToString(header));
+ }
+
+ public void Set(HttpResponseHeader header, string value)
+ {
+ Set(ResponseHeaderToString(header), value);
+ }
+
+ private static string RequestHeaderToString(HttpRequestHeader value)
+ {
+ switch (value)
+ {
+ case HttpRequestHeader.CacheControl:
+ return "cache-control";
+ case HttpRequestHeader.Connection:
+ return "connection";
+ case HttpRequestHeader.Date:
+ return "date";
+ case HttpRequestHeader.KeepAlive:
+ return "keep-alive";
+ case HttpRequestHeader.Pragma:
+ return "pragma";
+ case HttpRequestHeader.Trailer:
+ return "trailer";
+ case HttpRequestHeader.TransferEncoding:
+ return "transfer-encoding";
+ case HttpRequestHeader.Upgrade:
+ return "upgrade";
+ case HttpRequestHeader.Via:
+ return "via";
+ case HttpRequestHeader.Warning:
+ return "warning";
+ case HttpRequestHeader.Allow:
+ return "allow";
+ case HttpRequestHeader.ContentLength:
+ return "content-length";
+ case HttpRequestHeader.ContentType:
+ return "content-type";
+ case HttpRequestHeader.ContentEncoding:
+ return "content-encoding";
+ case HttpRequestHeader.ContentLanguage:
+ return "content-language";
+ case HttpRequestHeader.ContentLocation:
+ return "content-location";
+ case HttpRequestHeader.ContentMd5:
+ return "content-md5";
+ case HttpRequestHeader.ContentRange:
+ return "content-range";
+ case HttpRequestHeader.Expires:
+ return "expires";
+ case HttpRequestHeader.LastModified:
+ return "last-modified";
+ case HttpRequestHeader.Accept:
+ return "accept";
+ case HttpRequestHeader.AcceptCharset:
+ return "accept-charset";
+ case HttpRequestHeader.AcceptEncoding:
+ return "accept-encoding";
+ case HttpRequestHeader.AcceptLanguage:
+ return "accept-language";
+ case HttpRequestHeader.Authorization:
+ return "authorization";
+ case HttpRequestHeader.Cookie:
+ return "cookie";
+ case HttpRequestHeader.Expect:
+ return "expect";
+ case HttpRequestHeader.From:
+ return "from";
+ case HttpRequestHeader.Host:
+ return "host";
+ case HttpRequestHeader.IfMatch:
+ return "if-match";
+ case HttpRequestHeader.IfModifiedSince:
+ return "if-modified-since";
+ case HttpRequestHeader.IfNoneMatch:
+ return "if-none-match";
+ case HttpRequestHeader.IfRange:
+ return "if-range";
+ case HttpRequestHeader.IfUnmodifiedSince:
+ return "if-unmodified-since";
+ case HttpRequestHeader.MaxForwards:
+ return "max-forwards";
+ case HttpRequestHeader.ProxyAuthorization:
+ return "proxy-authorization";
+ case HttpRequestHeader.Referer:
+ return "referer";
+ case HttpRequestHeader.Range:
+ return "range";
+ case HttpRequestHeader.Te:
+ return "te";
+ case HttpRequestHeader.Translate:
+ return "translate";
+ case HttpRequestHeader.UserAgent:
+ return "user-agent";
+ default:
+ throw new InvalidOperationException();
+ }
+ }
+
+
+ private static string ResponseHeaderToString(HttpResponseHeader value)
+ {
+ switch (value)
+ {
+ case HttpResponseHeader.CacheControl:
+ return "cache-control";
+ case HttpResponseHeader.Connection:
+ return "connection";
+ case HttpResponseHeader.Date:
+ return "date";
+ case HttpResponseHeader.KeepAlive:
+ return "keep-alive";
+ case HttpResponseHeader.Pragma:
+ return "pragma";
+ case HttpResponseHeader.Trailer:
+ return "trailer";
+ case HttpResponseHeader.TransferEncoding:
+ return "transfer-encoding";
+ case HttpResponseHeader.Upgrade:
+ return "upgrade";
+ case HttpResponseHeader.Via:
+ return "via";
+ case HttpResponseHeader.Warning:
+ return "warning";
+ case HttpResponseHeader.Allow:
+ return "allow";
+ case HttpResponseHeader.ContentLength:
+ return "content-length";
+ case HttpResponseHeader.ContentType:
+ return "content-type";
+ case HttpResponseHeader.ContentEncoding:
+ return "content-encoding";
+ case HttpResponseHeader.ContentLanguage:
+ return "content-language";
+ case HttpResponseHeader.ContentLocation:
+ return "content-location";
+ case HttpResponseHeader.ContentMd5:
+ return "content-md5";
+ case HttpResponseHeader.ContentRange:
+ return "content-range";
+ case HttpResponseHeader.Expires:
+ return "expires";
+ case HttpResponseHeader.LastModified:
+ return "last-modified";
+ case HttpResponseHeader.AcceptRanges:
+ return "accept-ranges";
+ case HttpResponseHeader.Age:
+ return "age";
+ case HttpResponseHeader.ETag:
+ return "etag";
+ case HttpResponseHeader.Location:
+ return "location";
+ case HttpResponseHeader.ProxyAuthenticate:
+ return "proxy-authenticate";
+ case HttpResponseHeader.RetryAfter:
+ return "RetryAfter";
+ case HttpResponseHeader.Server:
+ return "server";
+ case HttpResponseHeader.SetCookie:
+ return "set-cookie";
+ case HttpResponseHeader.Vary:
+ return "vary";
+ case HttpResponseHeader.WwwAuthenticate:
+ return "www-authenticate";
+ default:
+ throw new InvalidOperationException();
+ }
+ }
+
+ public override IEnumerator GetEnumerator()
+ {
+ return (base.GetEnumerator());
+ }
+
+ // Internal Methods
+
+ // With this we don't check for invalid characters in header. See bug #55994.
+ internal void SetInternal(string header)
+ {
+ var pos = header.IndexOf(':');
+ if (pos == -1)
+ throw new ArgumentException("no colon found", "header");
+
+ SetInternal(header.Substring(0, pos), header.Substring(pos + 1));
+ }
+
+ internal void SetInternal(string name, string value)
+ {
+ value = value == null ? String.Empty : value.Trim();
+ if (!IsHeaderValue(value))
+ throw new ArgumentException("invalid header value");
+
+ if (IsMultiValue(name))
+ {
+ base.Add(name, value);
+ }
+ else
+ {
+ base.Remove(name);
+ base.Set(name, value);
+ }
+ }
+
+ internal void RemoveAndAdd(string name, string value)
+ {
+ value = value == null ? String.Empty : value.Trim();
+
+ base.Remove(name);
+ base.Set(name, value);
+ }
+
+ internal void RemoveInternal(string name)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+ base.Remove(name);
+ }
+
+ internal static bool IsMultiValue(string headerName)
+ {
+ return !string.IsNullOrEmpty(headerName) && _multiValue.ContainsKey(headerName);
+ }
+
+ internal static bool IsHeaderValue(string value)
+ {
+ // TEXT any 8 bit value except CTL's (0-31 and 127)
+ // but including \r\n space and \t
+ // after a newline at least one space or \t must follow
+ // certain header fields allow comments ()
+
+ var len = value.Length;
+ for (var i = 0; i < len; i++)
+ {
+ var c = value[i];
+ if (c == 127)
+ return false;
+ if (c < 0x20 && (c != '\r' && c != '\n' && c != '\t'))
+ return false;
+ if (c == '\n' && ++i < len)
+ {
+ c = value[i];
+ if (c != ' ' && c != '\t')
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ internal static bool IsHeaderName(string name)
+ {
+ // token = 1*<any CHAR except CTLs or tspecials>
+ // tspecials = "(" | ")" | "<" | ">" | "@"
+ // | "," | ";" | ":" | "\" | <">
+ // | "/" | "[" | "]" | "?" | "="
+ // | "{" | "}" | SP | HT
+
+ if (string.IsNullOrEmpty(name))
+ return false;
+
+ var len = name.Length;
+ for (var i = 0; i < len; i++)
+ {
+ var c = name[i];
+ if (c < 0x20 || c >= 0x7f)
+ return false;
+ }
+
+ return name.IndexOfAny(tspecials) == -1;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Security;
+
+// 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("Hammock")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apitize")]
+[assembly: AssemblyProduct("Hammock")]
+[assembly: AssemblyCopyright("Copyright © Daniel Crenna and Jason Diller")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: AllowPartiallyTrustedCallers]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("31b4614f-f68c-481b-b56e-99fdeaec5c4e")]
+
+// 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 Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.50727</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{46AFFE9E-B0DF-4DE9-A1A3-1773E08DCB51}</ProjectGuid>
+ <ProjectTypeGuids>{A1591282-1198-4647-A2B1-27E5FF5F6F3B};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Hammock.Silverlight</RootNamespace>
+ <AssemblyName>Hammock.Silverlight</AssemblyName>
+ <TargetFrameworkIdentifier>Silverlight</TargetFrameworkIdentifier>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion>
+ <SilverlightApplication>false</SilverlightApplication>
+ <ValidateXaml>true</ValidateXaml>
+ <ThrowErrorsInValidation>true</ThrowErrorsInValidation>
+ </PropertyGroup>
+ <!-- This property group is only here to support building this project using the
+ MSBuild 3.5 toolset. In order to work correctly with this older toolset, it needs
+ to set the TargetFrameworkVersion to v3.5 -->
+ <PropertyGroup Condition="'$(MSBuildToolsVersion)' == '3.5'">
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\bin\lib\SL4\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;SILVERLIGHT,Silverlight,SL,SL4,NET40</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\bin\lib\sl4\</OutputPath>
+ <DefineConstants>TRACE;SILVERLIGHT,Silverlight,SL,SL4,NET40</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup>
+ <SignAssembly>true</SignAssembly>
+ </PropertyGroup>
+ <PropertyGroup>
+ <AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ClientProfiles|AnyCPU'">
+ <OutputPath>bin\ClientProfiles\</OutputPath>
+ <DefineConstants>TRACE;SILVERLIGHT,Silverlight,SL,SL4</DefineConstants>
+ <Optimize>true</Optimize>
+ <NoStdLib>true</NoStdLib>
+ <DebugType>pdbonly</DebugType>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <CodeAnalysisLogFile>..\..\..\bin\net40\Hammock.Silverlight.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+ <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+ <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+ <CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>
+ <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+ <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
+ <NoConfig>true</NoConfig>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Microsoft.CSharp, Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
+ <Reference Include="mscorlib" />
+ <Reference Include="System.Json, Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
+ <Reference Include="System.Runtime.Serialization" />
+ <Reference Include="System.Runtime.Serialization.Json, Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
+ <Reference Include="System.ServiceModel.Web" />
+ <Reference Include="System.Windows" />
+ <Reference Include="system" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml" />
+ <Reference Include="System.Net" />
+ <Reference Include="System.Windows.Browser" />
+ <Reference Include="System.Xml.Linq, Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\..\net35\Hammock.Silverlight\Compat\DecompressionMethods.cs">
+ <Link>Compat\DecompressionMethods.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock.Silverlight\Compat\GzipHttpWebResponse.cs">
+ <Link>Compat\GzipHttpWebResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock.Silverlight\Compat\NameValueCollection.cs">
+ <Link>Compat\NameValueCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock.Silverlight\Compat\Trace.cs">
+ <Link>Compat\Trace.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\INamedAttribute.cs">
+ <Link>Attributes\INamedAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\IValidatingAttribute.cs">
+ <Link>Attributes\IValidatingAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\EntityAttribute.cs">
+ <Link>Attributes\Specialized\EntityAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\HeaderAttribute.cs">
+ <Link>Attributes\Specialized\HeaderAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\ParameterAttribute.cs">
+ <Link>Attributes\Specialized\ParameterAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\UserAgentAttribute.cs">
+ <Link>Attributes\Specialized\UserAgentAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\BooleanToIntegerAttribute.cs">
+ <Link>Attributes\Validation\BooleanToIntegerAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\DateTimeFormatAttribute.cs">
+ <Link>Attributes\Validation\DateTimeFormatAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\RequiredAttribute.cs">
+ <Link>Attributes\Validation\RequiredAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\SpecificationAttribute.cs">
+ <Link>Attributes\Validation\SpecificationAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\ValidationAttribute.cs">
+ <Link>Attributes\Validation\ValidationAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\Basic\BasicAuthCredentials.cs">
+ <Link>Authentication\Basic\BasicAuthCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\IWebCredentials.cs">
+ <Link>Authentication\IWebCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthCredentials.cs">
+ <Link>Authentication\OAuth\OAuthCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthParameterHandling.cs">
+ <Link>Authentication\OAuth\OAuthParameterHandling.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthSignatureMethod.cs">
+ <Link>Authentication\OAuth\OAuthSignatureMethod.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthToken.cs">
+ <Link>Authentication\OAuth\OAuthToken.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthTools.cs">
+ <Link>Authentication\OAuth\OAuthTools.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthType.cs">
+ <Link>Authentication\OAuth\OAuthType.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWebQuery.cs">
+ <Link>Authentication\OAuth\OAuthWebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWebQueryInfo.cs">
+ <Link>Authentication\OAuth\OAuthWebQueryInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWorkflow.cs">
+ <Link>Authentication\OAuth\OAuthWorkflow.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheFactory.cs">
+ <Link>Caching\CacheFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheMode.cs">
+ <Link>Caching\CacheMode.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheOptions.cs">
+ <Link>Caching\CacheOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\ICache.cs">
+ <Link>Caching\ICache.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\SimpleCache.cs">
+ <Link>Caching\SimpleCache.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\CollectionExtensions.cs">
+ <Link>Extensions\CollectionExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\FormatExtensions.cs">
+ <Link>Extensions\FormatExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\OAuthExtensions.cs">
+ <Link>Extensions\OAuthExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\ObjectExtensions.cs">
+ <Link>Extensions\ObjectExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\ReflectionExtensions.cs">
+ <Link>Extensions\ReflectionExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\SpecificationExtensions.cs">
+ <Link>Extensions\SpecificationExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\StringExtensions.cs">
+ <Link>Extensions\StringExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\TimeExtensions.cs">
+ <Link>Extensions\TimeExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\WebExtensions.cs">
+ <Link>Extensions\WebExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\IRestClient.cs">
+ <Link>IRestClient.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Model\PropertyChangedBase.cs">
+ <Link>Model\PropertyChangedBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestBase.cs">
+ <Link>RestBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestCallback.cs">
+ <Link>RestCallback.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestClient.cs">
+ <Link>RestClient.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestRequest.cs">
+ <Link>RestRequest.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestResponse.cs">
+ <Link>RestResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\IRetryCondition.cs">
+ <Link>Retries\IRetryCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\IRetryCustomCondition.cs">
+ <Link>Retries\IRetryCustomCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\NetworkError.cs">
+ <Link>Retries\NetworkError.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryCustomCondition.cs">
+ <Link>Retries\RetryCustomCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryErrorCondition.cs">
+ <Link>Retries\RetryErrorCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryPolicy.cs">
+ <Link>Retries\RetryPolicy.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryResultCondition.cs">
+ <Link>Retries\RetryResultCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\DefaultJsonSerializer.cs">
+ <Link>Serialization\DefaultJsonSerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\HammockDataContractJsonSerializer.cs">
+ <Link>Serialization\HammockDataContractJsonSerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\HammockDataContractSerializer.cs">
+ <Link>Serialization\HammockDataContractSerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\IDeserializer.cs">
+ <Link>Serialization\IDeserializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\ISerializer.cs">
+ <Link>Serialization\ISerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\JsonParser.cs">
+ <Link>Serialization\JsonParser.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\Utf8Serializer.cs">
+ <Link>Serialization\Utf8Serializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\AndSpecification.cs">
+ <Link>Specifications\AndSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\CompositeSpecificationBase.cs">
+ <Link>Specifications\CompositeSpecificationBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\HammockSpecification.cs">
+ <Link>Specifications\HammockSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\ISpecification.cs">
+ <Link>Specifications\ISpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\NotSpecification.cs">
+ <Link>Specifications\NotSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\OrSpecification.cs">
+ <Link>Specifications\OrSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Streaming\StreamOptions.cs">
+ <Link>Streaming\StreamOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\IRateLimitingRule.cs">
+ <Link>Tasks\IRateLimitingRule.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\IRateLimitStatus.cs">
+ <Link>Tasks\IRateLimitStatus.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITaskOptions.cs">
+ <Link>Tasks\ITaskOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITaskState.cs">
+ <Link>Tasks\ITaskState.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITimedTask.cs">
+ <Link>Tasks\ITimedTask.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\RateLimitingRule.cs">
+ <Link>Tasks\RateLimitingRule.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\RateLimitType.cs">
+ <Link>Tasks\RateLimitType.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TaskOptions.cs">
+ <Link>Tasks\TaskOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TaskState.cs">
+ <Link>Tasks\TaskState.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TimedTask.cs">
+ <Link>Tasks\TimedTask.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Validation\ValidationException.cs">
+ <Link>Validation\ValidationException.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Validation\ValidEmailSpecification.cs">
+ <Link>Validation\ValidEmailSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\BasicAuthWebQuery.cs">
+ <Link>Web\BasicAuthWebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\GetOrDelete.cs">
+ <Link>Web\GetOrDelete.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\HttpCookieParameter.cs">
+ <Link>Web\HttpCookieParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\HttpPostParameter.cs">
+ <Link>Web\HttpPostParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\HttpPostParameterType.cs">
+ <Link>Web\HttpPostParameterType.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\IWebQueryInfo.cs">
+ <Link>Web\IWebQueryInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\IMockable.cs">
+ <Link>Web\Mocks\IMockable.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\IWebResponse.cs">
+ <Link>Web\Mocks\IWebResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockHttpWebRequest.cs">
+ <Link>Web\Mocks\MockHttpWebRequest.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockHttpWebResponse.cs">
+ <Link>Web\Mocks\MockHttpWebResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockWebRequestFactory.cs">
+ <Link>Web\Mocks\MockWebRequestFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Pair.cs">
+ <Link>Web\Pair.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\PostOrPut.cs">
+ <Link>Web\PostOrPut.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Triplet.cs">
+ <Link>Web\Triplet.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebCallback.cs">
+ <Link>Web\WebCallback.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebEntity.cs">
+ <Link>Web\WebEntity.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebHeader.cs">
+ <Link>Web\WebHeader.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebHeaderCollection.cs">
+ <Link>Web\WebHeaderCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebMethod.cs">
+ <Link>Web\WebMethod.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebPair.cs">
+ <Link>Web\WebPair.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebPairCollection.cs">
+ <Link>Web\WebPairCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebParameter.cs">
+ <Link>Web\WebParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebParameterCollection.cs">
+ <Link>Web\WebParameterCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQuery.Async.cs">
+ <Link>Web\WebQuery.Async.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQuery.cs">
+ <Link>Web\WebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryAsyncResult.cs">
+ <Link>Web\WebQueryAsyncResult.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryRequestEventArgs.cs">
+ <Link>Web\WebQueryRequestEventArgs.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryResponseEventArgs.cs">
+ <Link>Web\WebQueryResponseEventArgs.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryResult.cs">
+ <Link>Web\WebQueryResult.cs</Link>
+ </Compile>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\net35\Hammock\Attributes\Specialized\_Specialized.cd">
+ <Link>Attributes\Specialized\_Specialized.cd</Link>
+ </None>
+ <None Include="..\..\net35\Hammock\Attributes\Validation\_Validation.cd">
+ <Link>Attributes\Validation\_Validation.cd</Link>
+ </None>
+ <None Include="..\..\net35\Hammock\Authentication\OAuth\_OAuth.cd">
+ <Link>Authentication\OAuth\_OAuth.cd</Link>
+ </None>
+ <None Include="..\..\net35\Hammock\Authentication\_Authentication.cd">
+ <Link>Authentication\_Authentication.cd</Link>
+ </None>
+ <None Include="..\..\net35\Hammock\Caching\_Caching.cd">
+ <Link>Caching\_Caching.cd</Link>
+ </None>
+ <None Include="..\..\net35\Hammock\Model\_Model.cd">
+ <Link>Model\_Model.cd</Link>
+ </None>
+ <None Include="..\..\net35\Hammock\Retries\_Retries.cd">
+ <Link>Retries\_Retries.cd</Link>
+ </None>
+ <None Include="..\..\net35\Hammock\Tasks\_Tasks.cd">
+ <Link>Tasks\_Tasks.cd</Link>
+ </None>
+ <None Include="..\..\net35\Hammock\Web\Mocks\_Mocks.cd">
+ <Link>Web\Mocks\_Mocks.cd</Link>
+ </None>
+ <None Include="..\..\net35\Hammock\Web\_Web.cd">
+ <Link>Web\_Web.cd</Link>
+ </None>
+ <None Include="..\..\net35\Hammock\_Hammock.cd">
+ <Link>_Hammock.cd</Link>
+ </None>
+ <None Include="key.snk" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\ICSharpCode.SharpZipLib.Silverlight\ICSharpCode.SharpZipLib.Silverlight.csproj">
+ <Project>{5953279F-F478-4D5F-9906-03D56CE2DA2D}</Project>
+ <Name>ICSharpCode.SharpZipLib.Silverlight %28.NET 4.0\SharpZipLib\ICSharpCode.SharpZipLib.Silverlight%29</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\$(SilverlightVersion)\Microsoft.Silverlight.CSharp.targets" />
+ <ProjectExtensions>
+ <VisualStudio>
+ <FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
+ <SilverlightProjectProperties />
+ </FlavorProperties>
+ </VisualStudio>
+ </ProjectExtensions>
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
\ No newline at end of file
--- /dev/null
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 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("Hammock.Silverlight")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Hammock.Silverlight")]
+[assembly: AssemblyCopyright("Copyright © Daniel Crenna and Jason Diller")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("f1d5d65e-7ee4-4bd7-af97-7ee4668d51bc")]
+
+// 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.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>10.0.20506</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{3059FD1C-4B4B-4460-A0D4-53C84CCE6CAC}</ProjectGuid>
+ <ProjectTypeGuids>{C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Hammock.WindowsPhone</RootNamespace>
+ <AssemblyName>Hammock.WindowsPhone</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion>
+ <TargetFrameworkProfile>WindowsPhone</TargetFrameworkProfile>
+ <TargetFrameworkIdentifier>Silverlight</TargetFrameworkIdentifier>
+ <SilverlightApplication>false</SilverlightApplication>
+ <ValidateXaml>true</ValidateXaml>
+ <ThrowErrorsInValidation>true</ThrowErrorsInValidation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\bin\lib\WP7\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;SILVERLIGHT,Silverlight,WindowsPhone</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\bin\lib\sl4-wp\</OutputPath>
+ <DefineConstants>TRACE;SILVERLIGHT,Silverlight,SL,WindowsPhone,WINDOWS_PHONE</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ClientProfiles|AnyCPU'">
+ <OutputPath>bin\ClientProfiles\</OutputPath>
+ <DefineConstants>TRACE;SILVERLIGHT,Silverlight,SL,WindowsPhone</DefineConstants>
+ <Optimize>true</Optimize>
+ <NoStdLib>true</NoStdLib>
+ <DebugType>pdbonly</DebugType>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <CodeAnalysisLogFile>..\..\..\bin\net40\Hammock.WindowsPhone.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+ <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+ <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+ <CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>
+ <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+ <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="mscorlib" />
+ <Reference Include="System.Runtime.Serialization" />
+ <Reference Include="System.Servicemodel.Web" />
+ <Reference Include="System.Windows" />
+ <Reference Include="system" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml" />
+ <Reference Include="System.Net" />
+ <Reference Include="System.Xml.Linq" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\..\net35\Hammock.Silverlight\Compat\GzipHttpWebResponse.cs">
+ <Link>Compat\GzipHttpWebResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\INamedAttribute.cs">
+ <Link>Attributes\INamedAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\IValidatingAttribute.cs">
+ <Link>Attributes\IValidatingAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock.Silverlight\Compat\DecompressionMethods.cs">
+ <Link>Compat\DecompressionMethods.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock.Silverlight\Compat\NameValueCollection.cs">
+ <Link>Compat\NameValueCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock.Silverlight\Compat\Trace.cs">
+ <Link>Compat\Trace.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\EntityAttribute.cs">
+ <Link>Attributes\Specialized\EntityAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\HeaderAttribute.cs">
+ <Link>Attributes\Specialized\HeaderAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\ParameterAttribute.cs">
+ <Link>Attributes\Specialized\ParameterAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\UserAgentAttribute.cs">
+ <Link>Attributes\Specialized\UserAgentAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\BooleanToIntegerAttribute.cs">
+ <Link>Attributes\Validation\BooleanToIntegerAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\DateTimeFormatAttribute.cs">
+ <Link>Attributes\Validation\DateTimeFormatAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\RequiredAttribute.cs">
+ <Link>Attributes\Validation\RequiredAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\SpecificationAttribute.cs">
+ <Link>Attributes\Validation\SpecificationAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\ValidationAttribute.cs">
+ <Link>Attributes\Validation\ValidationAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\Basic\BasicAuthCredentials.cs">
+ <Link>Authentication\Basic\BasicAuthCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\IWebCredentials.cs">
+ <Link>Authentication\IWebCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthCredentials.cs">
+ <Link>Authentication\OAuth\OAuthCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthParameterHandling.cs">
+ <Link>Authentication\OAuth\OAuthParameterHandling.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthSignatureMethod.cs">
+ <Link>Authentication\OAuth\OAuthSignatureMethod.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthToken.cs">
+ <Link>Authentication\OAuth\OAuthToken.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthTools.cs">
+ <Link>Authentication\OAuth\OAuthTools.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthType.cs">
+ <Link>Authentication\OAuth\OAuthType.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWebQuery.cs">
+ <Link>Authentication\OAuth\OAuthWebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWebQueryInfo.cs">
+ <Link>Authentication\OAuth\OAuthWebQueryInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWorkflow.cs">
+ <Link>Authentication\OAuth\OAuthWorkflow.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheFactory.cs">
+ <Link>Caching\CacheFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheMode.cs">
+ <Link>Caching\CacheMode.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheOptions.cs">
+ <Link>Caching\CacheOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\ICache.cs">
+ <Link>Caching\ICache.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\SimpleCache.cs">
+ <Link>Caching\SimpleCache.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\CollectionExtensions.cs">
+ <Link>Extensions\CollectionExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\FormatExtensions.cs">
+ <Link>Extensions\FormatExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\OAuthExtensions.cs">
+ <Link>Extensions\OAuthExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\ObjectExtensions.cs">
+ <Link>Extensions\ObjectExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\ReflectionExtensions.cs">
+ <Link>Extensions\ReflectionExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\SpecificationExtensions.cs">
+ <Link>Extensions\SpecificationExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\StringExtensions.cs">
+ <Link>Extensions\StringExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\TimeExtensions.cs">
+ <Link>Extensions\TimeExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\WebExtensions.cs">
+ <Link>Extensions\WebExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Model\PropertyChangedBase.cs">
+ <Link>Model\PropertyChangedBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\ConnectionClosed.cs">
+ <Link>Retries\ConnectionClosed.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\IRetryCondition.cs">
+ <Link>Retries\IRetryCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\IRetryCustomCondition.cs">
+ <Link>Retries\IRetryCustomCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\NetworkError.cs">
+ <Link>Retries\NetworkError.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryCondition.cs">
+ <Link>Retries\RetryCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryCustomCondition.cs">
+ <Link>Retries\RetryCustomCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryErrorCondition.cs">
+ <Link>Retries\RetryErrorCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryPolicy.cs">
+ <Link>Retries\RetryPolicy.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryResultCondition.cs">
+ <Link>Retries\RetryResultCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\Timeout.cs">
+ <Link>Retries\Timeout.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\DefaultJsonSerializer.cs">
+ <Link>Serialization\DefaultJsonSerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\HammockDataContractJsonSerializer.cs">
+ <Link>Serialization\HammockDataContractJsonSerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\HammockDataContractSerializer.cs">
+ <Link>Serialization\HammockDataContractSerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\IDeserializer.cs">
+ <Link>Serialization\IDeserializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\ISerializer.cs">
+ <Link>Serialization\ISerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\JsonParser.cs">
+ <Link>Serialization\JsonParser.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\Utf8Serializer.cs">
+ <Link>Serialization\Utf8Serializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\AndSpecification.cs">
+ <Link>Specifications\AndSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\CompositeSpecificationBase.cs">
+ <Link>Specifications\CompositeSpecificationBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\HammockSpecification.cs">
+ <Link>Specifications\HammockSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\ISpecification.cs">
+ <Link>Specifications\ISpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\NotSpecification.cs">
+ <Link>Specifications\NotSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\OrSpecification.cs">
+ <Link>Specifications\OrSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Streaming\StreamOptions.cs">
+ <Link>Streaming\StreamOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\IRateLimitingRule.cs">
+ <Link>Tasks\IRateLimitingRule.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\IRateLimitStatus.cs">
+ <Link>Tasks\IRateLimitStatus.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITaskOptions.cs">
+ <Link>Tasks\ITaskOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITaskState.cs">
+ <Link>Tasks\ITaskState.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITimedTask.cs">
+ <Link>Tasks\ITimedTask.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\RateLimitingRule.cs">
+ <Link>Tasks\RateLimitingRule.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\RateLimitType.cs">
+ <Link>Tasks\RateLimitType.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TaskOptions.cs">
+ <Link>Tasks\TaskOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TaskState.cs">
+ <Link>Tasks\TaskState.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TimedTask.cs">
+ <Link>Tasks\TimedTask.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Validation\ValidationException.cs">
+ <Link>Validation\ValidationException.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Validation\ValidEmailSpecification.cs">
+ <Link>Validation\ValidEmailSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\BasicAuthWebQuery.cs">
+ <Link>Web\BasicAuthWebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\GetOrDelete.cs">
+ <Link>Web\GetOrDelete.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\HttpCookieParameter.cs">
+ <Link>Web\HttpCookieParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\HttpPostParameter.cs">
+ <Link>Web\HttpPostParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\HttpPostParameterType.cs">
+ <Link>Web\HttpPostParameterType.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\IWebQueryInfo.cs">
+ <Link>Web\IWebQueryInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\IMockable.cs">
+ <Link>Web\Mock\IMockable.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\IWebResponse.cs">
+ <Link>Web\Mock\IWebResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockHttpWebRequest.cs">
+ <Link>Web\Mock\MockHttpWebRequest.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockHttpWebResponse.cs">
+ <Link>Web\Mock\MockHttpWebResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockWebRequestFactory.cs">
+ <Link>Web\Mock\MockWebRequestFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Pair.cs">
+ <Link>Web\Pair.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\PostOrPut.cs">
+ <Link>Web\PostOrPut.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Triplet.cs">
+ <Link>Web\Triplet.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebCallback.cs">
+ <Link>Web\WebCallback.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebEntity.cs">
+ <Link>Web\WebEntity.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebHeader.cs">
+ <Link>Web\WebHeader.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebHeaderCollection.cs">
+ <Link>Web\WebHeaderCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebMethod.cs">
+ <Link>Web\WebMethod.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebPair.cs">
+ <Link>Web\WebPair.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebPairCollection.cs">
+ <Link>Web\WebPairCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebParameter.cs">
+ <Link>Web\WebParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebParameterCollection.cs">
+ <Link>Web\WebParameterCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQuery.Async.cs">
+ <Link>Web\WebQuery.Async.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQuery.cs">
+ <Link>Web\WebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryAsyncResult.cs">
+ <Link>Web\WebQueryAsyncResult.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryRequestEventArgs.cs">
+ <Link>Web\WebQueryRequestEventArgs.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryResponseEventArgs.cs">
+ <Link>Web\WebQueryResponseEventArgs.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryResult.cs">
+ <Link>Web\WebQueryResult.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\IRestClient.cs">
+ <Link>IRestClient.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestBase.cs">
+ <Link>RestBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestCallback.cs">
+ <Link>RestCallback.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestClient.cs">
+ <Link>RestClient.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestRequest.cs">
+ <Link>RestRequest.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestResponse.cs">
+ <Link>RestResponse.cs</Link>
+ </Compile>
+ <Compile Include="Mono\HttpUtility.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="..\..\net35\Hammock\Hammock.csproj">
+ <Link>Hammock.csproj</Link>
+ </Content>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\net35\Hammock\Retries\_Retries.cd">
+ <Link>Retries\_Retries.cd</Link>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\ICSharpCode.SharpZipLib.WindowsPhone\ICSharpCode.SharpZipLib.WindowsPhone.csproj">
+ <Project>{BF04A546-D681-4F5A-AC41-CFC67CAEC66E}</Project>
+ <Name>ICSharpCode.SharpZipLib.WindowsPhone</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.$(TargetFrameworkProfile).Overrides.targets" />
+ <Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.CSharp.targets" />
+ <ProjectExtensions />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
\ No newline at end of file
--- /dev/null
+using System.Globalization;
+using System.IO;
+using System.Text;
+using System.Collections.Generic;
+
+#if SILVERLIGHT
+using Hammock.Silverlight.Compat;
+#endif
+
+namespace System.Web
+{
+ public sealed class HttpUtility
+ {
+ #region Fields
+
+ private static Dictionary<string, string> entities;
+ private static readonly object lock_ = new object();
+
+ #endregion // Fields
+
+ private static Dictionary<string, string> Entities
+ {
+ get
+ {
+ lock (lock_)
+ {
+ if (entities == null)
+ {
+ InitEntities();
+ }
+
+ return entities;
+ }
+ }
+ }
+
+ #region Constructors
+
+ private static void InitEntities()
+ {
+ // Build the hash table of HTML entity references. This list comes
+ // from the HTML 4.01 W3C recommendation.
+ entities = new Dictionary<string, string>
+ {
+ {"nbsp", "\u00A0"},
+ {"iexcl", "\u00A1"},
+ {"cent", "\u00A2"},
+ {"pound", "\u00A3"},
+ {"curren", "\u00A4"},
+ {"yen", "\u00A5"},
+ {"brvbar", "\u00A6"},
+ {"sect", "\u00A7"},
+ {"uml", "\u00A8"},
+ {"copy", "\u00A9"},
+ {"ordf", "\u00AA"},
+ {"laquo", "\u00AB"},
+ {"not", "\u00AC"},
+ {"shy", "\u00AD"},
+ {"reg", "\u00AE"},
+ {"macr", "\u00AF"},
+ {"deg", "\u00B0"},
+ {"plusmn", "\u00B1"},
+ {"sup2", "\u00B2"},
+ {"sup3", "\u00B3"},
+ {"acute", "\u00B4"},
+ {"micro", "\u00B5"},
+ {"para", "\u00B6"},
+ {"middot", "\u00B7"},
+ {"cedil", "\u00B8"},
+ {"sup1", "\u00B9"},
+ {"ordm", "\u00BA"},
+ {"raquo", "\u00BB"},
+ {"frac14", "\u00BC"},
+ {"frac12", "\u00BD"},
+ {"frac34", "\u00BE"},
+ {"iquest", "\u00BF"},
+ {"Agrave", "\u00C0"},
+ {"Aacute", "\u00C1"},
+ {"Acirc", "\u00C2"},
+ {"Atilde", "\u00C3"},
+ {"Auml", "\u00C4"},
+ {"Aring", "\u00C5"},
+ {"AElig", "\u00C6"},
+ {"Ccedil", "\u00C7"},
+ {"Egrave", "\u00C8"},
+ {"Eacute", "\u00C9"},
+ {"Ecirc", "\u00CA"},
+ {"Euml", "\u00CB"},
+ {"Igrave", "\u00CC"},
+ {"Iacute", "\u00CD"},
+ {"Icirc", "\u00CE"},
+ {"Iuml", "\u00CF"},
+ {"ETH", "\u00D0"},
+ {"Ntilde", "\u00D1"},
+ {"Ograve", "\u00D2"},
+ {"Oacute", "\u00D3"},
+ {"Ocirc", "\u00D4"},
+ {"Otilde", "\u00D5"},
+ {"Ouml", "\u00D6"},
+ {"times", "\u00D7"},
+ {"Oslash", "\u00D8"},
+ {"Ugrave", "\u00D9"},
+ {"Uacute", "\u00DA"},
+ {"Ucirc", "\u00DB"},
+ {"Uuml", "\u00DC"},
+ {"Yacute", "\u00DD"},
+ {"THORN", "\u00DE"},
+ {"szlig", "\u00DF"},
+ {"agrave", "\u00E0"},
+ {"aacute", "\u00E1"},
+ {"acirc", "\u00E2"},
+ {"atilde", "\u00E3"},
+ {"auml", "\u00E4"},
+ {"aring", "\u00E5"},
+ {"aelig", "\u00E6"},
+ {"ccedil", "\u00E7"},
+ {"egrave", "\u00E8"},
+ {"eacute", "\u00E9"},
+ {"ecirc", "\u00EA"},
+ {"euml", "\u00EB"},
+ {"igrave", "\u00EC"},
+ {"iacute", "\u00ED"},
+ {"icirc", "\u00EE"},
+ {"iuml", "\u00EF"},
+ {"eth", "\u00F0"},
+ {"ntilde", "\u00F1"},
+ {"ograve", "\u00F2"},
+ {"oacute", "\u00F3"},
+ {"ocirc", "\u00F4"},
+ {"otilde", "\u00F5"},
+ {"ouml", "\u00F6"},
+ {"divide", "\u00F7"},
+ {"oslash", "\u00F8"},
+ {"ugrave", "\u00F9"},
+ {"uacute", "\u00FA"},
+ {"ucirc", "\u00FB"},
+ {"uuml", "\u00FC"},
+ {"yacute", "\u00FD"},
+ {"thorn", "\u00FE"},
+ {"yuml", "\u00FF"},
+ {"fnof", "\u0192"},
+ {"Alpha", "\u0391"},
+ {"Beta", "\u0392"},
+ {"Gamma", "\u0393"},
+ {"Delta", "\u0394"},
+ {"Epsilon", "\u0395"},
+ {"Zeta", "\u0396"},
+ {"Eta", "\u0397"},
+ {"Theta", "\u0398"},
+ {"Iota", "\u0399"},
+ {"Kappa", "\u039A"},
+ {"Lambda", "\u039B"},
+ {"Mu", "\u039C"},
+ {"Nu", "\u039D"},
+ {"Xi", "\u039E"},
+ {"Omicron", "\u039F"},
+ {"Pi", "\u03A0"},
+ {"Rho", "\u03A1"},
+ {"Sigma", "\u03A3"},
+ {"Tau", "\u03A4"},
+ {"Upsilon", "\u03A5"},
+ {"Phi", "\u03A6"},
+ {"Chi", "\u03A7"},
+ {"Psi", "\u03A8"},
+ {"Omega", "\u03A9"},
+ {"alpha", "\u03B1"},
+ {"beta", "\u03B2"},
+ {"gamma", "\u03B3"},
+ {"delta", "\u03B4"},
+ {"epsilon", "\u03B5"},
+ {"zeta", "\u03B6"},
+ {"eta", "\u03B7"},
+ {"theta", "\u03B8"},
+ {"iota", "\u03B9"},
+ {"kappa", "\u03BA"},
+ {"lambda", "\u03BB"},
+ {"mu", "\u03BC"},
+ {"nu", "\u03BD"},
+ {"xi", "\u03BE"},
+ {"omicron", "\u03BF"},
+ {"pi", "\u03C0"},
+ {"rho", "\u03C1"},
+ {"sigmaf", "\u03C2"},
+ {"sigma", "\u03C3"},
+ {"tau", "\u03C4"},
+ {"upsilon", "\u03C5"},
+ {"phi", "\u03C6"},
+ {"chi", "\u03C7"},
+ {"psi", "\u03C8"},
+ {"omega", "\u03C9"},
+ {"thetasym", "\u03D1"},
+ {"upsih", "\u03D2"},
+ {"piv", "\u03D6"},
+ {"bull", "\u2022"},
+ {"hellip", "\u2026"},
+ {"prime", "\u2032"},
+ {"Prime", "\u2033"},
+ {"oline", "\u203E"},
+ {"frasl", "\u2044"},
+ {"weierp", "\u2118"},
+ {"image", "\u2111"},
+ {"real", "\u211C"},
+ {"trade", "\u2122"},
+ {"alefsym", "\u2135"},
+ {"larr", "\u2190"},
+ {"uarr", "\u2191"},
+ {"rarr", "\u2192"},
+ {"darr", "\u2193"},
+ {"harr", "\u2194"},
+ {"crarr", "\u21B5"},
+ {"lArr", "\u21D0"},
+ {"uArr", "\u21D1"},
+ {"rArr", "\u21D2"},
+ {"dArr", "\u21D3"},
+ {"hArr", "\u21D4"},
+ {"forall", "\u2200"},
+ {"part", "\u2202"},
+ {"exist", "\u2203"},
+ {"empty", "\u2205"},
+ {"nabla", "\u2207"},
+ {"isin", "\u2208"},
+ {"notin", "\u2209"},
+ {"ni", "\u220B"},
+ {"prod", "\u220F"},
+ {"sum", "\u2211"},
+ {"minus", "\u2212"},
+ {"lowast", "\u2217"},
+ {"radic", "\u221A"},
+ {"prop", "\u221D"},
+ {"infin", "\u221E"},
+ {"ang", "\u2220"},
+ {"and", "\u2227"},
+ {"or", "\u2228"},
+ {"cap", "\u2229"},
+ {"cup", "\u222A"},
+ {"int", "\u222B"},
+ {"there4", "\u2234"},
+ {"sim", "\u223C"},
+ {"cong", "\u2245"},
+ {"asymp", "\u2248"},
+ {"ne", "\u2260"},
+ {"equiv", "\u2261"},
+ {"le", "\u2264"},
+ {"ge", "\u2265"},
+ {"sub", "\u2282"},
+ {"sup", "\u2283"},
+ {"nsub", "\u2284"},
+ {"sube", "\u2286"},
+ {"supe", "\u2287"},
+ {"oplus", "\u2295"},
+ {"otimes", "\u2297"},
+ {"perp", "\u22A5"},
+ {"sdot", "\u22C5"},
+ {"lceil", "\u2308"},
+ {"rceil", "\u2309"},
+ {"lfloor", "\u230A"},
+ {"rfloor", "\u230B"},
+ {"lang", "\u2329"},
+ {"rang", "\u232A"},
+ {"loz", "\u25CA"},
+ {"spades", "\u2660"},
+ {"clubs", "\u2663"},
+ {"hearts", "\u2665"},
+ {"diams", "\u2666"},
+ {"quot", "\u0022"},
+ {"amp", "\u0026"},
+ {"lt", "\u003C"},
+ {"gt", "\u003E"},
+ {"OElig", "\u0152"},
+ {"oelig", "\u0153"},
+ {"Scaron", "\u0160"},
+ {"scaron", "\u0161"},
+ {"Yuml", "\u0178"},
+ {"circ", "\u02C6"},
+ {"tilde", "\u02DC"},
+ {"ensp", "\u2002"},
+ {"emsp", "\u2003"},
+ {"thinsp", "\u2009"},
+ {"zwnj", "\u200C"},
+ {"zwj", "\u200D"},
+ {"lrm", "\u200E"},
+ {"rlm", "\u200F"},
+ {"ndash", "\u2013"},
+ {"mdash", "\u2014"},
+ {"lsquo", "\u2018"},
+ {"rsquo", "\u2019"},
+ {"sbquo", "\u201A"},
+ {"ldquo", "\u201C"},
+ {"rdquo", "\u201D"},
+ {"bdquo", "\u201E"},
+ {"dagger", "\u2020"},
+ {"Dagger", "\u2021"},
+ {"permil", "\u2030"},
+ {"lsaquo", "\u2039"},
+ {"rsaquo", "\u203A"},
+ {"euro", "\u20AC"}
+ };
+ }
+
+ #endregion // Constructors
+
+ #region Methods
+
+ private static readonly char[] hexChars = "0123456789abcdef".ToCharArray();
+
+ public static void HtmlAttributeEncode(string s, TextWriter output)
+ {
+ output.Write(HtmlAttributeEncode(s));
+ }
+
+ public static string HtmlAttributeEncode(string s)
+ {
+ if (null == s)
+ {
+ return null;
+ }
+
+ var needEncode = false;
+ for (var i = 0; i < s.Length; i++)
+ {
+ if (s[i] == '&' || s[i] == '"' || s[i] == '<')
+ {
+ needEncode = true;
+ break;
+ }
+ }
+
+ if (!needEncode)
+ {
+ return s;
+ }
+
+ var output = new StringBuilder();
+ var len = s.Length;
+ for (var i = 0; i < len; i++)
+ {
+ switch (s[i])
+ {
+ case '&':
+ output.Append("&");
+ break;
+ case '"':
+ output.Append(""");
+ break;
+ case '<':
+ output.Append("<");
+ break;
+ default:
+ output.Append(s[i]);
+ break;
+ }
+ }
+
+ return output.ToString();
+ }
+
+ public static string UrlDecode(string str)
+ {
+ return UrlDecode(str, Encoding.UTF8);
+ }
+
+ private static char[] GetChars(MemoryStream b, Encoding e)
+ {
+ return e.GetChars(b.GetBuffer(), 0, (int) b.Length);
+ }
+
+ public static string UrlDecode(string s, Encoding e)
+ {
+ if (null == s)
+ {
+ return null;
+ }
+
+ if (s.IndexOf('%') == -1 && s.IndexOf('+') == -1)
+ {
+ return s;
+ }
+
+ if (e == null)
+ {
+ e = Encoding.UTF8;
+ }
+
+ var output = new StringBuilder();
+ long len = s.Length;
+ var bytes = new MemoryStream();
+
+ for (var i = 0; i < len; i++)
+ {
+ if (s[i] == '%' && i + 2 < len && s[i + 1] != '%')
+ {
+ int xchar;
+ if (s[i + 1] == 'u' && i + 5 < len)
+ {
+ if (bytes.Length > 0)
+ {
+ output.Append(GetChars(bytes, e));
+ bytes.SetLength(0);
+ }
+
+ xchar = GetChar(s, i + 2, 4);
+ if (xchar != -1)
+ {
+ output.Append((char) xchar);
+ i += 5;
+ }
+ else
+ {
+ output.Append('%');
+ }
+ }
+ else if ((xchar = GetChar(s, i + 1, 2)) != -1)
+ {
+ bytes.WriteByte((byte) xchar);
+ i += 2;
+ }
+ else
+ {
+ output.Append('%');
+ }
+ continue;
+ }
+
+ if (bytes.Length > 0)
+ {
+ output.Append(GetChars(bytes, e));
+ bytes.SetLength(0);
+ }
+
+ if (s[i] == '+')
+ {
+ output.Append(' ');
+ }
+ else
+ {
+ output.Append(s[i]);
+ }
+ }
+
+ if (bytes.Length > 0)
+ {
+ output.Append(GetChars(bytes, e));
+ }
+
+ return output.ToString();
+ }
+
+ public static string UrlDecode(byte[] bytes, Encoding e)
+ {
+ return bytes == null ? null : UrlDecode(bytes, 0, bytes.Length, e);
+ }
+
+ private static int GetInt(byte b)
+ {
+ var c = (char) b;
+ if (c >= '0' && c <= '9')
+ {
+ return c - '0';
+ }
+
+ if (c >= 'a' && c <= 'f')
+ {
+ return c - 'a' + 10;
+ }
+
+ if (c >= 'A' && c <= 'F')
+ {
+ return c - 'A' + 10;
+ }
+
+ return -1;
+ }
+
+ private static int GetChar(byte[] bytes, int offset, int length)
+ {
+ var value = 0;
+ var end = length + offset;
+ for (var i = offset; i < end; i++)
+ {
+ var current = GetInt(bytes[i]);
+ if (current == -1)
+ {
+ return -1;
+ }
+ value = (value << 4) + current;
+ }
+
+ return value;
+ }
+
+ private static int GetChar(string str, int offset, int length)
+ {
+ var val = 0;
+ var end = length + offset;
+ for (var i = offset; i < end; i++)
+ {
+ var c = str[i];
+ if (c > 127)
+ {
+ return -1;
+ }
+
+ var current = GetInt((byte) c);
+ if (current == -1)
+ {
+ return -1;
+ }
+ val = (val << 4) + current;
+ }
+
+ return val;
+ }
+
+ public static string UrlDecode(byte[] bytes, int offset, int count, Encoding e)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+ if (count == 0)
+ {
+ return String.Empty;
+ }
+
+ if (bytes == null)
+ {
+ throw new ArgumentNullException("bytes");
+ }
+
+ if (offset < 0 || offset > bytes.Length)
+ {
+ throw new ArgumentOutOfRangeException("offset");
+ }
+
+ if (count < 0 || offset + count > bytes.Length)
+ {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ var output = new StringBuilder();
+ var acc = new MemoryStream();
+
+ var end = count + offset;
+ for (var i = offset; i < end; i++)
+ {
+ if (bytes[i] == '%' && i + 2 < count && bytes[i + 1] != '%')
+ {
+ int xchar;
+ if (bytes[i + 1] == (byte) 'u' && i + 5 < end)
+ {
+ if (acc.Length > 0)
+ {
+ output.Append(GetChars(acc, e));
+ acc.SetLength(0);
+ }
+ xchar = GetChar(bytes, i + 2, 4);
+ if (xchar != -1)
+ {
+ output.Append((char) xchar);
+ i += 5;
+ continue;
+ }
+ }
+ else if ((xchar = GetChar(bytes, i + 1, 2)) != -1)
+ {
+ acc.WriteByte((byte) xchar);
+ i += 2;
+ continue;
+ }
+ }
+
+ if (acc.Length > 0)
+ {
+ output.Append(GetChars(acc, e));
+ acc.SetLength(0);
+ }
+
+ if (bytes[i] == '+')
+ {
+ output.Append(' ');
+ }
+ else
+ {
+ output.Append((char) bytes[i]);
+ }
+ }
+
+ if (acc.Length > 0)
+ {
+ output.Append(GetChars(acc, e));
+ }
+
+ return output.ToString();
+ }
+
+ public static byte[] UrlDecodeToBytes(byte[] bytes)
+ {
+ return bytes == null ? null : UrlDecodeToBytes(bytes, 0, bytes.Length);
+ }
+
+ public static byte[] UrlDecodeToBytes(string str)
+ {
+ return UrlDecodeToBytes(str, Encoding.UTF8);
+ }
+
+ public static byte[] UrlDecodeToBytes(string str, Encoding e)
+ {
+ if (str == null)
+ {
+ return null;
+ }
+
+ if (e == null)
+ {
+ throw new ArgumentNullException("e");
+ }
+
+ return UrlDecodeToBytes(e.GetBytes(str));
+ }
+
+ public static byte[] UrlDecodeToBytes(byte[] bytes, int offset, int count)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+ if (count == 0)
+ {
+ return new byte[0];
+ }
+
+ var len = bytes.Length;
+ if (offset < 0 || offset >= len)
+ {
+ throw new ArgumentOutOfRangeException("offset");
+ }
+
+ if (count < 0 || offset > len - count)
+ {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ var result = new MemoryStream();
+ var end = offset + count;
+ for (var i = offset; i < end; i++)
+ {
+ var c = (char) bytes[i];
+ if (c == '+')
+ {
+ c = ' ';
+ }
+ else if (c == '%' && i < end - 2)
+ {
+ var xchar = GetChar(bytes, i + 1, 2);
+ if (xchar != -1)
+ {
+ c = (char) xchar;
+ i += 2;
+ }
+ }
+ result.WriteByte((byte) c);
+ }
+
+ return result.ToArray();
+ }
+
+ public static string UrlEncode(string str)
+ {
+ return UrlEncode(str, Encoding.UTF8);
+ }
+
+ public static string UrlEncode(string s, Encoding Enc)
+ {
+ if (s == null)
+ {
+ return null;
+ }
+
+ if (s == "")
+ {
+ return "";
+ }
+
+ var needEncode = false;
+ var len = s.Length;
+ for (var i = 0; i < len; i++)
+ {
+ var c = s[i];
+ if ((c < '0') || (c < 'A' && c > '9') || (c > 'Z' && c < 'a') || (c > 'z'))
+ {
+ if (NotEncoded(c))
+ {
+ continue;
+ }
+
+ needEncode = true;
+ break;
+ }
+ }
+
+ if (!needEncode)
+ {
+ return s;
+ }
+
+ // avoided GetByteCount call
+ var bytes = new byte[Enc.GetMaxByteCount(s.Length)];
+ var realLen = Enc.GetBytes(s, 0, s.Length, bytes, 0);
+ return Encoding.UTF8.GetString(UrlEncodeToBytes(bytes, 0, realLen), 0, realLen);
+ }
+
+ public static string UrlEncode(byte[] bytes)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ if (bytes.Length == 0)
+ {
+ return "";
+ }
+
+ return Encoding.UTF8.GetString(UrlEncodeToBytes(bytes, 0, bytes.Length), 0, bytes.Length);
+ }
+
+ public static string UrlEncode(byte[] bytes, int offset, int count)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ if (bytes.Length == 0)
+ {
+ return "";
+ }
+
+ return Encoding.UTF8.GetString(UrlEncodeToBytes(bytes, offset, count), offset, count);
+ }
+
+ public static byte[] UrlEncodeToBytes(string str)
+ {
+ return UrlEncodeToBytes(str, Encoding.UTF8);
+ }
+
+ public static byte[] UrlEncodeToBytes(string str, Encoding e)
+ {
+ if (str == null)
+ {
+ return null;
+ }
+
+ if (str == "")
+ {
+ return new byte[0];
+ }
+
+ var bytes = e.GetBytes(str);
+ return UrlEncodeToBytes(bytes, 0, bytes.Length);
+ }
+
+ public static byte[] UrlEncodeToBytes(byte[] bytes)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ if (bytes.Length == 0)
+ {
+ return new byte[0];
+ }
+
+ return UrlEncodeToBytes(bytes, 0, bytes.Length);
+ }
+
+ private static bool NotEncoded(char c)
+ {
+ return (c == '!' || c == '\'' || c == '(' || c == ')' || c == '*' || c == '-' || c == '.' || c == '_');
+ }
+
+ private static void UrlEncodeChar(char c, Stream result, bool isUnicode)
+ {
+ if (c > 255)
+ {
+ //FIXME: what happens when there is an internal error?
+ //if (!isUnicode)
+ // throw new ArgumentOutOfRangeException ("c", c, "c must be less than 256");
+ int i = c;
+
+ result.WriteByte((byte) '%');
+ result.WriteByte((byte) 'u');
+ var idx = i >> 12;
+ result.WriteByte((byte) hexChars[idx]);
+ idx = (i >> 8) & 0x0F;
+ result.WriteByte((byte) hexChars[idx]);
+ idx = (i >> 4) & 0x0F;
+ result.WriteByte((byte) hexChars[idx]);
+ idx = i & 0x0F;
+ result.WriteByte((byte) hexChars[idx]);
+ return;
+ }
+
+ if (c > ' ' && NotEncoded(c))
+ {
+ result.WriteByte((byte) c);
+ return;
+ }
+ if (c == ' ')
+ {
+ result.WriteByte((byte) '+');
+ return;
+ }
+ if ((c < '0') ||
+ (c < 'A' && c > '9') ||
+ (c > 'Z' && c < 'a') ||
+ (c > 'z'))
+ {
+ if (isUnicode && c > 127)
+ {
+ result.WriteByte((byte) '%');
+ result.WriteByte((byte) 'u');
+ result.WriteByte((byte) '0');
+ result.WriteByte((byte) '0');
+ }
+ else
+ {
+ result.WriteByte((byte) '%');
+ }
+
+ var idx = (c) >> 4;
+ result.WriteByte((byte) hexChars[idx]);
+ idx = (c) & 0x0F;
+ result.WriteByte((byte) hexChars[idx]);
+ }
+ else
+ {
+ result.WriteByte((byte) c);
+ }
+ }
+
+ public static byte[] UrlEncodeToBytes(byte[] bytes, int offset, int count)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ var len = bytes.Length;
+ if (len == 0)
+ {
+ return new byte[0];
+ }
+
+ if (offset < 0 || offset >= len)
+ {
+ throw new ArgumentOutOfRangeException("offset");
+ }
+
+ if (count < 0 || count > len - offset)
+ {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ var result = new MemoryStream(count);
+ var end = offset + count;
+ for (var i = offset; i < end; i++)
+ {
+ UrlEncodeChar((char) bytes[i], result, false);
+ }
+
+ return result.ToArray();
+ }
+
+ public static string UrlEncodeUnicode(string str)
+ {
+ if (str == null)
+ {
+ return null;
+ }
+
+ var bytes = UrlEncodeUnicodeToBytes(str);
+ return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
+ }
+
+ public static byte[] UrlEncodeUnicodeToBytes(string str)
+ {
+ if (str == null)
+ {
+ return null;
+ }
+
+ if (str == "")
+ {
+ return new byte[0];
+ }
+
+ var result = new MemoryStream(str.Length);
+ foreach (var c in str)
+ {
+ UrlEncodeChar(c, result, true);
+ }
+ return result.ToArray();
+ }
+
+ /// <summary>
+ /// Decodes an HTML-encoded string and returns the decoded string.
+ /// </summary>
+ /// <param name="s">The HTML string to decode. </param>
+ /// <returns>The decoded text.</returns>
+ public static string HtmlDecode(string s)
+ {
+ if (s == null)
+ {
+ throw new ArgumentNullException("s");
+ }
+
+ if (s.IndexOf('&') == -1)
+ {
+ return s;
+ }
+
+ var entity = new StringBuilder();
+ var output = new StringBuilder();
+ var len = s.Length;
+ // 0 -> nothing,
+ // 1 -> right after '&'
+ // 2 -> between '&' and ';' but no '#'
+ // 3 -> '#' found after '&' and getting numbers
+ var state = 0;
+ var number = 0;
+ var have_trailing_digits = false;
+
+ for (var i = 0; i < len; i++)
+ {
+ var c = s[i];
+ if (state == 0)
+ {
+ if (c == '&')
+ {
+ entity.Append(c);
+ state = 1;
+ }
+ else
+ {
+ output.Append(c);
+ }
+ continue;
+ }
+
+ if (c == '&')
+ {
+ state = 1;
+ if (have_trailing_digits)
+ {
+ entity.Append(number.ToString(CultureInfo.InvariantCulture));
+ have_trailing_digits = false;
+ }
+
+ output.Append(entity.ToString());
+ entity.Length = 0;
+ entity.Append('&');
+ continue;
+ }
+
+ if (state == 1)
+ {
+ if (c == ';')
+ {
+ state = 0;
+ output.Append(entity.ToString());
+ output.Append(c);
+ entity.Length = 0;
+ }
+ else
+ {
+ number = 0;
+ state = c != '#' ? 2 : 3;
+ entity.Append(c);
+ }
+ }
+ else if (state == 2)
+ {
+ entity.Append(c);
+ if (c == ';')
+ {
+ var key = entity.ToString();
+ if (key.Length > 1 && Entities.ContainsKey(key.Substring(1, key.Length - 2)))
+ {
+ key = Entities[key.Substring(1, key.Length - 2)].ToString();
+ }
+
+ output.Append(key);
+ state = 0;
+ entity.Length = 0;
+ }
+ }
+ else if (state == 3)
+ {
+ if (c == ';')
+ {
+ if (number > 65535)
+ {
+ output.Append("&#");
+ output.Append(number.ToString(CultureInfo.InvariantCulture));
+ output.Append(";");
+ }
+ else
+ {
+ output.Append((char) number);
+ }
+ state = 0;
+ entity.Length = 0;
+ have_trailing_digits = false;
+ }
+ else if (Char.IsDigit(c))
+ {
+ number = number*10 + (c - '0');
+ have_trailing_digits = true;
+ }
+ else
+ {
+ state = 2;
+ if (have_trailing_digits)
+ {
+ entity.Append(number.ToString(CultureInfo.InvariantCulture));
+ have_trailing_digits = false;
+ }
+ entity.Append(c);
+ }
+ }
+ }
+
+ if (entity.Length > 0)
+ {
+ output.Append(entity.ToString());
+ }
+ else if (have_trailing_digits)
+ {
+ output.Append(number.ToString(CultureInfo.InvariantCulture));
+ }
+ return output.ToString();
+ }
+
+ /// <summary>
+ /// Decodes an HTML-encoded string and sends the resulting output to a TextWriter output stream.
+ /// </summary>
+ /// <param name="s">The HTML string to decode</param>
+ /// <param name="output">The TextWriter output stream containing the decoded string. </param>
+ public static void HtmlDecode(string s, TextWriter output)
+ {
+ if (s != null)
+ {
+ output.Write(HtmlDecode(s));
+ }
+ }
+
+ /// <summary>
+ /// HTML-encodes a string and returns the encoded string.
+ /// </summary>
+ /// <param name="s">The text string to encode. </param>
+ /// <returns>The HTML-encoded text.</returns>
+ public static string HtmlEncode(string s)
+ {
+ if (s == null)
+ {
+ return null;
+ }
+
+ var needEncode = false;
+ for (var i = 0; i < s.Length; i++)
+ {
+ var c = s[i];
+ if (c == '&' || c == '"' || c == '<' || c == '>' || c > 159)
+ {
+ needEncode = true;
+ break;
+ }
+ }
+
+ if (!needEncode)
+ {
+ return s;
+ }
+
+ var output = new StringBuilder();
+
+ var len = s.Length;
+ for (var i = 0; i < len; i++)
+ {
+ switch (s[i])
+ {
+ case '&':
+ output.Append("&");
+ break;
+ case '>':
+ output.Append(">");
+ break;
+ case '<':
+ output.Append("<");
+ break;
+ case '"':
+ output.Append(""");
+ break;
+ default:
+ // MS starts encoding with &# from 160 and stops at 255.
+ // We don't do that. One reason is the 65308/65310 unicode
+ // characters that look like '<' and '>'.
+#if TARGET_JVM
+ if (s [i] > 159 && s [i] < 256) {
+#else
+ if (s[i] > 159)
+ {
+#endif
+ output.Append("&#");
+ output.Append(((int) s[i]).ToString(CultureInfo.InvariantCulture));
+ output.Append(";");
+ }
+ else
+ {
+ output.Append(s[i]);
+ }
+ break;
+ }
+ }
+ return output.ToString();
+ }
+
+ /// <summary>
+ /// HTML-encodes a string and sends the resulting output to a TextWriter output stream.
+ /// </summary>
+ /// <param name="s">The string to encode. </param>
+ /// <param name="output">The TextWriter output stream containing the encoded string. </param>
+ public static void HtmlEncode(string s, TextWriter output)
+ {
+ if (s != null)
+ {
+ output.Write(HtmlEncode(s));
+ }
+ }
+
+ public static string UrlPathEncode(string s)
+ {
+ if (string.IsNullOrEmpty(s))
+ return s;
+
+ var result = new MemoryStream();
+ var length = s.Length;
+ for (var i = 0; i < length; i++)
+ {
+ UrlPathEncodeChar(s[i], result);
+ }
+
+ var bytes = result.ToArray();
+ return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
+ }
+
+ private static void UrlPathEncodeChar(char c, Stream result)
+ {
+ if (c < 33 || c > 126)
+ {
+ var bIn = Encoding.UTF8.GetBytes(c.ToString());
+ for (var i = 0; i < bIn.Length; i++)
+ {
+ result.WriteByte((byte) '%');
+ var idx = bIn[i] >> 4;
+ result.WriteByte((byte) hexChars[idx]);
+ idx = bIn[i] & 0x0F;
+ result.WriteByte((byte) hexChars[idx]);
+ }
+ }
+ else if (c == ' ')
+ {
+ result.WriteByte((byte) '%');
+ result.WriteByte((byte) '2');
+ result.WriteByte((byte) '0');
+ }
+ else
+ result.WriteByte((byte) c);
+ }
+
+ public static NameValueCollection ParseQueryString(string query)
+ {
+ return ParseQueryString(query, Encoding.UTF8);
+ }
+
+ public static NameValueCollection ParseQueryString(string query, Encoding encoding)
+ {
+ if (query == null)
+ throw new ArgumentNullException("query");
+ if (encoding == null)
+ throw new ArgumentNullException("encoding");
+ if (query.Length == 0 || (query.Length == 1 && query[0] == '?'))
+ return new NameValueCollection();
+ if (query[0] == '?')
+ query = query.Substring(1);
+
+ var result = new NameValueCollection();
+ ParseQueryString(query, encoding, result);
+ return result;
+ }
+
+ internal static void ParseQueryString(string query, Encoding encoding, NameValueCollection result)
+ {
+ if (query.Length == 0)
+ {
+ return;
+ }
+
+ var decoded = HtmlDecode(query);
+ var decodedLength = decoded.Length;
+ var namePos = 0;
+ var first = true;
+ while (namePos <= decodedLength)
+ {
+ int valuePos = -1, valueEnd = -1;
+ for (var q = namePos; q < decodedLength; q++)
+ {
+ if (valuePos == -1 && decoded[q] == '=')
+ {
+ valuePos = q + 1;
+ }
+ else if (decoded[q] == '&')
+ {
+ valueEnd = q;
+ break;
+ }
+ }
+
+ if (first)
+ {
+ first = false;
+ if (decoded[namePos] == '?')
+ {
+ namePos++;
+ }
+ }
+
+ string name;
+ if (valuePos == -1)
+ {
+ name = null;
+ valuePos = namePos;
+ }
+ else
+ {
+ name = UrlDecode(decoded.Substring(namePos, valuePos - namePos - 1), encoding);
+ }
+ if (valueEnd < 0)
+ {
+ namePos = -1;
+ valueEnd = decoded.Length;
+ }
+ else
+ {
+ namePos = valueEnd + 1;
+ }
+ var value = UrlDecode(decoded.Substring(valuePos, valueEnd - valuePos), encoding);
+
+ result.Add(name, value);
+ if (namePos == -1)
+ {
+ break;
+ }
+ }
+ }
+
+ #endregion // Methods
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 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("Hammock.WindowsPhone")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Hammock.WindowsPhone")]
+[assembly: AssemblyCopyright("Copyright © Daniel Crenna and Jason Diller")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("4b494cbd-3b70-4aab-b4cf-f827066a1a6a")]
+
+// 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.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null
+// This file is used by Code Analysis to maintain SuppressMessage
+// attributes that are applied to this project.
+// Project-level suppressions either have no target or are given
+// a specific target and scoped to a namespace, type, member, etc.
+//
+// To add a suppression to this file, right-click the message in the
+// Error List, point to "Suppress Message(s)", and click
+// "In Project Suppression File".
+// You do not need to add suppressions to this file manually.
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors", Scope = "member", Target = "Hammock.RestResponseBase.#.ctor()")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2229:ImplementSerializationConstructors", Scope = "type", Target = "Mono.Net.WebHeaderCollection")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2229:ImplementSerializationConstructors", Scope = "type", Target = "Hammock.Web.Mocks.MockHttpWebResponse")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2229:ImplementSerializationConstructors", Scope = "type", Target = "Hammock.Web.Mocks.MockHttpWebRequest")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors", Scope = "member", Target = "Hammock.Web.WebQueryAsyncResult.#.ctor()")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors", Scope = "member", Target = "Hammock.Web.WebQuery.#.ctor(Hammock.Web.IWebQueryInfo)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Scope = "member", Target = "Hammock.Web.WebQuery.#EndStreaming(System.Net.WebRequest)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2240:ImplementISerializableCorrectly", Scope = "type", Target = "Mono.Net.WebHeaderCollection")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2240:ImplementISerializableCorrectly", Scope = "type", Target = "Hammock.Web.Mocks.MockHttpWebRequest")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2240:ImplementISerializableCorrectly", Scope = "type", Target = "Hammock.Web.Mocks.MockHttpWebResponse")]
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{CD569558-9092-466B-8670-EA1B151150E0}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Hammock</RootNamespace>
+ <AssemblyName>Hammock</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <TargetFrameworkProfile>
+ </TargetFrameworkProfile>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\bin\lib\4.0\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;NET40</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\bin\lib\net40\</OutputPath>
+ <DefineConstants>TRACE;NET40</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <RunCodeAnalysis>true</RunCodeAnalysis>
+ <CodeAnalysisIgnoreGeneratedCode>false</CodeAnalysisIgnoreGeneratedCode>
+ </PropertyGroup>
+ <PropertyGroup>
+ <SignAssembly>true</SignAssembly>
+ </PropertyGroup>
+ <PropertyGroup>
+ <AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ClientProfiles|AnyCPU'">
+ <OutputPath>bin\ClientProfiles\</OutputPath>
+ <DefineConstants>TRACE;NET40,ClientProfiles</DefineConstants>
+ <Optimize>true</Optimize>
+ <DebugType>pdbonly</DebugType>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <CodeAnalysisLogFile>..\..\..\bin\net40\Hammock.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+ <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+ <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+ <CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>
+ <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+ <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Runtime.Serialization" />
+ <Reference Include="System.Security" />
+ <Reference Include="System.ServiceModel" />
+ <Reference Include="System.ServiceModel.Web" />
+ <Reference Include="System.Web" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\..\net35\Hammock\Attributes\INamedAttribute.cs">
+ <Link>Attributes\INamedAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\IValidatingAttribute.cs">
+ <Link>Attributes\IValidatingAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\EntityAttribute.cs">
+ <Link>Attributes\Specialized\EntityAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\HeaderAttribute.cs">
+ <Link>Attributes\Specialized\HeaderAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\ParameterAttribute.cs">
+ <Link>Attributes\Specialized\ParameterAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\UserAgentAttribute.cs">
+ <Link>Attributes\Specialized\UserAgentAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\BooleanToIntegerAttribute.cs">
+ <Link>Attributes\Validation\BooleanToIntegerAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\DateTimeFormatAttribute.cs">
+ <Link>Attributes\Validation\DateTimeFormatAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\RequiredAttribute.cs">
+ <Link>Attributes\Validation\RequiredAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\SpecificationAttribute.cs">
+ <Link>Attributes\Validation\SpecificationAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\ValidationAttribute.cs">
+ <Link>Attributes\Validation\ValidationAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\Basic\BasicAuthCredentials.cs">
+ <Link>Authentication\Basic\BasicAuthCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\IWebCredentials.cs">
+ <Link>Authentication\IWebCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthCredentials.cs">
+ <Link>Authentication\OAuth\OAuthCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthParameterHandling.cs">
+ <Link>Authentication\OAuth\OAuthParameterHandling.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthSignatureMethod.cs">
+ <Link>Authentication\OAuth\OAuthSignatureMethod.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthToken.cs">
+ <Link>Authentication\OAuth\OAuthToken.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthTools.cs">
+ <Link>Authentication\OAuth\OAuthTools.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthType.cs">
+ <Link>Authentication\OAuth\OAuthType.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWebQuery.cs">
+ <Link>Authentication\OAuth\OAuthWebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWebQueryInfo.cs">
+ <Link>Authentication\OAuth\OAuthWebQueryInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWorkflow.cs">
+ <Link>Authentication\OAuth\OAuthWorkflow.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\AspNetCache.cs">
+ <Link>Caching\AspNetCache.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheFactory.cs">
+ <Link>Caching\CacheFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheMode.cs">
+ <Link>Caching\CacheMode.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheOptions.cs">
+ <Link>Caching\CacheOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\ICache.cs">
+ <Link>Caching\ICache.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\IDependencyCache.cs">
+ <Link>Caching\IDependencyCache.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\SimpleCache.cs">
+ <Link>Caching\SimpleCache.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\CollectionExtensions.cs">
+ <Link>Extensions\CollectionExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\FormatExtensions.cs">
+ <Link>Extensions\FormatExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\OAuthExtensions.cs">
+ <Link>Extensions\OAuthExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\ObjectExtensions.cs">
+ <Link>Extensions\ObjectExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\ReflectionExtensions.cs">
+ <Link>Extensions\ReflectionExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\SpecificationExtensions.cs">
+ <Link>Extensions\SpecificationExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\StringExtensions.cs">
+ <Link>Extensions\StringExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\TimeExtensions.cs">
+ <Link>Extensions\TimeExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\WebExtensions.cs">
+ <Link>Extensions\WebExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Model\PropertyChangedBase.cs">
+ <Link>Model\PropertyChangedBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\ConnectionClosed.cs">
+ <Link>Retries\ConnectionClosed.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\IRetryCondition.cs">
+ <Link>Retries\IRetryCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\IRetryCustomCondition.cs">
+ <Link>Retries\IRetryCustomCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\NetworkError.cs">
+ <Link>Retries\NetworkError.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryCondition.cs">
+ <Link>Retries\RetryCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryCustomCondition.cs">
+ <Link>Retries\RetryCustomCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryErrorCondition.cs">
+ <Link>Retries\RetryErrorCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryPolicy.cs">
+ <Link>Retries\RetryPolicy.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryResultCondition.cs">
+ <Link>Retries\RetryResultCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\Timeout.cs">
+ <Link>Retries\Timeout.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\DefaultJsonSerializer.cs">
+ <Link>Serialization\DefaultJsonSerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\HammockDataContractJsonSerializer.cs">
+ <Link>Serialization\HammockDataContractJsonSerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\HammockDataContractSerializer.cs">
+ <Link>Serialization\HammockDataContractSerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\HammockXmlSerializer.cs">
+ <Link>Serialization\HammockXmlSerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\IDeserializer.cs">
+ <Link>Serialization\IDeserializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\ISerializer.cs">
+ <Link>Serialization\ISerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\JsonParser.cs">
+ <Link>Serialization\JsonParser.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\Utf8Serializer.cs">
+ <Link>Serialization\Utf8Serializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\AndSpecification.cs">
+ <Link>Specifications\AndSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\CompositeSpecificationBase.cs">
+ <Link>Specifications\CompositeSpecificationBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\HammockSpecification.cs">
+ <Link>Specifications\HammockSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\ISpecification.cs">
+ <Link>Specifications\ISpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\NotSpecification.cs">
+ <Link>Specifications\NotSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\OrSpecification.cs">
+ <Link>Specifications\OrSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Streaming\StreamOptions.cs">
+ <Link>Streaming\StreamOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\IRateLimitingRule.cs">
+ <Link>Tasks\IRateLimitingRule.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\IRateLimitStatus.cs">
+ <Link>Tasks\IRateLimitStatus.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITaskOptions.cs">
+ <Link>Tasks\ITaskOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITaskState.cs">
+ <Link>Tasks\ITaskState.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITimedTask.cs">
+ <Link>Tasks\ITimedTask.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\RateLimitingRule.cs">
+ <Link>Tasks\RateLimitingRule.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\RateLimitType.cs">
+ <Link>Tasks\RateLimitType.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TaskOptions.cs">
+ <Link>Tasks\TaskOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TaskState.cs">
+ <Link>Tasks\TaskState.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TimedTask.cs">
+ <Link>Tasks\TimedTask.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Validation\ValidationException.cs">
+ <Link>Validation\ValidationException.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Validation\ValidEmailSpecification.cs">
+ <Link>Validation\ValidEmailSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\BasicAuthWebQuery.cs">
+ <Link>Web\BasicAuthWebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\GetOrDelete.cs">
+ <Link>Web\GetOrDelete.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\HttpCookieParameter.cs">
+ <Link>Web\HttpCookieParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\HttpPostParameter.cs">
+ <Link>Web\HttpPostParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\HttpPostParameterType.cs">
+ <Link>Web\HttpPostParameterType.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\IWebQueryInfo.cs">
+ <Link>Web\IWebQueryInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\IMockable.cs">
+ <Link>Web\Mocks\IMockable.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\IWebResponse.cs">
+ <Link>Web\Mocks\IWebResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockHttpWebRequest.cs">
+ <Link>Web\Mocks\MockHttpWebRequest.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockHttpWebResponse.cs">
+ <Link>Web\Mocks\MockHttpWebResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockWebRequestFactory.cs">
+ <Link>Web\Mocks\MockWebRequestFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Pair.cs">
+ <Link>Web\Pair.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\PostOrPut.cs">
+ <Link>Web\PostOrPut.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Triplet.cs">
+ <Link>Web\Triplet.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebCallback.cs">
+ <Link>Web\WebCallback.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebEntity.cs">
+ <Link>Web\WebEntity.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebHeader.cs">
+ <Link>Web\WebHeader.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebHeaderCollection.cs">
+ <Link>Web\WebHeaderCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebMethod.cs">
+ <Link>Web\WebMethod.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebPair.cs">
+ <Link>Web\WebPair.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebPairCollection.cs">
+ <Link>Web\WebPairCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebParameter.cs">
+ <Link>Web\WebParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebParameterCollection.cs">
+ <Link>Web\WebParameterCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQuery.Async.cs">
+ <Link>Web\WebQuery.Async.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQuery.cs">
+ <Link>Web\WebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryAsyncResult.cs">
+ <Link>Web\WebQueryAsyncResult.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryRequestEventArgs.cs">
+ <Link>Web\WebQueryRequestEventArgs.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryResponseEventArgs.cs">
+ <Link>Web\WebQueryResponseEventArgs.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryResult.cs">
+ <Link>Web\WebQueryResult.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\IRestClient.cs">
+ <Link>IRestClient.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestBase.cs">
+ <Link>RestBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestCallback.cs">
+ <Link>RestCallback.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestClient.cs">
+ <Link>RestClient.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestRequest.cs">
+ <Link>RestRequest.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestResponse.cs">
+ <Link>RestResponse.cs</Link>
+ </Compile>
+ <Compile Include="GlobalSuppressions.cs" />
+ <Compile Include="Mono\HttpUtility.cs" />
+ <Compile Include="Mono\WebHeaderCollection.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="key.snk" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
\ No newline at end of file
--- /dev/null
+//
+// System.Web.HttpUtility
+//
+// Authors:
+// Patrik Torstensson (Patrik.Torstensson@labs2.com)
+// Wictor Wilén (decode/encode functions) (wictor@ibizkit.se)
+// Tim Coleman (tim@timcoleman.com)
+// Gonzalo Paniagua Javier (gonzalo@ximian.com)
+//
+// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+
+using System.Collections;
+using System.Collections.Specialized;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+namespace System.Compat.Web
+{
+ public sealed class HttpUtility
+ {
+ #region Fields
+
+ private static Hashtable entities;
+ private static readonly object lock_ = new object();
+
+ #endregion // Fields
+
+ private static Hashtable Entities
+ {
+ get
+ {
+ lock (lock_)
+ {
+ if (entities == null)
+ {
+ InitEntities();
+ }
+
+ return entities;
+ }
+ }
+ }
+
+ #region Constructors
+
+ private static void InitEntities()
+ {
+ // Build the hash table of HTML entity references. This list comes
+ // from the HTML 4.01 W3C recommendation.
+ entities = new Hashtable
+ {
+ {"nbsp", '\u00A0'},
+ {"iexcl", '\u00A1'},
+ {"cent", '\u00A2'},
+ {"pound", '\u00A3'},
+ {"curren", '\u00A4'},
+ {"yen", '\u00A5'},
+ {"brvbar", '\u00A6'},
+ {"sect", '\u00A7'},
+ {"uml", '\u00A8'},
+ {"copy", '\u00A9'},
+ {"ordf", '\u00AA'},
+ {"laquo", '\u00AB'},
+ {"not", '\u00AC'},
+ {"shy", '\u00AD'},
+ {"reg", '\u00AE'},
+ {"macr", '\u00AF'},
+ {"deg", '\u00B0'},
+ {"plusmn", '\u00B1'},
+ {"sup2", '\u00B2'},
+ {"sup3", '\u00B3'},
+ {"acute", '\u00B4'},
+ {"micro", '\u00B5'},
+ {"para", '\u00B6'},
+ {"middot", '\u00B7'},
+ {"cedil", '\u00B8'},
+ {"sup1", '\u00B9'},
+ {"ordm", '\u00BA'},
+ {"raquo", '\u00BB'},
+ {"frac14", '\u00BC'},
+ {"frac12", '\u00BD'},
+ {"frac34", '\u00BE'},
+ {"iquest", '\u00BF'},
+ {"Agrave", '\u00C0'},
+ {"Aacute", '\u00C1'},
+ {"Acirc", '\u00C2'},
+ {"Atilde", '\u00C3'},
+ {"Auml", '\u00C4'},
+ {"Aring", '\u00C5'},
+ {"AElig", '\u00C6'},
+ {"Ccedil", '\u00C7'},
+ {"Egrave", '\u00C8'},
+ {"Eacute", '\u00C9'},
+ {"Ecirc", '\u00CA'},
+ {"Euml", '\u00CB'},
+ {"Igrave", '\u00CC'},
+ {"Iacute", '\u00CD'},
+ {"Icirc", '\u00CE'},
+ {"Iuml", '\u00CF'},
+ {"ETH", '\u00D0'},
+ {"Ntilde", '\u00D1'},
+ {"Ograve", '\u00D2'},
+ {"Oacute", '\u00D3'},
+ {"Ocirc", '\u00D4'},
+ {"Otilde", '\u00D5'},
+ {"Ouml", '\u00D6'},
+ {"times", '\u00D7'},
+ {"Oslash", '\u00D8'},
+ {"Ugrave", '\u00D9'},
+ {"Uacute", '\u00DA'},
+ {"Ucirc", '\u00DB'},
+ {"Uuml", '\u00DC'},
+ {"Yacute", '\u00DD'},
+ {"THORN", '\u00DE'},
+ {"szlig", '\u00DF'},
+ {"agrave", '\u00E0'},
+ {"aacute", '\u00E1'},
+ {"acirc", '\u00E2'},
+ {"atilde", '\u00E3'},
+ {"auml", '\u00E4'},
+ {"aring", '\u00E5'},
+ {"aelig", '\u00E6'},
+ {"ccedil", '\u00E7'},
+ {"egrave", '\u00E8'},
+ {"eacute", '\u00E9'},
+ {"ecirc", '\u00EA'},
+ {"euml", '\u00EB'},
+ {"igrave", '\u00EC'},
+ {"iacute", '\u00ED'},
+ {"icirc", '\u00EE'},
+ {"iuml", '\u00EF'},
+ {"eth", '\u00F0'},
+ {"ntilde", '\u00F1'},
+ {"ograve", '\u00F2'},
+ {"oacute", '\u00F3'},
+ {"ocirc", '\u00F4'},
+ {"otilde", '\u00F5'},
+ {"ouml", '\u00F6'},
+ {"divide", '\u00F7'},
+ {"oslash", '\u00F8'},
+ {"ugrave", '\u00F9'},
+ {"uacute", '\u00FA'},
+ {"ucirc", '\u00FB'},
+ {"uuml", '\u00FC'},
+ {"yacute", '\u00FD'},
+ {"thorn", '\u00FE'},
+ {"yuml", '\u00FF'},
+ {"fnof", '\u0192'},
+ {"Alpha", '\u0391'},
+ {"Beta", '\u0392'},
+ {"Gamma", '\u0393'},
+ {"Delta", '\u0394'},
+ {"Epsilon", '\u0395'},
+ {"Zeta", '\u0396'},
+ {"Eta", '\u0397'},
+ {"Theta", '\u0398'},
+ {"Iota", '\u0399'},
+ {"Kappa", '\u039A'},
+ {"Lambda", '\u039B'},
+ {"Mu", '\u039C'},
+ {"Nu", '\u039D'},
+ {"Xi", '\u039E'},
+ {"Omicron", '\u039F'},
+ {"Pi", '\u03A0'},
+ {"Rho", '\u03A1'},
+ {"Sigma", '\u03A3'},
+ {"Tau", '\u03A4'},
+ {"Upsilon", '\u03A5'},
+ {"Phi", '\u03A6'},
+ {"Chi", '\u03A7'},
+ {"Psi", '\u03A8'},
+ {"Omega", '\u03A9'},
+ {"alpha", '\u03B1'},
+ {"beta", '\u03B2'},
+ {"gamma", '\u03B3'},
+ {"delta", '\u03B4'},
+ {"epsilon", '\u03B5'},
+ {"zeta", '\u03B6'},
+ {"eta", '\u03B7'},
+ {"theta", '\u03B8'},
+ {"iota", '\u03B9'},
+ {"kappa", '\u03BA'},
+ {"lambda", '\u03BB'},
+ {"mu", '\u03BC'},
+ {"nu", '\u03BD'},
+ {"xi", '\u03BE'},
+ {"omicron", '\u03BF'},
+ {"pi", '\u03C0'},
+ {"rho", '\u03C1'},
+ {"sigmaf", '\u03C2'},
+ {"sigma", '\u03C3'},
+ {"tau", '\u03C4'},
+ {"upsilon", '\u03C5'},
+ {"phi", '\u03C6'},
+ {"chi", '\u03C7'},
+ {"psi", '\u03C8'},
+ {"omega", '\u03C9'},
+ {"thetasym", '\u03D1'},
+ {"upsih", '\u03D2'},
+ {"piv", '\u03D6'},
+ {"bull", '\u2022'},
+ {"hellip", '\u2026'},
+ {"prime", '\u2032'},
+ {"Prime", '\u2033'},
+ {"oline", '\u203E'},
+ {"frasl", '\u2044'},
+ {"weierp", '\u2118'},
+ {"image", '\u2111'},
+ {"real", '\u211C'},
+ {"trade", '\u2122'},
+ {"alefsym", '\u2135'},
+ {"larr", '\u2190'},
+ {"uarr", '\u2191'},
+ {"rarr", '\u2192'},
+ {"darr", '\u2193'},
+ {"harr", '\u2194'},
+ {"crarr", '\u21B5'},
+ {"lArr", '\u21D0'},
+ {"uArr", '\u21D1'},
+ {"rArr", '\u21D2'},
+ {"dArr", '\u21D3'},
+ {"hArr", '\u21D4'},
+ {"forall", '\u2200'},
+ {"part", '\u2202'},
+ {"exist", '\u2203'},
+ {"empty", '\u2205'},
+ {"nabla", '\u2207'},
+ {"isin", '\u2208'},
+ {"notin", '\u2209'},
+ {"ni", '\u220B'},
+ {"prod", '\u220F'},
+ {"sum", '\u2211'},
+ {"minus", '\u2212'},
+ {"lowast", '\u2217'},
+ {"radic", '\u221A'},
+ {"prop", '\u221D'},
+ {"infin", '\u221E'},
+ {"ang", '\u2220'},
+ {"and", '\u2227'},
+ {"or", '\u2228'},
+ {"cap", '\u2229'},
+ {"cup", '\u222A'},
+ {"int", '\u222B'},
+ {"there4", '\u2234'},
+ {"sim", '\u223C'},
+ {"cong", '\u2245'},
+ {"asymp", '\u2248'},
+ {"ne", '\u2260'},
+ {"equiv", '\u2261'},
+ {"le", '\u2264'},
+ {"ge", '\u2265'},
+ {"sub", '\u2282'},
+ {"sup", '\u2283'},
+ {"nsub", '\u2284'},
+ {"sube", '\u2286'},
+ {"supe", '\u2287'},
+ {"oplus", '\u2295'},
+ {"otimes", '\u2297'},
+ {"perp", '\u22A5'},
+ {"sdot", '\u22C5'},
+ {"lceil", '\u2308'},
+ {"rceil", '\u2309'},
+ {"lfloor", '\u230A'},
+ {"rfloor", '\u230B'},
+ {"lang", '\u2329'},
+ {"rang", '\u232A'},
+ {"loz", '\u25CA'},
+ {"spades", '\u2660'},
+ {"clubs", '\u2663'},
+ {"hearts", '\u2665'},
+ {"diams", '\u2666'},
+ {"quot", '\u0022'},
+ {"amp", '\u0026'},
+ {"lt", '\u003C'},
+ {"gt", '\u003E'},
+ {"OElig", '\u0152'},
+ {"oelig", '\u0153'},
+ {"Scaron", '\u0160'},
+ {"scaron", '\u0161'},
+ {"Yuml", '\u0178'},
+ {"circ", '\u02C6'},
+ {"tilde", '\u02DC'},
+ {"ensp", '\u2002'},
+ {"emsp", '\u2003'},
+ {"thinsp", '\u2009'},
+ {"zwnj", '\u200C'},
+ {"zwj", '\u200D'},
+ {"lrm", '\u200E'},
+ {"rlm", '\u200F'},
+ {"ndash", '\u2013'},
+ {"mdash", '\u2014'},
+ {"lsquo", '\u2018'},
+ {"rsquo", '\u2019'},
+ {"sbquo", '\u201A'},
+ {"ldquo", '\u201C'},
+ {"rdquo", '\u201D'},
+ {"bdquo", '\u201E'},
+ {"dagger", '\u2020'},
+ {"Dagger", '\u2021'},
+ {"permil", '\u2030'},
+ {"lsaquo", '\u2039'},
+ {"rsaquo", '\u203A'},
+ {"euro", '\u20AC'}
+ };
+ }
+
+ #endregion // Constructors
+
+ #region Methods
+
+ private static readonly char[] hexChars = "0123456789abcdef".ToCharArray();
+
+ public static void HtmlAttributeEncode(string s, TextWriter output)
+ {
+ output.Write(HtmlAttributeEncode(s));
+ }
+
+ public static string HtmlAttributeEncode(string s)
+ {
+ if (null == s)
+ {
+ return null;
+ }
+
+ var needEncode = false;
+ for (var i = 0; i < s.Length; i++)
+ {
+ if (s[i] == '&' || s[i] == '"' || s[i] == '<')
+ {
+ needEncode = true;
+ break;
+ }
+ }
+
+ if (!needEncode)
+ {
+ return s;
+ }
+
+ var output = new StringBuilder();
+ var len = s.Length;
+ for (var i = 0; i < len; i++)
+ {
+ switch (s[i])
+ {
+ case '&':
+ output.Append("&");
+ break;
+ case '"':
+ output.Append(""");
+ break;
+ case '<':
+ output.Append("<");
+ break;
+ default:
+ output.Append(s[i]);
+ break;
+ }
+ }
+
+ return output.ToString();
+ }
+
+ public static string UrlDecode(string str)
+ {
+ return UrlDecode(str, Encoding.UTF8);
+ }
+
+ private static char[] GetChars(MemoryStream b, Encoding e)
+ {
+ return e.GetChars(b.GetBuffer(), 0, (int) b.Length);
+ }
+
+ public static string UrlDecode(string s, Encoding e)
+ {
+ if (null == s)
+ {
+ return null;
+ }
+
+ if (s.IndexOf('%') == -1 && s.IndexOf('+') == -1)
+ {
+ return s;
+ }
+
+ if (e == null)
+ {
+ e = Encoding.UTF8;
+ }
+
+ var output = new StringBuilder();
+ long len = s.Length;
+ var bytes = new MemoryStream();
+
+ for (var i = 0; i < len; i++)
+ {
+ if (s[i] == '%' && i + 2 < len && s[i + 1] != '%')
+ {
+ int xchar;
+ if (s[i + 1] == 'u' && i + 5 < len)
+ {
+ if (bytes.Length > 0)
+ {
+ output.Append(GetChars(bytes, e));
+ bytes.SetLength(0);
+ }
+
+ xchar = GetChar(s, i + 2, 4);
+ if (xchar != -1)
+ {
+ output.Append((char) xchar);
+ i += 5;
+ }
+ else
+ {
+ output.Append('%');
+ }
+ }
+ else if ((xchar = GetChar(s, i + 1, 2)) != -1)
+ {
+ bytes.WriteByte((byte) xchar);
+ i += 2;
+ }
+ else
+ {
+ output.Append('%');
+ }
+ continue;
+ }
+
+ if (bytes.Length > 0)
+ {
+ output.Append(GetChars(bytes, e));
+ bytes.SetLength(0);
+ }
+
+ if (s[i] == '+')
+ {
+ output.Append(' ');
+ }
+ else
+ {
+ output.Append(s[i]);
+ }
+ }
+
+ if (bytes.Length > 0)
+ {
+ output.Append(GetChars(bytes, e));
+ }
+
+ return output.ToString();
+ }
+
+ public static string UrlDecode(byte[] bytes, Encoding e)
+ {
+ return bytes == null ? null : UrlDecode(bytes, 0, bytes.Length, e);
+ }
+
+ private static int GetInt(byte b)
+ {
+ var c = (char) b;
+ if (c >= '0' && c <= '9')
+ {
+ return c - '0';
+ }
+
+ if (c >= 'a' && c <= 'f')
+ {
+ return c - 'a' + 10;
+ }
+
+ if (c >= 'A' && c <= 'F')
+ {
+ return c - 'A' + 10;
+ }
+
+ return -1;
+ }
+
+ private static int GetChar(byte[] bytes, int offset, int length)
+ {
+ var value = 0;
+ var end = length + offset;
+ for (var i = offset; i < end; i++)
+ {
+ var current = GetInt(bytes[i]);
+ if (current == -1)
+ {
+ return -1;
+ }
+ value = (value << 4) + current;
+ }
+
+ return value;
+ }
+
+ private static int GetChar(string str, int offset, int length)
+ {
+ var val = 0;
+ var end = length + offset;
+ for (var i = offset; i < end; i++)
+ {
+ var c = str[i];
+ if (c > 127)
+ {
+ return -1;
+ }
+
+ var current = GetInt((byte) c);
+ if (current == -1)
+ {
+ return -1;
+ }
+ val = (val << 4) + current;
+ }
+
+ return val;
+ }
+
+ public static string UrlDecode(byte[] bytes, int offset, int count, Encoding e)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+ if (count == 0)
+ {
+ return String.Empty;
+ }
+
+ if (bytes == null)
+ {
+ throw new ArgumentNullException("bytes");
+ }
+
+ if (offset < 0 || offset > bytes.Length)
+ {
+ throw new ArgumentOutOfRangeException("offset");
+ }
+
+ if (count < 0 || offset + count > bytes.Length)
+ {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ var output = new StringBuilder();
+ var acc = new MemoryStream();
+
+ var end = count + offset;
+ for (var i = offset; i < end; i++)
+ {
+ if (bytes[i] == '%' && i + 2 < count && bytes[i + 1] != '%')
+ {
+ int xchar;
+ if (bytes[i + 1] == (byte) 'u' && i + 5 < end)
+ {
+ if (acc.Length > 0)
+ {
+ output.Append(GetChars(acc, e));
+ acc.SetLength(0);
+ }
+ xchar = GetChar(bytes, i + 2, 4);
+ if (xchar != -1)
+ {
+ output.Append((char) xchar);
+ i += 5;
+ continue;
+ }
+ }
+ else if ((xchar = GetChar(bytes, i + 1, 2)) != -1)
+ {
+ acc.WriteByte((byte) xchar);
+ i += 2;
+ continue;
+ }
+ }
+
+ if (acc.Length > 0)
+ {
+ output.Append(GetChars(acc, e));
+ acc.SetLength(0);
+ }
+
+ if (bytes[i] == '+')
+ {
+ output.Append(' ');
+ }
+ else
+ {
+ output.Append((char) bytes[i]);
+ }
+ }
+
+ if (acc.Length > 0)
+ {
+ output.Append(GetChars(acc, e));
+ }
+
+ return output.ToString();
+ }
+
+ public static byte[] UrlDecodeToBytes(byte[] bytes)
+ {
+ return bytes == null ? null : UrlDecodeToBytes(bytes, 0, bytes.Length);
+ }
+
+ public static byte[] UrlDecodeToBytes(string str)
+ {
+ return UrlDecodeToBytes(str, Encoding.UTF8);
+ }
+
+ public static byte[] UrlDecodeToBytes(string str, Encoding e)
+ {
+ if (str == null)
+ {
+ return null;
+ }
+
+ if (e == null)
+ {
+ throw new ArgumentNullException("e");
+ }
+
+ return UrlDecodeToBytes(e.GetBytes(str));
+ }
+
+ public static byte[] UrlDecodeToBytes(byte[] bytes, int offset, int count)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+ if (count == 0)
+ {
+ return new byte[0];
+ }
+
+ var len = bytes.Length;
+ if (offset < 0 || offset >= len)
+ {
+ throw new ArgumentOutOfRangeException("offset");
+ }
+
+ if (count < 0 || offset > len - count)
+ {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ var result = new MemoryStream();
+ var end = offset + count;
+ for (var i = offset; i < end; i++)
+ {
+ var c = (char) bytes[i];
+ if (c == '+')
+ {
+ c = ' ';
+ }
+ else if (c == '%' && i < end - 2)
+ {
+ var xchar = GetChar(bytes, i + 1, 2);
+ if (xchar != -1)
+ {
+ c = (char) xchar;
+ i += 2;
+ }
+ }
+ result.WriteByte((byte) c);
+ }
+
+ return result.ToArray();
+ }
+
+ public static string UrlEncode(string str)
+ {
+ return UrlEncode(str, Encoding.UTF8);
+ }
+
+ public static string UrlEncode(string s, Encoding Enc)
+ {
+ if (s == null)
+ {
+ return null;
+ }
+
+ if (s == "")
+ {
+ return "";
+ }
+
+ var needEncode = false;
+ var len = s.Length;
+ for (var i = 0; i < len; i++)
+ {
+ var c = s[i];
+ if ((c < '0') || (c < 'A' && c > '9') || (c > 'Z' && c < 'a') || (c > 'z'))
+ {
+ if (NotEncoded(c))
+ {
+ continue;
+ }
+
+ needEncode = true;
+ break;
+ }
+ }
+
+ if (!needEncode)
+ {
+ return s;
+ }
+
+ // avoided GetByteCount call
+ var bytes = new byte[Enc.GetMaxByteCount(s.Length)];
+ var realLen = Enc.GetBytes(s, 0, s.Length, bytes, 0);
+ return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, 0, realLen), 0, realLen);
+ }
+
+ public static string UrlEncode(byte[] bytes)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ if (bytes.Length == 0)
+ {
+ return "";
+ }
+
+ return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, 0, bytes.Length), 0, bytes.Length);
+ }
+
+ public static string UrlEncode(byte[] bytes, int offset, int count)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ if (bytes.Length == 0)
+ {
+ return "";
+ }
+
+ return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, offset, count), offset, count);
+ }
+
+ public static byte[] UrlEncodeToBytes(string str)
+ {
+ return UrlEncodeToBytes(str, Encoding.UTF8);
+ }
+
+ public static byte[] UrlEncodeToBytes(string str, Encoding e)
+ {
+ if (str == null)
+ {
+ return null;
+ }
+
+ if (str == "")
+ {
+ return new byte[0];
+ }
+
+ var bytes = e.GetBytes(str);
+ return UrlEncodeToBytes(bytes, 0, bytes.Length);
+ }
+
+ public static byte[] UrlEncodeToBytes(byte[] bytes)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ if (bytes.Length == 0)
+ {
+ return new byte[0];
+ }
+
+ return UrlEncodeToBytes(bytes, 0, bytes.Length);
+ }
+
+ private static bool NotEncoded(char c)
+ {
+ return (c == '!' || c == '\'' || c == '(' || c == ')' || c == '*' || c == '-' || c == '.' || c == '_');
+ }
+
+ private static void UrlEncodeChar(char c, Stream result, bool isUnicode)
+ {
+ if (c > 255)
+ {
+ //FIXME: what happens when there is an internal error?
+ //if (!isUnicode)
+ // throw new ArgumentOutOfRangeException ("c", c, "c must be less than 256");
+ int i = c;
+
+ result.WriteByte((byte) '%');
+ result.WriteByte((byte) 'u');
+ var idx = i >> 12;
+ result.WriteByte((byte) hexChars[idx]);
+ idx = (i >> 8) & 0x0F;
+ result.WriteByte((byte) hexChars[idx]);
+ idx = (i >> 4) & 0x0F;
+ result.WriteByte((byte) hexChars[idx]);
+ idx = i & 0x0F;
+ result.WriteByte((byte) hexChars[idx]);
+ return;
+ }
+
+ if (c > ' ' && NotEncoded(c))
+ {
+ result.WriteByte((byte) c);
+ return;
+ }
+ if (c == ' ')
+ {
+ result.WriteByte((byte) '+');
+ return;
+ }
+ if ((c < '0') ||
+ (c < 'A' && c > '9') ||
+ (c > 'Z' && c < 'a') ||
+ (c > 'z'))
+ {
+ if (isUnicode && c > 127)
+ {
+ result.WriteByte((byte) '%');
+ result.WriteByte((byte) 'u');
+ result.WriteByte((byte) '0');
+ result.WriteByte((byte) '0');
+ }
+ else
+ {
+ result.WriteByte((byte) '%');
+ }
+
+ var idx = (c) >> 4;
+ result.WriteByte((byte) hexChars[idx]);
+ idx = (c) & 0x0F;
+ result.WriteByte((byte) hexChars[idx]);
+ }
+ else
+ {
+ result.WriteByte((byte) c);
+ }
+ }
+
+ public static byte[] UrlEncodeToBytes(byte[] bytes, int offset, int count)
+ {
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ var len = bytes.Length;
+ if (len == 0)
+ {
+ return new byte[0];
+ }
+
+ if (offset < 0 || offset >= len)
+ {
+ throw new ArgumentOutOfRangeException("offset");
+ }
+
+ if (count < 0 || count > len - offset)
+ {
+ throw new ArgumentOutOfRangeException("count");
+ }
+
+ var result = new MemoryStream(count);
+ var end = offset + count;
+ for (var i = offset; i < end; i++)
+ {
+ UrlEncodeChar((char) bytes[i], result, false);
+ }
+
+ return result.ToArray();
+ }
+
+ public static string UrlEncodeUnicode(string str)
+ {
+ if (str == null)
+ {
+ return null;
+ }
+
+ var bytes = UrlEncodeUnicodeToBytes(str);
+ return Encoding.ASCII.GetString(bytes, 0, bytes.Length);
+ }
+
+ public static byte[] UrlEncodeUnicodeToBytes(string str)
+ {
+ if (str == null)
+ {
+ return null;
+ }
+
+ if (str == "")
+ {
+ return new byte[0];
+ }
+
+ var result = new MemoryStream(str.Length);
+ foreach (var c in str)
+ {
+ UrlEncodeChar(c, result, true);
+ }
+ return result.ToArray();
+ }
+
+ /// <summary>
+ /// Decodes an HTML-encoded string and returns the decoded string.
+ /// </summary>
+ /// <param name="s">The HTML string to decode. </param>
+ /// <returns>The decoded text.</returns>
+ public static string HtmlDecode(string s)
+ {
+ if (s == null)
+ {
+ throw new ArgumentNullException("s");
+ }
+
+ if (s.IndexOf('&') == -1)
+ {
+ return s;
+ }
+
+ var entity = new StringBuilder();
+ var output = new StringBuilder();
+ var len = s.Length;
+ // 0 -> nothing,
+ // 1 -> right after '&'
+ // 2 -> between '&' and ';' but no '#'
+ // 3 -> '#' found after '&' and getting numbers
+ var state = 0;
+ var number = 0;
+ var have_trailing_digits = false;
+
+ for (var i = 0; i < len; i++)
+ {
+ var c = s[i];
+ if (state == 0)
+ {
+ if (c == '&')
+ {
+ entity.Append(c);
+ state = 1;
+ }
+ else
+ {
+ output.Append(c);
+ }
+ continue;
+ }
+
+ if (c == '&')
+ {
+ state = 1;
+ if (have_trailing_digits)
+ {
+ entity.Append(number.ToString(CultureInfo.InvariantCulture));
+ have_trailing_digits = false;
+ }
+
+ output.Append(entity.ToString());
+ entity.Length = 0;
+ entity.Append('&');
+ continue;
+ }
+
+ if (state == 1)
+ {
+ if (c == ';')
+ {
+ state = 0;
+ output.Append(entity.ToString());
+ output.Append(c);
+ entity.Length = 0;
+ }
+ else
+ {
+ number = 0;
+ state = c != '#' ? 2 : 3;
+ entity.Append(c);
+ }
+ }
+ else if (state == 2)
+ {
+ entity.Append(c);
+ if (c == ';')
+ {
+ var key = entity.ToString();
+ if (key.Length > 1 && Entities.ContainsKey(key.Substring(1, key.Length - 2)))
+ {
+ key = Entities[key.Substring(1, key.Length - 2)].ToString();
+ }
+
+ output.Append(key);
+ state = 0;
+ entity.Length = 0;
+ }
+ }
+ else if (state == 3)
+ {
+ if (c == ';')
+ {
+ if (number > 65535)
+ {
+ output.Append("&#");
+ output.Append(number.ToString(CultureInfo.InvariantCulture));
+ output.Append(";");
+ }
+ else
+ {
+ output.Append((char) number);
+ }
+ state = 0;
+ entity.Length = 0;
+ have_trailing_digits = false;
+ }
+ else if (Char.IsDigit(c))
+ {
+ number = number*10 + (c - '0');
+ have_trailing_digits = true;
+ }
+ else
+ {
+ state = 2;
+ if (have_trailing_digits)
+ {
+ entity.Append(number.ToString(CultureInfo.InvariantCulture));
+ have_trailing_digits = false;
+ }
+ entity.Append(c);
+ }
+ }
+ }
+
+ if (entity.Length > 0)
+ {
+ output.Append(entity.ToString());
+ }
+ else if (have_trailing_digits)
+ {
+ output.Append(number.ToString(CultureInfo.InvariantCulture));
+ }
+ return output.ToString();
+ }
+
+ /// <summary>
+ /// Decodes an HTML-encoded string and sends the resulting output to a TextWriter output stream.
+ /// </summary>
+ /// <param name="s">The HTML string to decode</param>
+ /// <param name="output">The TextWriter output stream containing the decoded string. </param>
+ public static void HtmlDecode(string s, TextWriter output)
+ {
+ if (s != null)
+ {
+ output.Write(HtmlDecode(s));
+ }
+ }
+
+ /// <summary>
+ /// HTML-encodes a string and returns the encoded string.
+ /// </summary>
+ /// <param name="s">The text string to encode. </param>
+ /// <returns>The HTML-encoded text.</returns>
+ public static string HtmlEncode(string s)
+ {
+ if (s == null)
+ {
+ return null;
+ }
+
+ var needEncode = false;
+ for (var i = 0; i < s.Length; i++)
+ {
+ var c = s[i];
+ if (c == '&' || c == '"' || c == '<' || c == '>' || c > 159)
+ {
+ needEncode = true;
+ break;
+ }
+ }
+
+ if (!needEncode)
+ {
+ return s;
+ }
+
+ var output = new StringBuilder();
+
+ var len = s.Length;
+ for (var i = 0; i < len; i++)
+ {
+ switch (s[i])
+ {
+ case '&':
+ output.Append("&");
+ break;
+ case '>':
+ output.Append(">");
+ break;
+ case '<':
+ output.Append("<");
+ break;
+ case '"':
+ output.Append(""");
+ break;
+ default:
+ // MS starts encoding with &# from 160 and stops at 255.
+ // We don't do that. One reason is the 65308/65310 unicode
+ // characters that look like '<' and '>'.
+#if TARGET_JVM
+ if (s [i] > 159 && s [i] < 256) {
+#else
+ if (s[i] > 159)
+ {
+#endif
+ output.Append("&#");
+ output.Append(((int) s[i]).ToString(CultureInfo.InvariantCulture));
+ output.Append(";");
+ }
+ else
+ {
+ output.Append(s[i]);
+ }
+ break;
+ }
+ }
+ return output.ToString();
+ }
+
+ /// <summary>
+ /// HTML-encodes a string and sends the resulting output to a TextWriter output stream.
+ /// </summary>
+ /// <param name="s">The string to encode. </param>
+ /// <param name="output">The TextWriter output stream containing the encoded string. </param>
+ public static void HtmlEncode(string s, TextWriter output)
+ {
+ if (s != null)
+ {
+ output.Write(HtmlEncode(s));
+ }
+ }
+
+ public static string UrlPathEncode(string s)
+ {
+ if (string.IsNullOrEmpty(s))
+ return s;
+
+ var result = new MemoryStream();
+ var length = s.Length;
+ for (var i = 0; i < length; i++)
+ {
+ UrlPathEncodeChar(s[i], result);
+ }
+
+ var bytes = result.ToArray();
+ return Encoding.ASCII.GetString(bytes, 0, bytes.Length);
+ }
+
+ private static void UrlPathEncodeChar(char c, Stream result)
+ {
+ if (c < 33 || c > 126)
+ {
+ var bIn = Encoding.UTF8.GetBytes(c.ToString());
+ for (var i = 0; i < bIn.Length; i++)
+ {
+ result.WriteByte((byte) '%');
+ var idx = bIn[i] >> 4;
+ result.WriteByte((byte) hexChars[idx]);
+ idx = bIn[i] & 0x0F;
+ result.WriteByte((byte) hexChars[idx]);
+ }
+ }
+ else if (c == ' ')
+ {
+ result.WriteByte((byte) '%');
+ result.WriteByte((byte) '2');
+ result.WriteByte((byte) '0');
+ }
+ else
+ result.WriteByte((byte) c);
+ }
+
+ public static NameValueCollection ParseQueryString(string query)
+ {
+ return ParseQueryString(query, Encoding.UTF8);
+ }
+
+ public static NameValueCollection ParseQueryString(string query, Encoding encoding)
+ {
+ if (query == null)
+ throw new ArgumentNullException("query");
+ if (encoding == null)
+ throw new ArgumentNullException("encoding");
+ if (query.Length == 0 || (query.Length == 1 && query[0] == '?'))
+ return new NameValueCollection();
+ if (query[0] == '?')
+ query = query.Substring(1);
+
+ var result = new NameValueCollection();
+ ParseQueryString(query, encoding, result);
+ return result;
+ }
+
+ internal static void ParseQueryString(string query, Encoding encoding, NameValueCollection result)
+ {
+ if (query.Length == 0)
+ {
+ return;
+ }
+
+ var decoded = HtmlDecode(query);
+ var decodedLength = decoded.Length;
+ var namePos = 0;
+ var first = true;
+ while (namePos <= decodedLength)
+ {
+ int valuePos = -1, valueEnd = -1;
+ for (var q = namePos; q < decodedLength; q++)
+ {
+ if (valuePos == -1 && decoded[q] == '=')
+ {
+ valuePos = q + 1;
+ }
+ else if (decoded[q] == '&')
+ {
+ valueEnd = q;
+ break;
+ }
+ }
+
+ if (first)
+ {
+ first = false;
+ if (decoded[namePos] == '?')
+ {
+ namePos++;
+ }
+ }
+
+ string name;
+ if (valuePos == -1)
+ {
+ name = null;
+ valuePos = namePos;
+ }
+ else
+ {
+ name = UrlDecode(decoded.Substring(namePos, valuePos - namePos - 1), encoding);
+ }
+ if (valueEnd < 0)
+ {
+ namePos = -1;
+ valueEnd = decoded.Length;
+ }
+ else
+ {
+ namePos = valueEnd + 1;
+ }
+ var value = UrlDecode(decoded.Substring(valuePos, valueEnd - valuePos), encoding);
+
+ result.Add(name, value);
+ if (namePos == -1)
+ {
+ break;
+ }
+ }
+ }
+
+ #endregion // Methods
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// System.Net.WebHeaderCollection
+//
+// Authors:
+// Lawrence Pit (loz@cable.a2000.nl)
+// Gonzalo Paniagua Javier (gonzalo@ximian.com)
+// Miguel de Icaza (miguel@novell.com)
+//
+// Copyright 2003 Ximian, Inc. (http://www.ximian.com)
+// Copyright 2007 Novell, Inc. (http://www.novell.com)
+//
+//
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Net;
+using System.Runtime.InteropServices;
+using System.Text;
+
+// See RFC 2068 par 4.2 Message Headers
+
+namespace Mono.Net
+{
+ [Serializable]
+ [ComVisible(true)]
+ public class WebHeaderCollection : NameValueCollection
+ {
+ private static readonly Hashtable _restricted;
+ private static readonly Hashtable _multiValue;
+
+ private static readonly char[] tspecials =
+ new[]
+ {
+ '(', ')', '<', '>', '@',
+ ',', ';', ':', '\\', '"',
+ '/', '[', ']', '?', '=',
+ '{', '}', ' ', '\t'
+ };
+
+ private readonly bool internallyCreated;
+
+ // Static Initializer
+
+ static WebHeaderCollection()
+ {
+ // the list of restricted header names as defined
+ // by the ms.net spec
+ _restricted = new Hashtable(StringComparer.InvariantCultureIgnoreCase)
+ {
+ {"accept", true},
+ {"connection", true},
+ {"content-length", true},
+ {"content-type", true},
+ {"date", true},
+ {"expect", true},
+ {"host", true},
+ {"if-modified-since", true},
+ {"range", true},
+ {"referer", true},
+ {"transfer-encoding", true},
+ {"user-agent", true}
+ };
+
+ // see par 14 of RFC 2068 to see which header names
+ // accept multiple values each separated by a comma
+ _multiValue = new Hashtable(StringComparer.InvariantCultureIgnoreCase)
+ {
+ {"accept", true},
+ {"accept-charset", true},
+ {"accept-encoding", true},
+ {"accept-language", true},
+ {"accept-ranges", true},
+ {"allow", true},
+ {"authorization", true},
+ {"cache-control", true},
+ {"connection", true},
+ {"content-encoding", true},
+ {"content-language", true},
+ {"expect", true},
+ {"if-match", true},
+ {"if-none-match", true},
+ {"proxy-authenticate", true},
+ {"public", true},
+ {"range", true},
+ {"transfer-encoding", true},
+ {"upgrade", true},
+ {"vary", true},
+ {"via", true},
+ {"warning", true},
+ {"www-authenticate", true},
+ {"set-cookie", true},
+ {"set-cookie2", true}
+ };
+
+ // Extra
+ }
+
+ // Constructors
+
+ public WebHeaderCollection()
+ {
+ }
+
+ internal WebHeaderCollection(bool internallyCreated)
+ {
+ this.internallyCreated = internallyCreated;
+ }
+
+ public override string[] AllKeys
+ {
+ get { return (base.AllKeys); }
+ }
+
+ public override int Count
+ {
+ get { return (base.Count); }
+ }
+
+ public override KeysCollection Keys
+ {
+ get { return (base.Keys); }
+ }
+
+ public string this[HttpRequestHeader hrh]
+ {
+ get { return Get(RequestHeaderToString(hrh)); }
+
+ set { Add(RequestHeaderToString(hrh), value); }
+ }
+
+ public string this[HttpResponseHeader hrh]
+ {
+ get { return Get(ResponseHeaderToString(hrh)); }
+
+ set { Add(ResponseHeaderToString(hrh), value); }
+ }
+
+ // Methods
+
+ public void Add(string header)
+ {
+ if (header == null)
+ throw new ArgumentNullException("header");
+ var pos = header.IndexOf(':');
+ if (pos == -1)
+ throw new ArgumentException("no colon found", "header");
+ Add(header.Substring(0, pos),
+ header.Substring(pos + 1));
+ }
+
+ public override void Add(string name, string value)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+ if (internallyCreated && IsRestricted(name))
+ throw new ArgumentException("This header must be modified with the appropiate property.");
+ AddWithoutValidate(name, value);
+ }
+
+ protected void AddWithoutValidate(string headerName, string headerValue)
+ {
+ if (!IsHeaderName(headerName))
+ throw new ArgumentException("invalid header name: " + headerName, "headerName");
+ headerValue = headerValue == null ? String.Empty : headerValue.Trim();
+ if (!IsHeaderValue(headerValue))
+ throw new ArgumentException("invalid header value: " + headerValue, "headerValue");
+ base.Add(headerName, headerValue);
+ }
+
+ public override string[] GetValues(string header)
+ {
+ if (header == null)
+ throw new ArgumentNullException("header");
+
+ var values = base.GetValues(header);
+ if (values == null || values.Length == 0)
+ return null;
+
+ /*
+ if (IsMultiValue (header)) {
+ values = GetMultipleValues (values);
+ }
+ */
+
+ return values;
+ }
+
+ public override string[] GetValues(int index)
+ {
+ var values = base.GetValues(index);
+ if (values == null || values.Length == 0)
+ {
+ return (null);
+ }
+
+ return (values);
+ }
+
+ /* Now i wonder why this is here...
+ static string [] GetMultipleValues (string [] values)
+ {
+ ArrayList mvalues = new ArrayList (values.Length);
+ StringBuilder sb = null;
+ for (int i = 0; i < values.Length; ++i) {
+ string val = values [i];
+ if (val.IndexOf (',') == -1) {
+ mvalues.Add (val);
+ continue;
+ }
+
+ if (sb == null)
+ sb = new StringBuilder ();
+
+ bool quote = false;
+ for (int k = 0; k < val.Length; k++) {
+ char c = val [k];
+ if (c == '"') {
+ quote = !quote;
+ } else if (!quote && c == ',') {
+ mvalues.Add (sb.ToString ().Trim ());
+ sb.Length = 0;
+ continue;
+ }
+ sb.Append (c);
+ }
+
+ if (sb.Length > 0) {
+ mvalues.Add (sb.ToString ().Trim ());
+ sb.Length = 0;
+ }
+ }
+
+ return (string []) mvalues.ToArray (typeof (string));
+ }
+ */
+
+ public static bool IsRestricted(string headerName)
+ {
+ if (headerName == null)
+ throw new ArgumentNullException("headerName");
+
+ if (headerName == "") // MS throw nullexception here!
+ throw new ArgumentException("empty string", "headerName");
+
+ return _restricted.ContainsKey(headerName);
+ }
+
+ public static bool IsRestricted(string headerName, bool response)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void Remove(string name)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+ if (internallyCreated && IsRestricted(name))
+ throw new ArgumentException("restricted header");
+ base.Remove(name);
+ }
+
+ public override void Set(string name, string value)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+ if (internallyCreated && IsRestricted(name))
+ throw new ArgumentException("restricted header");
+ if (!IsHeaderName(name))
+ throw new ArgumentException("invalid header name");
+ value = value == null ? String.Empty : value.Trim();
+ if (!IsHeaderValue(value))
+ throw new ArgumentException("invalid header value");
+ base.Set(name, value);
+ }
+
+ public byte[] ToByteArray()
+ {
+ return Encoding.UTF8.GetBytes(ToString());
+ }
+
+ public override string ToString()
+ {
+ var sb = new StringBuilder();
+
+ var count = base.Count;
+ for (var i = 0; i < count; i++)
+ sb.Append(GetKey(i))
+ .Append(": ")
+ .Append(Get(i))
+ .Append("\r\n");
+
+ return sb.Append("\r\n").ToString();
+ }
+
+ public override string Get(int index)
+ {
+ return (base.Get(index));
+ }
+
+ public override string Get(string name)
+ {
+ return (base.Get(name));
+ }
+
+ public override string GetKey(int index)
+ {
+ return (base.GetKey(index));
+ }
+
+ public void Add(HttpRequestHeader header, string value)
+ {
+ Add(RequestHeaderToString(header), value);
+ }
+
+ public void Remove(HttpRequestHeader header)
+ {
+ Remove(RequestHeaderToString(header));
+ }
+
+ public void Set(HttpRequestHeader header, string value)
+ {
+ Set(RequestHeaderToString(header), value);
+ }
+
+ public void Add(HttpResponseHeader header, string value)
+ {
+ Add(ResponseHeaderToString(header), value);
+ }
+
+ public void Remove(HttpResponseHeader header)
+ {
+ Remove(ResponseHeaderToString(header));
+ }
+
+ public void Set(HttpResponseHeader header, string value)
+ {
+ Set(ResponseHeaderToString(header), value);
+ }
+
+ private static string RequestHeaderToString(HttpRequestHeader value)
+ {
+ switch (value)
+ {
+ case HttpRequestHeader.CacheControl:
+ return "cache-control";
+ case HttpRequestHeader.Connection:
+ return "connection";
+ case HttpRequestHeader.Date:
+ return "date";
+ case HttpRequestHeader.KeepAlive:
+ return "keep-alive";
+ case HttpRequestHeader.Pragma:
+ return "pragma";
+ case HttpRequestHeader.Trailer:
+ return "trailer";
+ case HttpRequestHeader.TransferEncoding:
+ return "transfer-encoding";
+ case HttpRequestHeader.Upgrade:
+ return "upgrade";
+ case HttpRequestHeader.Via:
+ return "via";
+ case HttpRequestHeader.Warning:
+ return "warning";
+ case HttpRequestHeader.Allow:
+ return "allow";
+ case HttpRequestHeader.ContentLength:
+ return "content-length";
+ case HttpRequestHeader.ContentType:
+ return "content-type";
+ case HttpRequestHeader.ContentEncoding:
+ return "content-encoding";
+ case HttpRequestHeader.ContentLanguage:
+ return "content-language";
+ case HttpRequestHeader.ContentLocation:
+ return "content-location";
+ case HttpRequestHeader.ContentMd5:
+ return "content-md5";
+ case HttpRequestHeader.ContentRange:
+ return "content-range";
+ case HttpRequestHeader.Expires:
+ return "expires";
+ case HttpRequestHeader.LastModified:
+ return "last-modified";
+ case HttpRequestHeader.Accept:
+ return "accept";
+ case HttpRequestHeader.AcceptCharset:
+ return "accept-charset";
+ case HttpRequestHeader.AcceptEncoding:
+ return "accept-encoding";
+ case HttpRequestHeader.AcceptLanguage:
+ return "accept-language";
+ case HttpRequestHeader.Authorization:
+ return "authorization";
+ case HttpRequestHeader.Cookie:
+ return "cookie";
+ case HttpRequestHeader.Expect:
+ return "expect";
+ case HttpRequestHeader.From:
+ return "from";
+ case HttpRequestHeader.Host:
+ return "host";
+ case HttpRequestHeader.IfMatch:
+ return "if-match";
+ case HttpRequestHeader.IfModifiedSince:
+ return "if-modified-since";
+ case HttpRequestHeader.IfNoneMatch:
+ return "if-none-match";
+ case HttpRequestHeader.IfRange:
+ return "if-range";
+ case HttpRequestHeader.IfUnmodifiedSince:
+ return "if-unmodified-since";
+ case HttpRequestHeader.MaxForwards:
+ return "max-forwards";
+ case HttpRequestHeader.ProxyAuthorization:
+ return "proxy-authorization";
+ case HttpRequestHeader.Referer:
+ return "referer";
+ case HttpRequestHeader.Range:
+ return "range";
+ case HttpRequestHeader.Te:
+ return "te";
+ case HttpRequestHeader.Translate:
+ return "translate";
+ case HttpRequestHeader.UserAgent:
+ return "user-agent";
+ default:
+ throw new InvalidOperationException();
+ }
+ }
+
+
+ private static string ResponseHeaderToString(HttpResponseHeader value)
+ {
+ switch (value)
+ {
+ case HttpResponseHeader.CacheControl:
+ return "cache-control";
+ case HttpResponseHeader.Connection:
+ return "connection";
+ case HttpResponseHeader.Date:
+ return "date";
+ case HttpResponseHeader.KeepAlive:
+ return "keep-alive";
+ case HttpResponseHeader.Pragma:
+ return "pragma";
+ case HttpResponseHeader.Trailer:
+ return "trailer";
+ case HttpResponseHeader.TransferEncoding:
+ return "transfer-encoding";
+ case HttpResponseHeader.Upgrade:
+ return "upgrade";
+ case HttpResponseHeader.Via:
+ return "via";
+ case HttpResponseHeader.Warning:
+ return "warning";
+ case HttpResponseHeader.Allow:
+ return "allow";
+ case HttpResponseHeader.ContentLength:
+ return "content-length";
+ case HttpResponseHeader.ContentType:
+ return "content-type";
+ case HttpResponseHeader.ContentEncoding:
+ return "content-encoding";
+ case HttpResponseHeader.ContentLanguage:
+ return "content-language";
+ case HttpResponseHeader.ContentLocation:
+ return "content-location";
+ case HttpResponseHeader.ContentMd5:
+ return "content-md5";
+ case HttpResponseHeader.ContentRange:
+ return "content-range";
+ case HttpResponseHeader.Expires:
+ return "expires";
+ case HttpResponseHeader.LastModified:
+ return "last-modified";
+ case HttpResponseHeader.AcceptRanges:
+ return "accept-ranges";
+ case HttpResponseHeader.Age:
+ return "age";
+ case HttpResponseHeader.ETag:
+ return "etag";
+ case HttpResponseHeader.Location:
+ return "location";
+ case HttpResponseHeader.ProxyAuthenticate:
+ return "proxy-authenticate";
+ case HttpResponseHeader.RetryAfter:
+ return "RetryAfter";
+ case HttpResponseHeader.Server:
+ return "server";
+ case HttpResponseHeader.SetCookie:
+ return "set-cookie";
+ case HttpResponseHeader.Vary:
+ return "vary";
+ case HttpResponseHeader.WwwAuthenticate:
+ return "www-authenticate";
+ default:
+ throw new InvalidOperationException();
+ }
+ }
+
+ public override IEnumerator GetEnumerator()
+ {
+ return (base.GetEnumerator());
+ }
+
+ // Internal Methods
+
+ // With this we don't check for invalid characters in header. See bug #55994.
+ internal void SetInternal(string header)
+ {
+ var pos = header.IndexOf(':');
+ if (pos == -1)
+ throw new ArgumentException("no colon found", "header");
+
+ SetInternal(header.Substring(0, pos), header.Substring(pos + 1));
+ }
+
+ internal void SetInternal(string name, string value)
+ {
+ value = value == null ? String.Empty : value.Trim();
+ if (!IsHeaderValue(value))
+ throw new ArgumentException("invalid header value");
+
+ if (IsMultiValue(name))
+ {
+ base.Add(name, value);
+ }
+ else
+ {
+ base.Remove(name);
+ base.Set(name, value);
+ }
+ }
+
+ internal void RemoveAndAdd(string name, string value)
+ {
+ value = value == null ? String.Empty : value.Trim();
+
+ base.Remove(name);
+ base.Set(name, value);
+ }
+
+ internal void RemoveInternal(string name)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+ base.Remove(name);
+ }
+
+ internal static bool IsMultiValue(string headerName)
+ {
+ return !string.IsNullOrEmpty(headerName) && _multiValue.ContainsKey(headerName);
+ }
+
+ internal static bool IsHeaderValue(string value)
+ {
+ // TEXT any 8 bit value except CTL's (0-31 and 127)
+ // but including \r\n space and \t
+ // after a newline at least one space or \t must follow
+ // certain header fields allow comments ()
+
+ var len = value.Length;
+ for (var i = 0; i < len; i++)
+ {
+ var c = value[i];
+ if (c == 127)
+ return false;
+ if (c < 0x20 && (c != '\r' && c != '\n' && c != '\t'))
+ return false;
+ if (c == '\n' && ++i < len)
+ {
+ c = value[i];
+ if (c != ' ' && c != '\t')
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ internal static bool IsHeaderName(string name)
+ {
+ // token = 1*<any CHAR except CTLs or tspecials>
+ // tspecials = "(" | ")" | "<" | ">" | "@"
+ // | "," | ";" | ":" | "\" | <">
+ // | "/" | "[" | "]" | "?" | "="
+ // | "{" | "}" | SP | HT
+
+ if (string.IsNullOrEmpty(name))
+ return false;
+
+ var len = name.Length;
+ for (var i = 0; i < len; i++)
+ {
+ var c = name[i];
+ if (c < 0x20 || c >= 0x7f)
+ return false;
+ }
+
+ return name.IndexOfAny(tspecials) == -1;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Security;
+
+// 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("Hammock")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apitize")]
+[assembly: AssemblyProduct("Hammock")]
+[assembly: AssemblyCopyright("Copyright © Daniel Crenna and Jason Diller")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: AllowPartiallyTrustedCallers]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("f7ca855b-bb0d-4b54-a093-55dce9e57012")]
+
+// 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 Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: SecurityRules(SecurityRuleSet.Level1)]
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.50727</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{5953279F-F478-4D5F-9906-03D56CE2DA2D}</ProjectGuid>
+ <ProjectTypeGuids>{A1591282-1198-4647-A2B1-27E5FF5F6F3B};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>ICSharpCode.SharpZipLib.Silverlight</RootNamespace>
+ <AssemblyName>ICSharpCode.SharpZipLib.Silverlight</AssemblyName>
+ <TargetFrameworkIdentifier>Silverlight</TargetFrameworkIdentifier>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion>
+ <SilverlightApplication>false</SilverlightApplication>
+ <ValidateXaml>true</ValidateXaml>
+ <ThrowErrorsInValidation>true</ThrowErrorsInValidation>
+ <SignManifests>false</SignManifests>
+ <TargetFrameworkProfile />
+ </PropertyGroup>
+ <!-- This property group is only here to support building this project using the
+ MSBuild 3.5 toolset. In order to work correctly with this older toolset, it needs
+ to set the TargetFrameworkVersion to v3.5 -->
+ <PropertyGroup Condition="'$(MSBuildToolsVersion)' == '3.5'">
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>Bin\Debug</OutputPath>
+ <DefineConstants>TRACE;DEBUG;SILVERLIGHT,SL4</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>Bin\Release</OutputPath>
+ <DefineConstants>TRACE;SILVERLIGHT,SL4</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup>
+ <SignAssembly>true</SignAssembly>
+ </PropertyGroup>
+ <PropertyGroup>
+ <AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="mscorlib" />
+ <Reference Include="System.Windows" />
+ <Reference Include="system" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Net" />
+ <Reference Include="System.Windows.Browser" />
+ <Reference Include="System.Xml, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, processorArchitecture=MSIL" />
+ <Reference Include="System.Xml.Linq, Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\BZip2\BZip2.cs">
+ <Link>BZip2\BZip2.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\BZip2\BZip2Constants.cs">
+ <Link>BZip2\BZip2Constants.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\BZip2\BZip2Exception.cs">
+ <Link>BZip2\BZip2Exception.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\BZip2\BZip2InputStream.cs">
+ <Link>BZip2\BZip2InputStream.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\BZip2\BZip2OutputStream.cs">
+ <Link>BZip2\BZip2OutputStream.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Checksums\Adler32.cs">
+ <Link>Checksums\Adler32.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Checksums\CRC32.cs">
+ <Link>Checksums\CRC32.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Checksums\IChecksum.cs">
+ <Link>Checksums\IChecksum.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Checksums\StrangeCRC.cs">
+ <Link>Checksums\StrangeCRC.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Compat\Extensions.cs">
+ <Link>Compat\Extensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Core\FileSystemScanner.cs">
+ <Link>Core\FileSystemScanner.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Core\INameTransform.cs">
+ <Link>Core\INameTransform.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Core\IScanFilter.cs">
+ <Link>Core\IScanFilter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Core\NameFilter.cs">
+ <Link>Core\NameFilter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Core\PathFilter.cs">
+ <Link>Core\PathFilter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Core\StreamUtils.cs">
+ <Link>Core\StreamUtils.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Encryption\PkzipClassic.cs">
+ <Link>Encryption\PkzipClassic.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\GZip\GZIPConstants.cs">
+ <Link>GZip\GZIPConstants.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\GZip\GZipException.cs">
+ <Link>GZip\GZipException.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\GZip\GzipInputStream.cs">
+ <Link>GZip\GzipInputStream.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\GZip\GzipOutputStream.cs">
+ <Link>GZip\GzipOutputStream.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Serialization\ISerializable.cs">
+ <Link>Serialization\ISerializable.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Serialization\NonSerializedAttribute.cs">
+ <Link>Serialization\NonSerializedAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Serialization\SerializableAttribute.cs">
+ <Link>Serialization\SerializableAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Serialization\SerializableBase.cs">
+ <Link>Serialization\SerializableBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Serialization\SerializableDateTime.cs">
+ <Link>Serialization\SerializableDateTime.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Serialization\SerializableString.cs">
+ <Link>Serialization\SerializableString.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Serialization\SerializationInfo.cs">
+ <Link>Serialization\SerializationInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Serialization\XmlFormatter.Deserialize.cs">
+ <Link>Serialization\XmlFormatter.Deserialize.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Serialization\XmlFormatter.Serialize.cs">
+ <Link>Serialization\XmlFormatter.Serialize.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\SharpZipBaseException.cs">
+ <Link>SharpZipBaseException.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Tar\InvalidHeaderException.cs">
+ <Link>Tar\InvalidHeaderException.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Tar\TarArchive.cs">
+ <Link>Tar\TarArchive.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Tar\TarBuffer.cs">
+ <Link>Tar\TarBuffer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Tar\TarEntry.cs">
+ <Link>Tar\TarEntry.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Tar\TarException.cs">
+ <Link>Tar\TarException.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Tar\TarHeader.cs">
+ <Link>Tar\TarHeader.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Tar\TarInputStream.cs">
+ <Link>Tar\TarInputStream.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Tar\TarOutputStream.cs">
+ <Link>Tar\TarOutputStream.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\Compression\Deflater.cs">
+ <Link>Zip\Compression\Deflater.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\Compression\DeflaterConstants.cs">
+ <Link>Zip\Compression\DeflaterConstants.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\Compression\DeflaterEngine.cs">
+ <Link>Zip\Compression\DeflaterEngine.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\Compression\DeflaterHuffman.cs">
+ <Link>Zip\Compression\DeflaterHuffman.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\Compression\DeflaterPending.cs">
+ <Link>Zip\Compression\DeflaterPending.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\Compression\Inflater.cs">
+ <Link>Zip\Compression\Inflater.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\Compression\InflaterDynHeader.cs">
+ <Link>Zip\Compression\InflaterDynHeader.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\Compression\InflaterHuffmanTree.cs">
+ <Link>Zip\Compression\InflaterHuffmanTree.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\Compression\PendingBuffer.cs">
+ <Link>Zip\Compression\PendingBuffer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\Compression\Streams\DeflaterOutputStream.cs">
+ <Link>Zip\Compression\Streams\DeflaterOutputStream.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\Compression\Streams\InflaterInputStream.cs">
+ <Link>Zip\Compression\Streams\InflaterInputStream.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\Compression\Streams\OutputWindow.cs">
+ <Link>Zip\Compression\Streams\OutputWindow.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\Compression\Streams\StreamManipulator.cs">
+ <Link>Zip\Compression\Streams\StreamManipulator.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\FastZip.cs">
+ <Link>Zip\FastZip.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\IEntryFactory.cs">
+ <Link>Zip\IEntryFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\ZipConstants.cs">
+ <Link>Zip\ZipConstants.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\ZipEntry.cs">
+ <Link>Zip\ZipEntry.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\ZipEntryFactory.cs">
+ <Link>Zip\ZipEntryFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\ZipException.cs">
+ <Link>Zip\ZipException.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\ZipExtraData.cs">
+ <Link>Zip\ZipExtraData.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\ZipFile.cs">
+ <Link>Zip\ZipFile.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\ZipHelperStream.cs">
+ <Link>Zip\ZipHelperStream.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\ZipInputStream.cs">
+ <Link>Zip\ZipInputStream.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\ZipNameTransform.cs">
+ <Link>Zip\ZipNameTransform.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\Zip\ZipOutputStream.cs">
+ <Link>Zip\ZipOutputStream.cs</Link>
+ </Compile>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="key.snk" />
+ </ItemGroup>
+ <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\$(SilverlightVersion)\Microsoft.Silverlight.CSharp.targets" />
+ <ProjectExtensions>
+ <VisualStudio>
+ <FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
+ <SilverlightProjectProperties />
+ </FlavorProperties>
+ </VisualStudio>
+ </ProjectExtensions>
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
\ No newline at end of file
--- /dev/null
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 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("ICSharpCode.SharpZipLib.Silverlight")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ICSharpCode.SharpZipLib.Silverlight")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("72802a97-fc94-4f09-b6d3-6796a938b0d0")]
+
+// 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.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>10.0.20506</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{BF04A546-D681-4F5A-AC41-CFC67CAEC66E}</ProjectGuid>
+ <ProjectTypeGuids>{C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>ICSharpCode.SharpZipLib.WindowsPhone</RootNamespace>
+ <AssemblyName>ICSharpCode.SharpZipLib.WindowsPhone</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion>
+ <TargetFrameworkProfile>WindowsPhone</TargetFrameworkProfile>
+ <TargetFrameworkIdentifier>Silverlight</TargetFrameworkIdentifier>
+ <SilverlightApplication>false</SilverlightApplication>
+ <ValidateXaml>true</ValidateXaml>
+ <ThrowErrorsInValidation>true</ThrowErrorsInValidation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>Bin\Debug</OutputPath>
+ <DefineConstants>DEBUG;TRACE;SILVERLIGHT</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>Bin\Release</OutputPath>
+ <DefineConstants>TRACE;SILVERLIGHT</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="mscorlib" />
+ <Reference Include="System.Windows" />
+ <Reference Include="system" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml" />
+ <Reference Include="System.Net" />
+ <Reference Include="System.Xml.Linq" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\bzip2\BZip2.cs">
+ <Link>BZip2\BZip2.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\bzip2\BZip2Constants.cs">
+ <Link>BZip2\BZip2Constants.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\bzip2\BZip2Exception.cs">
+ <Link>BZip2\BZip2Exception.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\bzip2\BZip2InputStream.cs">
+ <Link>BZip2\BZip2InputStream.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\bzip2\BZip2OutputStream.cs">
+ <Link>BZip2\BZip2OutputStream.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\checksums\Adler32.cs">
+ <Link>Checksums\Adler32.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\checksums\CRC32.cs">
+ <Link>Checksums\CRC32.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\checksums\IChecksum.cs">
+ <Link>Checksums\IChecksum.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\checksums\StrangeCRC.cs">
+ <Link>Checksums\StrangeCRC.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\compat\Extensions.cs">
+ <Link>Compat\Extensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\core\FileSystemScanner.cs">
+ <Link>Core\FileSystemScanner.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\core\INameTransform.cs">
+ <Link>Core\INameTransform.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\core\IScanFilter.cs">
+ <Link>Core\IScanFilter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\core\NameFilter.cs">
+ <Link>Core\NameFilter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\core\PathFilter.cs">
+ <Link>Core\PathFilter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\core\StreamUtils.cs">
+ <Link>Core\StreamUtils.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\encryption\PkzipClassic.cs">
+ <Link>Encryption\PkzipClassic.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\gzip\GZIPConstants.cs">
+ <Link>GZip\GZIPConstants.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\gzip\GZipException.cs">
+ <Link>GZip\GZipException.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\gzip\GzipInputStream.cs">
+ <Link>GZip\GzipInputStream.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\gzip\GzipOutputStream.cs">
+ <Link>GZip\GzipOutputStream.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\serialization\ISerializable.cs">
+ <Link>Serialization\ISerializable.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\serialization\NonSerializedAttribute.cs">
+ <Link>Serialization\NonSerializedAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\serialization\SerializableAttribute.cs">
+ <Link>Serialization\SerializableAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\serialization\SerializableBase.cs">
+ <Link>Serialization\SerializableBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\serialization\SerializableDateTime.cs">
+ <Link>Serialization\SerializableDateTime.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\serialization\SerializableString.cs">
+ <Link>Serialization\SerializableString.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\serialization\SerializationInfo.cs">
+ <Link>Serialization\SerializationInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\serialization\XmlFormatter.Deserialize.cs">
+ <Link>Serialization\XmlFormatter.Deserialize.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\serialization\XmlFormatter.Serialize.cs">
+ <Link>Serialization\XmlFormatter.Serialize.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\ICSharpCode.SharpZipLib.Silverlight\SharpZipBaseException.cs">
+ <Link>SharpZipBaseException.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\tar\InvalidHeaderException.cs">
+ <Link>Tar\InvalidHeaderException.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\tar\TarArchive.cs">
+ <Link>Tar\TarArchive.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\tar\TarBuffer.cs">
+ <Link>Tar\TarBuffer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\tar\TarEntry.cs">
+ <Link>Tar\TarEntry.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\tar\TarException.cs">
+ <Link>Tar\TarException.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\tar\TarHeader.cs">
+ <Link>Tar\TarHeader.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\tar\TarInputStream.cs">
+ <Link>Tar\TarInputStream.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\tar\TarOutputStream.cs">
+ <Link>Tar\TarOutputStream.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\compression\Deflater.cs">
+ <Link>Zip\Compression\Deflater.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\compression\DeflaterConstants.cs">
+ <Link>Zip\Compression\DeflaterConstants.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\compression\DeflaterEngine.cs">
+ <Link>Zip\Compression\DeflaterEngine.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\compression\DeflaterHuffman.cs">
+ <Link>Zip\Compression\DeflaterHuffman.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\compression\DeflaterPending.cs">
+ <Link>Zip\Compression\DeflaterPending.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\compression\Inflater.cs">
+ <Link>Zip\Compression\Inflater.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\compression\InflaterDynHeader.cs">
+ <Link>Zip\Compression\InflaterDynHeader.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\compression\InflaterHuffmanTree.cs">
+ <Link>Zip\Compression\InflaterHuffmanTree.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\compression\PendingBuffer.cs">
+ <Link>Zip\Compression\PendingBuffer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\compression\streams\DeflaterOutputStream.cs">
+ <Link>Zip\Compression\Streams\DeflaterOutputStream.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\compression\streams\InflaterInputStream.cs">
+ <Link>Zip\Compression\Streams\InflaterInputStream.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\compression\streams\OutputWindow.cs">
+ <Link>Zip\Compression\Streams\OutputWindow.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\compression\streams\StreamManipulator.cs">
+ <Link>Zip\Compression\Streams\StreamManipulator.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\FastZip.cs">
+ <Link>Zip\FastZip.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\IEntryFactory.cs">
+ <Link>Zip\IEntryFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\ZipConstants.cs">
+ <Link>Zip\ZipConstants.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\ZipEntry.cs">
+ <Link>Zip\ZipEntry.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\ZipEntryFactory.cs">
+ <Link>Zip\ZipEntryFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\ZipException.cs">
+ <Link>Zip\ZipException.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\ZipExtraData.cs">
+ <Link>Zip\ZipExtraData.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\ZipFile.cs">
+ <Link>Zip\ZipFile.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\ZipHelperStream.cs">
+ <Link>Zip\ZipHelperStream.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\ZipInputStream.cs">
+ <Link>Zip\ZipInputStream.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\ZipNameTransform.cs">
+ <Link>Zip\ZipNameTransform.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\icsharpcode.sharpziplib.silverlight\zip\ZipOutputStream.cs">
+ <Link>Zip\ZipOutputStream.cs</Link>
+ </Compile>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.$(TargetFrameworkProfile).Overrides.targets" />
+ <Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.CSharp.targets" />
+ <ProjectExtensions />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
\ No newline at end of file
--- /dev/null
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 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("ICSharpCode.SharpZipLib.WindowsPhone")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ICSharpCode.SharpZipLib.WindowsPhone")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("4b494cbd-3b70-4aab-b4cf-f827066a1a6a")]
+
+// 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.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{392866D3-D060-4F54-B761-2BAF509989CF}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Hammock.Compact</RootNamespace>
+ <AssemblyName>Hammock.Compact</AssemblyName>
+ <ProjectTypeGuids>{4D628B5B-2FBC-4AA6-8C16-197242AEB884};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <PlatformFamilyName>WindowsCE</PlatformFamilyName>
+ <PlatformID>E2BECB1F-8C8C-41ba-B736-9BE7D946A398</PlatformID>
+ <OSVersion>5.0</OSVersion>
+ <DeployDirSuffix>Hammock</DeployDirSuffix>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <NativePlatformName>Windows CE</NativePlatformName>
+ <FormFactorID>
+ </FormFactorID>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\bin\lib\Compact\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;WindowsCE NETCF</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <FileAlignment>512</FileAlignment>
+ <WarningLevel>4</WarningLevel>
+ <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\bin\lib\Compact\</OutputPath>
+ <DefineConstants>TRACE;WindowsCE NETCF</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <FileAlignment>512</FileAlignment>
+ <WarningLevel>4</WarningLevel>
+ <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="mscorlib" />
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\..\net35\Hammock\Attributes\INamedAttribute.cs">
+ <Link>Attributes\INamedAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\IValidatingAttribute.cs">
+ <Link>Attributes\IValidatingAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\EntityAttribute.cs">
+ <Link>Attributes\Specialized\EntityAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\HeaderAttribute.cs">
+ <Link>Attributes\Specialized\HeaderAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\ParameterAttribute.cs">
+ <Link>Attributes\Specialized\ParameterAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Specialized\UserAgentAttribute.cs">
+ <Link>Attributes\Specialized\UserAgentAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\BooleanToIntegerAttribute.cs">
+ <Link>Attributes\Validation\BooleanToIntegerAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\DateTimeFormatAttribute.cs">
+ <Link>Attributes\Validation\DateTimeFormatAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\RequiredAttribute.cs">
+ <Link>Attributes\Validation\RequiredAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\SpecificationAttribute.cs">
+ <Link>Attributes\Validation\SpecificationAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Attributes\Validation\ValidationAttribute.cs">
+ <Link>Attributes\Validation\ValidationAttribute.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\Basic\BasicAuthCredentials.cs">
+ <Link>Authentication\Basic\BasicAuthCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\IWebCredentials.cs">
+ <Link>Authentication\IWebCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthCredentials.cs">
+ <Link>Authentication\OAuth\OAuthCredentials.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthParameterHandling.cs">
+ <Link>Authentication\OAuth\OAuthParameterHandling.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthSignatureMethod.cs">
+ <Link>Authentication\OAuth\OAuthSignatureMethod.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthToken.cs">
+ <Link>Authentication\OAuth\OAuthToken.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthTools.cs">
+ <Link>Authentication\OAuth\OAuthTools.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthType.cs">
+ <Link>Authentication\OAuth\OAuthType.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWebQuery.cs">
+ <Link>Authentication\OAuth\OAuthWebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWebQueryInfo.cs">
+ <Link>Authentication\OAuth\OAuthWebQueryInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Authentication\OAuth\OAuthWorkflow.cs">
+ <Link>Authentication\OAuth\OAuthWorkflow.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheFactory.cs">
+ <Link>Caching\CacheFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheMode.cs">
+ <Link>Caching\CacheMode.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\CacheOptions.cs">
+ <Link>Caching\CacheOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\ICache.cs">
+ <Link>Caching\ICache.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Caching\SimpleCache.cs">
+ <Link>Caching\SimpleCache.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\CollectionExtensions.cs">
+ <Link>Extensions\CollectionExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\FormatExtensions.cs">
+ <Link>Extensions\FormatExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\OAuthExtensions.cs">
+ <Link>Extensions\OAuthExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\ObjectExtensions.cs">
+ <Link>Extensions\ObjectExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\ReflectionExtensions.cs">
+ <Link>Extensions\ReflectionExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\SpecificationExtensions.cs">
+ <Link>Extensions\SpecificationExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\StringExtensions.cs">
+ <Link>Extensions\StringExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\TimeExtensions.cs">
+ <Link>Extensions\TimeExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Extensions\WebExtensions.cs">
+ <Link>Extensions\WebExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\IRestClient.cs">
+ <Link>IRestClient.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Model\PropertyChangedBase.cs">
+ <Link>Model\PropertyChangedBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Mono\HttpUtility.cs">
+ <Link>Mono\HttpUtility.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestBase.cs">
+ <Link>RestBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestCallback.cs">
+ <Link>RestCallback.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestClient.cs">
+ <Link>RestClient.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestRequest.cs">
+ <Link>RestRequest.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\RestResponse.cs">
+ <Link>RestResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\ConnectionClosed.cs">
+ <Link>Retries\ConnectionClosed.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\IRetryCondition.cs">
+ <Link>Retries\IRetryCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\IRetryCustomCondition.cs">
+ <Link>Retries\IRetryCustomCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\NetworkError.cs">
+ <Link>Retries\NetworkError.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryCondition.cs">
+ <Link>Retries\RetryCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryCustomCondition.cs">
+ <Link>Retries\RetryCustomCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryErrorCondition.cs">
+ <Link>Retries\RetryErrorCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryPolicy.cs">
+ <Link>Retries\RetryPolicy.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\RetryResultCondition.cs">
+ <Link>Retries\RetryResultCondition.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Retries\Timeout.cs">
+ <Link>Retries\Timeout.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\DefaultJsonSerializer.cs">
+ <Link>Serialization\DefaultJsonSerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\HammockXmlSerializer.cs">
+ <Link>Serialization\HammockXmlSerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\IDeserializer.cs">
+ <Link>Serialization\IDeserializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\ISerializer.cs">
+ <Link>Serialization\ISerializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\JsonParser.cs">
+ <Link>Serialization\JsonParser.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Serialization\Utf8Serializer.cs">
+ <Link>Serialization\Utf8Serializer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\AndSpecification.cs">
+ <Link>Specifications\AndSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\CompositeSpecificationBase.cs">
+ <Link>Specifications\CompositeSpecificationBase.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\HammockSpecification.cs">
+ <Link>Specifications\HammockSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\ISpecification.cs">
+ <Link>Specifications\ISpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\NotSpecification.cs">
+ <Link>Specifications\NotSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Specifications\OrSpecification.cs">
+ <Link>Specifications\OrSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Streaming\StreamOptions.cs">
+ <Link>Streaming\StreamOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\IRateLimitingRule.cs">
+ <Link>Tasks\IRateLimitingRule.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\IRateLimitStatus.cs">
+ <Link>Tasks\IRateLimitStatus.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITaskOptions.cs">
+ <Link>Tasks\ITaskOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITaskState.cs">
+ <Link>Tasks\ITaskState.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\ITimedTask.cs">
+ <Link>Tasks\ITimedTask.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\RateLimitingRule.cs">
+ <Link>Tasks\RateLimitingRule.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\RateLimitType.cs">
+ <Link>Tasks\RateLimitType.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TaskOptions.cs">
+ <Link>Tasks\TaskOptions.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TaskState.cs">
+ <Link>Tasks\TaskState.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Tasks\TimedTask.cs">
+ <Link>Tasks\TimedTask.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Validation\ValidationException.cs">
+ <Link>Validation\ValidationException.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Validation\ValidEmailSpecification.cs">
+ <Link>Validation\ValidEmailSpecification.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\BasicAuthWebQuery.cs">
+ <Link>Web\BasicAuthWebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\GetOrDelete.cs">
+ <Link>Web\GetOrDelete.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\HttpCookieParameter.cs">
+ <Link>Web\HttpCookieParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\HttpPostParameter.cs">
+ <Link>Web\HttpPostParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\HttpPostParameterType.cs">
+ <Link>Web\HttpPostParameterType.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\IWebQueryInfo.cs">
+ <Link>Web\IWebQueryInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\IMockable.cs">
+ <Link>Web\Mocks\IMockable.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\IWebResponse.cs">
+ <Link>Web\Mocks\IWebResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockHttpWebRequest.cs">
+ <Link>Web\Mocks\MockHttpWebRequest.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockHttpWebResponse.cs">
+ <Link>Web\Mocks\MockHttpWebResponse.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Mocks\MockWebRequestFactory.cs">
+ <Link>Web\Mocks\MockWebRequestFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Pair.cs">
+ <Link>Web\Pair.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\PostOrPut.cs">
+ <Link>Web\PostOrPut.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\Triplet.cs">
+ <Link>Web\Triplet.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebCallback.cs">
+ <Link>Web\WebCallback.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebEntity.cs">
+ <Link>Web\WebEntity.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebHeader.cs">
+ <Link>Web\WebHeader.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebHeaderCollection.cs">
+ <Link>Web\WebHeaderCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebMethod.cs">
+ <Link>Web\WebMethod.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebPair.cs">
+ <Link>Web\WebPair.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebPairCollection.cs">
+ <Link>Web\WebPairCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebParameter.cs">
+ <Link>Web\WebParameter.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebParameterCollection.cs">
+ <Link>Web\WebParameterCollection.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQuery.Async.cs">
+ <Link>Web\WebQuery.Async.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQuery.cs">
+ <Link>Web\WebQuery.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryAsyncResult.cs">
+ <Link>Web\WebQueryAsyncResult.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryRequestEventArgs.cs">
+ <Link>Web\WebQueryRequestEventArgs.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryResponseEventArgs.cs">
+ <Link>Web\WebQueryResponseEventArgs.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net35\Hammock\Web\WebQueryResult.cs">
+ <Link>Web\WebQueryResult.cs</Link>
+ </Compile>
+ <Compile Include="Mono\Security\Cryptography\BlockProcessor.cs" />
+ <Compile Include="Mono\Security\Cryptography\HMACAlgorithm.cs" />
+ <Compile Include="Mono\Security\Cryptography\KeyBuilder.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Security\Cryptography\HMACSHA1.cs" />
+ <Compile Include="Security\Cryptography\KeyedHashAlgorithm.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.targets" />
+ <ProjectExtensions>
+ <VisualStudio>
+ <FlavorProperties GUID="{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}">
+ <HostingProcess disable="1" />
+ </FlavorProperties>
+ </VisualStudio>
+ </ProjectExtensions>
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Security.Cryptography;
+
+namespace Hammock.Mono.Security.Cryptography
+{
+ public class BlockProcessor
+ {
+ private ICryptoTransform transform;
+ private byte[] block;
+ private int blockSize;
+ private int blockCount;
+
+ public BlockProcessor(ICryptoTransform transform)
+ : this(transform, transform.InputBlockSize)
+ {
+ }
+
+ public BlockProcessor(ICryptoTransform transform, int blockSize)
+ {
+ this.transform = transform;
+ this.blockSize = blockSize;
+ this.block = new byte[blockSize];
+ }
+
+ ~BlockProcessor()
+ {
+ Array.Clear((Array)this.block, 0, this.blockSize);
+ }
+
+ public void Initialize()
+ {
+ Array.Clear((Array)this.block, 0, this.blockSize);
+ this.blockCount = 0;
+ }
+
+ public void Core(byte[] rgb)
+ {
+ this.Core(rgb, 0, rgb.Length);
+ }
+
+ public void Core(byte[] rgb, int ib, int cb)
+ {
+ int count = Math.Min(this.blockSize - this.blockCount, cb);
+ Buffer.BlockCopy((Array)rgb, ib, (Array)this.block, this.blockCount, count);
+ this.blockCount += count;
+ if (this.blockCount == this.blockSize)
+ {
+ this.transform.TransformBlock(this.block, 0, this.blockSize, this.block, 0);
+ int num = (cb - count) / this.blockSize;
+ for (int index = 0; index < num; ++index)
+ {
+ this.transform.TransformBlock(rgb, count + ib, this.blockSize, this.block, 0);
+ count += this.blockSize;
+ }
+ this.blockCount = cb - count;
+ if (this.blockCount > 0)
+ Buffer.BlockCopy((Array)rgb, count + ib, (Array)this.block, 0, this.blockCount);
+ }
+ }
+
+ public byte[] Final()
+ {
+ return this.transform.TransformFinalBlock(this.block, 0, this.blockCount);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Security.Cryptography;
+
+namespace Hammock.Mono.Security.Cryptography
+{
+ internal class HMACAlgorithm
+ {
+ private HashAlgorithm algo;
+ private BlockProcessor block;
+ private byte[] hash;
+ private string hashName;
+ private byte[] key;
+
+ public HashAlgorithm Algo
+ {
+ get
+ {
+ return this.algo;
+ }
+ }
+
+ public string HashName
+ {
+ get
+ {
+ return this.hashName;
+ }
+ set
+ {
+ this.CreateHash(value);
+ }
+ }
+
+ public byte[] Key
+ {
+ get
+ {
+ return this.key;
+ }
+ set
+ {
+ if (value != null && value.Length > 64)
+ this.key = this.algo.ComputeHash(value);
+ else if (value != null)
+ this.key = (byte[])value.Clone();
+ }
+ }
+
+ public HMACAlgorithm(string algoName)
+ {
+ this.CreateHash(algoName);
+ }
+
+ ~HMACAlgorithm()
+ {
+ this.Dispose();
+ }
+
+ private void CreateHash(string algoName)
+ {
+ this.algo = HashAlgorithm.Create(algoName);
+ this.hashName = algoName;
+ this.block = new BlockProcessor((ICryptoTransform)this.algo, 8);
+ }
+
+ public void Dispose()
+ {
+ if (this.key != null)
+ Array.Clear((Array)this.key, 0, this.key.Length);
+ }
+
+ public void Initialize()
+ {
+ this.hash = (byte[])null;
+ this.block.Initialize();
+ byte[] rgb = HMACAlgorithm.KeySetup(this.key, (byte)54);
+ this.algo.Initialize();
+ this.block.Core(rgb);
+ Array.Clear((Array)rgb, 0, rgb.Length);
+ }
+
+ private static byte[] KeySetup(byte[] key, byte padding)
+ {
+ byte[] numArray = new byte[64];
+ for (int index = 0; index < key.Length; ++index)
+ numArray[index] = (byte)((uint)key[index] ^ (uint)padding);
+ for (int length = key.Length; length < 64; ++length)
+ numArray[length] = padding;
+ return numArray;
+ }
+
+ public void Core(byte[] rgb, int ib, int cb)
+ {
+ this.block.Core(rgb, ib, cb);
+ }
+
+ public byte[] Final()
+ {
+ this.block.Final();
+ byte[] hash = this.algo.Hash;
+ byte[] numArray = HMACAlgorithm.KeySetup(this.key, (byte)92);
+ this.algo.Initialize();
+ this.algo.TransformBlock(numArray, 0, numArray.Length, numArray, 0);
+ this.algo.TransformFinalBlock(hash, 0, hash.Length);
+ this.hash = this.algo.Hash;
+ Array.Clear((Array)numArray, 0, numArray.Length);
+ Array.Clear((Array)hash, 0, hash.Length);
+ return this.hash;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Security.Cryptography;
+
+namespace Hammock.Mono.Security.Cryptography
+{
+ public static class KeyBuilder
+ {
+ private static RandomNumberGenerator rng;
+
+ private static RandomNumberGenerator Rng
+ {
+ get { return rng ?? (rng = RandomNumberGenerator.Create()); }
+ }
+
+ public static byte[] Key(int size)
+ {
+ var data = new byte[size];
+ Rng.GetBytes(data);
+ return data;
+ }
+
+ public static byte[] IV(int size)
+ {
+ var data = new byte[size];
+ Rng.GetBytes(data);
+ return data;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 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("Hammock.Compact")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Hammock.Compact")]
+[assembly: AssemblyCopyright("Copyright © Daniel Crenna and Jason Diller")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("3742e2d3-7b88-4663-816d-1c81cb853fb0")]
+
+// 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.*")]
+
--- /dev/null
+using System;
+using System.Security.Cryptography;
+using Hammock.Mono.Security.Cryptography;
+
+namespace Hammock.Security.Cryptography
+{
+ public class HMACSHA1 : KeyedHashAlgorithm
+ {
+ private readonly HMACAlgorithm hmac;
+ private bool m_disposed;
+
+ public override sealed byte[] Key
+ {
+ get
+ {
+ return base.Key;
+ }
+ set
+ {
+ this.hmac.Key = value;
+ base.Key = value;
+ }
+ }
+
+ public string HashName
+ {
+ get
+ {
+ return this.hmac.HashName;
+ }
+ set
+ {
+ if (this.State == 0)
+ this.hmac.HashName = value;
+ }
+ }
+
+ public HMACSHA1()
+ : this(KeyBuilder.Key(8))
+ {
+ }
+
+ public HMACSHA1(byte[] rgbKey)
+ {
+ this.hmac = new HMACAlgorithm("SHA1");
+ this.HashSizeValue = 160;
+ this.Key = rgbKey;
+ this.m_disposed = false;
+ }
+
+ ~HMACSHA1()
+ {
+ this.Dispose(false);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (!this.m_disposed)
+ {
+ if (this.hmac != null)
+ this.hmac.Dispose();
+ base.Dispose(disposing);
+ this.m_disposed = true;
+ }
+ }
+
+ public override void Initialize()
+ {
+ if (this.m_disposed)
+ throw new ObjectDisposedException("HMACSHA1");
+ else if (!(this.hmac.Algo is SHA1))
+ {
+ throw new InvalidCastException(string.Format("Invalid hash algorithm '{0}', expected '{1}'.", this.hmac.Algo == null ? (object)"none" : (object)this.hmac.Algo.GetType().ToString(), (object)"SHA1"));
+ }
+ else
+ {
+ this.State = 0;
+ this.hmac.Initialize();
+ }
+ }
+
+ protected override void HashCore(byte[] rgb, int ib, int cb)
+ {
+ if (this.m_disposed)
+ {
+ throw new ObjectDisposedException("HMACSHA1");
+ }
+ else
+ {
+ if (this.State == 0)
+ {
+ this.Initialize();
+ this.State = 1;
+ }
+ this.hmac.Core(rgb, ib, cb);
+ }
+ }
+
+ protected override byte[] HashFinal()
+ {
+ if (this.m_disposed)
+ {
+ throw new ObjectDisposedException("HMACSHA1");
+ }
+ else
+ {
+ this.State = 0;
+ return this.hmac.Final();
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Security.Cryptography;
+
+namespace Hammock.Security.Cryptography
+{
+ public abstract class KeyedHashAlgorithm : HashAlgorithm
+ {
+ protected byte[] KeyValue;
+
+ public virtual byte[] Key
+ {
+ get
+ {
+ return (byte[])this.KeyValue.Clone();
+ }
+ set
+ {
+ if (this.State != 0)
+ {
+ throw new CryptographicException("Key can't be changed at this state.");
+ }
+
+ this.ZeroizeKey();
+ this.KeyValue = (byte[])value.Clone();
+ }
+ }
+
+ ~KeyedHashAlgorithm()
+ {
+ this.Dispose(false);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ this.ZeroizeKey();
+ base.Dispose(disposing);
+ }
+
+ private void ZeroizeKey()
+ {
+ if (this.KeyValue != null)
+ Array.Clear(this.KeyValue, 0, this.KeyValue.Length);
+ }
+
+ public static new KeyedHashAlgorithm Create()
+ {
+ return Create("System.Security.Cryptography.KeyedHashAlgorithm");
+ }
+
+ public static new KeyedHashAlgorithm Create(string algName)
+ {
+ return (KeyedHashAlgorithm)CryptoConfig.CreateFromName(algName);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+ <body>
+ <h1>NUnit Acceptance Tests</h1>
+ <p>
+ Developers love self-referential programs! Hence, NUnit has always run all it's
+ own tests, even those that are not really unit tests.
+ <p>Now, beginning with NUnit 2.4, NUnit has top-level tests using Ward Cunningham's
+ FIT framework. At this time, the tests are pretty rudimentary, but it's a start
+ and it's a framework for doing more.
+ <h2>Running the Tests</h2>
+ <p>Open a console or shell window and navigate to the NUnit bin directory, which
+ contains this file. To run the test under Microsoft .Net, enter the command
+ <pre> runFile NUnitFitTests.html TestResults.html .</pre>
+ To run it under Mono, enter
+ <pre> mono runFile.exe NUnitFitTests.html TestResults.html .</pre>
+ Note the space and dot at the end of each command. The results of your test
+ will be in TestResults.html in the same directory.
+ <h2>Platform and CLR Version</h2>
+ <table BORDER cellSpacing="0" cellPadding="5">
+ <tr>
+ <td colspan="2">NUnit.Fixtures.PlatformInfo</td>
+ </tr>
+ </table>
+ <h2>Verify Unit Tests</h2>
+ <p>
+ Load and run the NUnit unit tests, verifying that the results are as expected.
+ When these tests are run on different platforms, different numbers of tests may
+ be skipped, so the values for Skipped and Run tests are informational only.
+ <p>
+ The number of tests in each assembly should be constant across all platforms -
+ any discrepancy usually means that one of the test source files was not
+ compiled on the platform. There should be no failures and no tests ignored.
+ <p><b>Note:</b>
+ At the moment, the nunit.extensions.tests assembly is failing because the
+ fixture doesn't initialize addins in the test domain.
+ <p>
+ <table BORDER cellSpacing="0" cellPadding="5">
+ <tr>
+ <td colspan="6">NUnit.Fixtures.AssemblyRunner</td>
+ </tr>
+ <tr>
+ <td>Assembly</td>
+ <td>Tests()</td>
+ <td>Run()</td>
+ <td>Skipped()</td>
+ <td>Ignored()</td>
+ <td>Failures()</td>
+ </tr>
+ <tr>
+ <td>nunit.framework.tests.dll</td>
+ <td>397</td>
+ <td> </td>
+ <td> </td>
+ <td>0</td>
+ <td>0</td>
+ </tr>
+ <tr>
+ <td>nunit.core.tests.dll</td>
+ <td>355</td>
+ <td> </td>
+ <td> </td>
+ <td>0</td>
+ <td>0</td>
+ </tr>
+ <tr>
+ <td>nunit.util.tests.dll</td>
+ <td>238</td>
+ <td> </td>
+ <td> </td>
+ <td>0</td>
+ <td>0</td>
+ </tr>
+ <tr>
+ <td>nunit.mocks.tests.dll</td>
+ <td>43</td>
+ <td> </td>
+ <td> </td>
+ <td>0</td>
+ <td>0</td>
+ </tr>
+ <tr>
+ <td>nunit.extensions.tests.dll</td>
+ <td>5</td>
+ <td> </td>
+ <td> </td>
+ <td>0</td>
+ <td>0</td>
+ </tr>
+ <tr>
+ <td>nunit-console.tests.dll</td>
+ <td>40</td>
+ <td> </td>
+ <td> </td>
+ <td>0</td>
+ <td>0</td>
+ </tr>
+ <tr>
+ <td>nunit.uikit.tests.dll</td>
+ <td>34</td>
+ <td> </td>
+ <td> </td>
+ <td>0</td>
+ <td>0</td>
+ </tr>
+ <tr>
+ <td>nunit-gui.tests.dll</td>
+ <td>15</td>
+ <td> </td>
+ <td> </td>
+ <td>0</td>
+ <td>0</td>
+ </tr>
+ <tr>
+ <td>nunit.fixtures.tests.dll</td>
+ <td>6</td>
+ <td> </td>
+ <td> </td>
+ <td>0</td>
+ <td>0</td>
+ </tr>
+ </table>
+ <h2>Code Snippet Tests</h2>
+ <p>
+ These tests create a test assembly from a snippet of code and then load and run
+ the tests that it contains, verifying that the structure of the loaded tests is
+ as expected and that the number of tests run, skipped, ignored or failed is
+ correct.
+ <p>
+ <table BORDER cellSpacing="0" cellPadding="5">
+ <tr>
+ <td colspan="6">NUnit.Fixtures.SnippetRunner</td>
+ </tr>
+ <tr>
+ <td>Code</td>
+ <td>Tree()</td>
+ <td>Run()</td>
+ <td>Skipped()</td>
+ <td>Ignored()</td>
+ <td>Failures()</td>
+ </tr>
+ <tr>
+ <td><pre>public class TestClass
+{
+}</pre>
+ </td>
+ <td>EMPTY</td>
+ <td>0</td>
+ <td>0</td>
+ <td>0</td>
+ <td>0</td>
+ </tr>
+ <tr>
+ <td><pre>using NUnit.Framework;
+
+[TestFixture]
+public class TestClass
+{
+}</pre>
+ </td>
+ <td>TestClass</td>
+ <td>0</td>
+ <td>0</td>
+ <td>0</td>
+ <td>0</td>
+ </tr>
+ <tr>
+ <td><pre>using NUnit.Framework;
+
+[TestFixture]
+public class TestClass
+{
+ [Test]
+ public void T1() { }
+ [Test]
+ public void T2() { }
+ [Test]
+ public void T3() { }
+}</pre>
+ </td>
+ <td><pre>TestClass
+>T1
+>T2
+>T3</pre>
+ </td>
+ <td>3</td>
+ <td>0</td>
+ <td>0</td>
+ <td>0</td>
+ </tr>
+ <tr>
+ <td><pre>using NUnit.Framework;
+
+[TestFixture]
+public class TestClass1
+{
+ [Test]
+ public void T1() { }
+}
+
+[TestFixture]
+public class TestClass2
+{
+ [Test]
+ public void T2() { }
+ [Test]
+ public void T3() { }
+}</pre>
+ </td>
+ <td><pre>TestClass1
+>T1
+TestClass2
+>T2
+>T3</pre>
+ </td>
+ <td>3</td>
+ <td>0</td>
+ <td>0</td>
+ <td>0</td>
+ </tr>
+ <tr>
+ <td><pre>using NUnit.Framework;
+
+[TestFixture]
+public class TestClass
+{
+ [Test]
+ public void T1() { }
+ [Test, Ignore]
+ public void T2() { }
+ [Test]
+ public void T3() { }
+}</pre>
+ </td>
+ <td><pre>TestClass
+>T1
+>T2
+>T3</pre>
+ </td>
+ <td>2</td>
+ <td>0</td>
+ <td>1</td>
+ <td>0</td>
+ </tr>
+ <tr>
+ <td><pre>using NUnit.Framework;
+
+[TestFixture]
+public class TestClass
+{
+ [Test]
+ public void T1() { }
+ [Test, Explicit]
+ public void T2() { }
+ [Test]
+ public void T3() { }
+}</pre>
+ </td>
+ <td><pre>TestClass
+>T1
+>T2
+>T3</pre>
+ </td>
+ <td>2</td>
+ <td>1</td>
+ <td>0</td>
+ <td>0</td>
+ </tr>
+ </table>
+ <h2>Summary Information</h2>
+ <table BORDER cellSpacing="0" cellPadding="5">
+ <tr>
+ <td colspan="2">fit.Summary</td>
+ </tr>
+ </table>
+ </body>
+</html>
--- /dev/null
+\r
+\r
+ GNU GENERAL PUBLIC LICENSE\r
+ Version 2, June 1991\r
+\r
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.\r
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+ Everyone is permitted to copy and distribute verbatim copies\r
+ of this license document, but changing it is not allowed.\r
+\r
+ Preamble\r
+\r
+ The licenses for most software are designed to take away your\r
+freedom to share and change it. By contrast, the GNU General Public\r
+License is intended to guarantee your freedom to share and change free\r
+software--to make sure the software is free for all its users. This\r
+General Public License applies to most of the Free Software\r
+Foundation's software and to any other program whose authors commit to\r
+using it. (Some other Free Software Foundation software is covered by\r
+the GNU Library General Public License instead.) You can apply it to\r
+your programs, too.\r
+\r
+ When we speak of free software, we are referring to freedom, not\r
+price. Our General Public Licenses are designed to make sure that you\r
+have the freedom to distribute copies of free software (and charge for\r
+this service if you wish), that you receive source code or can get it\r
+if you want it, that you can change the software or use pieces of it\r
+in new free programs; and that you know you can do these things.\r
+\r
+ To protect your rights, we need to make restrictions that forbid\r
+anyone to deny you these rights or to ask you to surrender the rights.\r
+These restrictions translate to certain responsibilities for you if you\r
+distribute copies of the software, or if you modify it.\r
+\r
+ For example, if you distribute copies of such a program, whether\r
+gratis or for a fee, you must give the recipients all the rights that\r
+you have. You must make sure that they, too, receive or can get the\r
+source code. And you must show them these terms so they know their\r
+rights.\r
+\r
+ We protect your rights with two steps: (1) copyright the software, and\r
+(2) offer you this license which gives you legal permission to copy,\r
+distribute and/or modify the software.\r
+\r
+ Also, for each author's protection and ours, we want to make certain\r
+that everyone understands that there is no warranty for this free\r
+software. If the software is modified by someone else and passed on, we\r
+want its recipients to know that what they have is not the original, so\r
+that any problems introduced by others will not reflect on the original\r
+authors' reputations.\r
+\r
+ Finally, any free program is threatened constantly by software\r
+patents. We wish to avoid the danger that redistributors of a free\r
+program will individually obtain patent licenses, in effect making the\r
+program proprietary. To prevent this, we have made it clear that any\r
+patent must be licensed for everyone's free use or not licensed at all.\r
+\r
+ The precise terms and conditions for copying, distribution and\r
+modification follow.\r
+\r
+ GNU GENERAL PUBLIC LICENSE\r
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\r
+\r
+ 0. This License applies to any program or other work which contains\r
+a notice placed by the copyright holder saying it may be distributed\r
+under the terms of this General Public License. The "Program", below,\r
+refers to any such program or work, and a "work based on the Program"\r
+means either the Program or any derivative work under copyright law:\r
+that is to say, a work containing the Program or a portion of it,\r
+either verbatim or with modifications and/or translated into another\r
+language. (Hereinafter, translation is included without limitation in\r
+the term "modification".) Each licensee is addressed as "you".\r
+\r
+Activities other than copying, distribution and modification are not\r
+covered by this License; they are outside its scope. The act of\r
+running the Program is not restricted, and the output from the Program\r
+is covered only if its contents constitute a work based on the\r
+Program (independent of having been made by running the Program).\r
+Whether that is true depends on what the Program does.\r
+\r
+ 1. You may copy and distribute verbatim copies of the Program's\r
+source code as you receive it, in any medium, provided that you\r
+conspicuously and appropriately publish on each copy an appropriate\r
+copyright notice and disclaimer of warranty; keep intact all the\r
+notices that refer to this License and to the absence of any warranty;\r
+and give any other recipients of the Program a copy of this License\r
+along with the Program.\r
+\r
+You may charge a fee for the physical act of transferring a copy, and\r
+you may at your option offer warranty protection in exchange for a fee.\r
+\r
+ 2. You may modify your copy or copies of the Program or any portion\r
+of it, thus forming a work based on the Program, and copy and\r
+distribute such modifications or work under the terms of Section 1\r
+above, provided that you also meet all of these conditions:\r
+\r
+ a) You must cause the modified files to carry prominent notices\r
+ stating that you changed the files and the date of any change.\r
+\r
+ b) You must cause any work that you distribute or publish, that in\r
+ whole or in part contains or is derived from the Program or any\r
+ part thereof, to be licensed as a whole at no charge to all third\r
+ parties under the terms of this License.\r
+\r
+ c) If the modified program normally reads commands interactively\r
+ when run, you must cause it, when started running for such\r
+ interactive use in the most ordinary way, to print or display an\r
+ announcement including an appropriate copyright notice and a\r
+ notice that there is no warranty (or else, saying that you provide\r
+ a warranty) and that users may redistribute the program under\r
+ these conditions, and telling the user how to view a copy of this\r
+ License. (Exception: if the Program itself is interactive but\r
+ does not normally print such an announcement, your work based on\r
+ the Program is not required to print an announcement.)\r
+\r
+These requirements apply to the modified work as a whole. If\r
+identifiable sections of that work are not derived from the Program,\r
+and can be reasonably considered independent and separate works in\r
+themselves, then this License, and its terms, do not apply to those\r
+sections when you distribute them as separate works. But when you\r
+distribute the same sections as part of a whole which is a work based\r
+on the Program, the distribution of the whole must be on the terms of\r
+this License, whose permissions for other licensees extend to the\r
+entire whole, and thus to each and every part regardless of who wrote it.\r
+\r
+Thus, it is not the intent of this section to claim rights or contest\r
+your rights to work written entirely by you; rather, the intent is to\r
+exercise the right to control the distribution of derivative or\r
+collective works based on the Program.\r
+\r
+In addition, mere aggregation of another work not based on the Program\r
+with the Program (or with a work based on the Program) on a volume of\r
+a storage or distribution medium does not bring the other work under\r
+the scope of this License.\r
+\r
+ 3. You may copy and distribute the Program (or a work based on it,\r
+under Section 2) in object code or executable form under the terms of\r
+Sections 1 and 2 above provided that you also do one of the following:\r
+\r
+ a) Accompany it with the complete corresponding machine-readable\r
+ source code, which must be distributed under the terms of Sections\r
+ 1 and 2 above on a medium customarily used for software interchange; or,\r
+\r
+ b) Accompany it with a written offer, valid for at least three\r
+ years, to give any third party, for a charge no more than your\r
+ cost of physically performing source distribution, a complete\r
+ machine-readable copy of the corresponding source code, to be\r
+ distributed under the terms of Sections 1 and 2 above on a medium\r
+ customarily used for software interchange; or,\r
+\r
+ c) Accompany it with the information you received as to the offer\r
+ to distribute corresponding source code. (This alternative is\r
+ allowed only for noncommercial distribution and only if you\r
+ received the program in object code or executable form with such\r
+ an offer, in accord with Subsection b above.)\r
+\r
+The source code for a work means the preferred form of the work for\r
+making modifications to it. For an executable work, complete source\r
+code means all the source code for all modules it contains, plus any\r
+associated interface definition files, plus the scripts used to\r
+control compilation and installation of the executable. However, as a\r
+special exception, the source code distributed need not include\r
+anything that is normally distributed (in either source or binary\r
+form) with the major components (compiler, kernel, and so on) of the\r
+operating system on which the executable runs, unless that component\r
+itself accompanies the executable.\r
+\r
+If distribution of executable or object code is made by offering\r
+access to copy from a designated place, then offering equivalent\r
+access to copy the source code from the same place counts as\r
+distribution of the source code, even though third parties are not\r
+compelled to copy the source along with the object code.\r
+\r
+ 4. You may not copy, modify, sublicense, or distribute the Program\r
+except as expressly provided under this License. Any attempt\r
+otherwise to copy, modify, sublicense or distribute the Program is\r
+void, and will automatically terminate your rights under this License.\r
+However, parties who have received copies, or rights, from you under\r
+this License will not have their licenses terminated so long as such\r
+parties remain in full compliance.\r
+\r
+ 5. You are not required to accept this License, since you have not\r
+signed it. However, nothing else grants you permission to modify or\r
+distribute the Program or its derivative works. These actions are\r
+prohibited by law if you do not accept this License. Therefore, by\r
+modifying or distributing the Program (or any work based on the\r
+Program), you indicate your acceptance of this License to do so, and\r
+all its terms and conditions for copying, distributing or modifying\r
+the Program or works based on it.\r
+\r
+ 6. Each time you redistribute the Program (or any work based on the\r
+Program), the recipient automatically receives a license from the\r
+original licensor to copy, distribute or modify the Program subject to\r
+these terms and conditions. You may not impose any further\r
+restrictions on the recipients' exercise of the rights granted herein.\r
+You are not responsible for enforcing compliance by third parties to\r
+this License.\r
+\r
+ 7. If, as a consequence of a court judgment or allegation of patent\r
+infringement or for any other reason (not limited to patent issues),\r
+conditions are imposed on you (whether by court order, agreement or\r
+otherwise) that contradict the conditions of this License, they do not\r
+excuse you from the conditions of this License. If you cannot\r
+distribute so as to satisfy simultaneously your obligations under this\r
+License and any other pertinent obligations, then as a consequence you\r
+may not distribute the Program at all. For example, if a patent\r
+license would not permit royalty-free redistribution of the Program by\r
+all those who receive copies directly or indirectly through you, then\r
+the only way you could satisfy both it and this License would be to\r
+refrain entirely from distribution of the Program.\r
+\r
+If any portion of this section is held invalid or unenforceable under\r
+any particular circumstance, the balance of the section is intended to\r
+apply and the section as a whole is intended to apply in other\r
+circumstances.\r
+\r
+It is not the purpose of this section to induce you to infringe any\r
+patents or other property right claims or to contest validity of any\r
+such claims; this section has the sole purpose of protecting the\r
+integrity of the free software distribution system, which is\r
+implemented by public license practices. Many people have made\r
+generous contributions to the wide range of software distributed\r
+through that system in reliance on consistent application of that\r
+system; it is up to the author/donor to decide if he or she is willing\r
+to distribute software through any other system and a licensee cannot\r
+impose that choice.\r
+\r
+This section is intended to make thoroughly clear what is believed to\r
+be a consequence of the rest of this License.\r
+\r
+ 8. If the distribution and/or use of the Program is restricted in\r
+certain countries either by patents or by copyrighted interfaces, the\r
+original copyright holder who places the Program under this License\r
+may add an explicit geographical distribution limitation excluding\r
+those countries, so that distribution is permitted only in or among\r
+countries not thus excluded. In such case, this License incorporates\r
+the limitation as if written in the body of this License.\r
+\r
+ 9. The Free Software Foundation may publish revised and/or new versions\r
+of the General Public License from time to time. Such new versions will\r
+be similar in spirit to the present version, but may differ in detail to\r
+address new problems or concerns.\r
+\r
+Each version is given a distinguishing version number. If the Program\r
+specifies a version number of this License which applies to it and "any\r
+later version", you have the option of following the terms and conditions\r
+either of that version or of any later version published by the Free\r
+Software Foundation. If the Program does not specify a version number of\r
+this License, you may choose any version ever published by the Free Software\r
+Foundation.\r
+\r
+ 10. If you wish to incorporate parts of the Program into other free\r
+programs whose distribution conditions are different, write to the author\r
+to ask for permission. For software which is copyrighted by the Free\r
+Software Foundation, write to the Free Software Foundation; we sometimes\r
+make exceptions for this. Our decision will be guided by the two goals\r
+of preserving the free status of all derivatives of our free software and\r
+of promoting the sharing and reuse of software generally.\r
+\r
+ NO WARRANTY\r
+\r
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\r
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\r
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\r
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\r
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\r
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\r
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\r
+REPAIR OR CORRECTION.\r
+\r
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\r
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\r
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\r
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\r
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\r
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\r
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\r
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\r
+POSSIBILITY OF SUCH DAMAGES.\r
+\r
+ END OF TERMS AND CONDITIONS\r
+\r
+ How to Apply These Terms to Your New Programs\r
+\r
+ If you develop a new program, and you want it to be of the greatest\r
+possible use to the public, the best way to achieve this is to make it\r
+free software which everyone can redistribute and change under these terms.\r
+\r
+ To do so, attach the following notices to the program. It is safest\r
+to attach them to the start of each source file to most effectively\r
+convey the exclusion of warranty; and each file should have at least\r
+the "copyright" line and a pointer to where the full notice is found.\r
+\r
+ <one line to give the program's name and a brief idea of what it does.>\r
+ Copyright (C) <year> <name of author>\r
+\r
+ This program is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+\r
+Also add information on how to contact you by electronic and paper mail.\r
+\r
+If the program is interactive, make it output a short notice like this\r
+when it starts in an interactive mode:\r
+\r
+ Gnomovision version 69, Copyright (C) year name of author\r
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\r
+ This is free software, and you are welcome to redistribute it\r
+ under certain conditions; type `show c' for details.\r
+\r
+The hypothetical commands `show w' and `show c' should show the appropriate\r
+parts of the General Public License. Of course, the commands you use may\r
+be called something other than `show w' and `show c'; they could even be\r
+mouse-clicks or menu items--whatever suits your program.\r
+\r
+You should also get your employer (if you work as a programmer) or your\r
+school, if any, to sign a "copyright disclaimer" for the program, if\r
+necessary. Here is a sample; alter the names:\r
+\r
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program\r
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.\r
+\r
+ <signature of Ty Coon>, 1 April 1989\r
+ Ty Coon, President of Vice\r
+\r
+This General Public License does not permit incorporating your program into\r
+proprietary programs. If your program is a subroutine library, you may\r
+consider it more useful to permit linking proprietary applications with the\r
+library. If this is what you want to do, use the GNU Library General\r
+Public License instead of this License.\r
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>
+<doc>
+ <assembly>
+ <name>nunit.framework</name>
+ </assembly>
+ <members>
+ <member name="T:NUnit.Framework.CategoryAttribute">
+ <summary>
+ Attribute used to apply a category to a test
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.CategoryAttribute.categoryName">
+ <summary>
+ The name of the category
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.CategoryAttribute.#ctor(System.String)">
+ <summary>
+ Construct attribute for a given category based on
+ a name. The name may not contain the characters ',',
+ '+', '-' or '!'. However, this is not checked in the
+ constructor since it would cause an error to arise at
+ as the test was loaded without giving a clear indication
+ of where the problem is located. The error is handled
+ in NUnitFramework.cs by marking the test as not
+ runnable.
+ </summary>
+ <param name="name">The name of the category</param>
+ </member>
+ <member name="M:NUnit.Framework.CategoryAttribute.#ctor">
+ <summary>
+ Protected constructor uses the Type name as the name
+ of the category.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.CategoryAttribute.Name">
+ <summary>
+ The name of the category
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.DatapointAttribute">
+ <summary>
+ Used to mark a field for use as a datapoint when executing a theory
+ within the same fixture that requires an argument of the field's Type.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.DatapointsAttribute">
+ <summary>
+ Used to mark an array as containing a set of datapoints to be used
+ executing a theory within the same fixture that requires an argument
+ of the Type of the array elements.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.DescriptionAttribute">
+ <summary>
+ Attribute used to provide descriptive text about a
+ test case or fixture.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.DescriptionAttribute.#ctor(System.String)">
+ <summary>
+ Construct the attribute
+ </summary>
+ <param name="description">Text describing the test</param>
+ </member>
+ <member name="P:NUnit.Framework.DescriptionAttribute.Description">
+ <summary>
+ Gets the test description
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.MessageMatch">
+ <summary>
+ Enumeration indicating how the expected message parameter is to be used
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.MessageMatch.Exact">
+ Expect an exact match
+ </member>
+ <member name="F:NUnit.Framework.MessageMatch.Contains">
+ Expect a message containing the parameter string
+ </member>
+ <member name="F:NUnit.Framework.MessageMatch.Regex">
+ Match the regular expression provided as a parameter
+ </member>
+ <member name="F:NUnit.Framework.MessageMatch.StartsWith">
+ Expect a message that starts with the parameter string
+ </member>
+ <member name="T:NUnit.Framework.ExpectedExceptionAttribute">
+ <summary>
+ ExpectedExceptionAttribute
+ </summary>
+
+ </member>
+ <member name="M:NUnit.Framework.ExpectedExceptionAttribute.#ctor">
+ <summary>
+ Constructor for a non-specific exception
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.ExpectedExceptionAttribute.#ctor(System.Type)">
+ <summary>
+ Constructor for a given type of exception
+ </summary>
+ <param name="exceptionType">The type of the expected exception</param>
+ </member>
+ <member name="M:NUnit.Framework.ExpectedExceptionAttribute.#ctor(System.String)">
+ <summary>
+ Constructor for a given exception name
+ </summary>
+ <param name="exceptionName">The full name of the expected exception</param>
+ </member>
+ <member name="P:NUnit.Framework.ExpectedExceptionAttribute.ExpectedException">
+ <summary>
+ Gets or sets the expected exception type
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.ExpectedExceptionAttribute.ExpectedExceptionName">
+ <summary>
+ Gets or sets the full Type name of the expected exception
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.ExpectedExceptionAttribute.ExpectedMessage">
+ <summary>
+ Gets or sets the expected message text
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.ExpectedExceptionAttribute.UserMessage">
+ <summary>
+ Gets or sets the user message displayed in case of failure
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.ExpectedExceptionAttribute.MatchType">
+ <summary>
+ Gets or sets the type of match to be performed on the expected message
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.ExpectedExceptionAttribute.Handler">
+ <summary>
+ Gets the name of a method to be used as an exception handler
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.ExplicitAttribute">
+ <summary>
+ ExplicitAttribute marks a test or test fixture so that it will
+ only be run if explicitly executed from the gui or command line
+ or if it is included by use of a filter. The test will not be
+ run simply because an enclosing suite is run.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.ExplicitAttribute.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.ExplicitAttribute.#ctor(System.String)">
+ <summary>
+ Constructor with a reason
+ </summary>
+ <param name="reason">The reason test is marked explicit</param>
+ </member>
+ <member name="P:NUnit.Framework.ExplicitAttribute.Reason">
+ <summary>
+ The reason test is marked explicit
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.IgnoreAttribute">
+ <summary>
+ Attribute used to mark a test that is to be ignored.
+ Ignored tests result in a warning message when the
+ tests are run.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.IgnoreAttribute.#ctor">
+ <summary>
+ Constructs the attribute without giving a reason
+ for ignoring the test.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.IgnoreAttribute.#ctor(System.String)">
+ <summary>
+ Constructs the attribute giving a reason for ignoring the test
+ </summary>
+ <param name="reason">The reason for ignoring the test</param>
+ </member>
+ <member name="P:NUnit.Framework.IgnoreAttribute.Reason">
+ <summary>
+ The reason for ignoring a test
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.IncludeExcludeAttribute">
+ <summary>
+ Abstract base for Attributes that are used to include tests
+ in the test run based on environmental settings.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.IncludeExcludeAttribute.#ctor">
+ <summary>
+ Constructor with no included items specified, for use
+ with named property syntax.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.IncludeExcludeAttribute.#ctor(System.String)">
+ <summary>
+ Constructor taking one or more included items
+ </summary>
+ <param name="include">Comma-delimited list of included items</param>
+ </member>
+ <member name="P:NUnit.Framework.IncludeExcludeAttribute.Include">
+ <summary>
+ Name of the item that is needed in order for
+ a test to run. Multiple itemss may be given,
+ separated by a comma.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.IncludeExcludeAttribute.Exclude">
+ <summary>
+ Name of the item to be excluded. Multiple items
+ may be given, separated by a comma.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.IncludeExcludeAttribute.Reason">
+ <summary>
+ The reason for including or excluding the test
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.PlatformAttribute">
+ <summary>
+ PlatformAttribute is used to mark a test fixture or an
+ individual method as applying to a particular platform only.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.PlatformAttribute.#ctor">
+ <summary>
+ Constructor with no platforms specified, for use
+ with named property syntax.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.PlatformAttribute.#ctor(System.String)">
+ <summary>
+ Constructor taking one or more platforms
+ </summary>
+ <param name="platforms">Comma-deliminted list of platforms</param>
+ </member>
+ <member name="T:NUnit.Framework.CultureAttribute">
+ <summary>
+ CultureAttribute is used to mark a test fixture or an
+ individual method as applying to a particular Culture only.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.CultureAttribute.#ctor">
+ <summary>
+ Constructor with no cultures specified, for use
+ with named property syntax.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.CultureAttribute.#ctor(System.String)">
+ <summary>
+ Constructor taking one or more cultures
+ </summary>
+ <param name="cultures">Comma-deliminted list of cultures</param>
+ </member>
+ <member name="T:NUnit.Framework.CombinatorialAttribute">
+ <summary>
+ Marks a test to use a combinatorial join of any argument data
+ provided. NUnit will create a test case for every combination of
+ the arguments provided. This can result in a large number of test
+ cases and so should be used judiciously. This is the default join
+ type, so the attribute need not be used except as documentation.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.PropertyAttribute">
+ <summary>
+ PropertyAttribute is used to attach information to a test as a name/value pair..
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.PropertyAttribute.#ctor(System.String,System.String)">
+ <summary>
+ Construct a PropertyAttribute with a name and string value
+ </summary>
+ <param name="propertyName">The name of the property</param>
+ <param name="propertyValue">The property value</param>
+ </member>
+ <member name="M:NUnit.Framework.PropertyAttribute.#ctor(System.String,System.Int32)">
+ <summary>
+ Construct a PropertyAttribute with a name and int value
+ </summary>
+ <param name="propertyName">The name of the property</param>
+ <param name="propertyValue">The property value</param>
+ </member>
+ <member name="M:NUnit.Framework.PropertyAttribute.#ctor(System.String,System.Double)">
+ <summary>
+ Construct a PropertyAttribute with a name and double value
+ </summary>
+ <param name="propertyName">The name of the property</param>
+ <param name="propertyValue">The property value</param>
+ </member>
+ <member name="M:NUnit.Framework.PropertyAttribute.#ctor">
+ <summary>
+ Constructor for derived classes that set the
+ property dictionary directly.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.PropertyAttribute.#ctor(System.Object)">
+ <summary>
+ Constructor for use by derived classes that use the
+ name of the type as the property name. Derived classes
+ must ensure that the Type of the property value is
+ a standard type supported by the BCL. Any custom
+ types will cause a serialization Exception when
+ in the client.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.PropertyAttribute.Properties">
+ <summary>
+ Gets the property dictionary for this attribute
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.CombinatorialAttribute.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.PairwiseAttribute">
+ <summary>
+ Marks a test to use pairwise join of any argument data provided.
+ NUnit will attempt too excercise every pair of argument values at
+ least once, using as small a number of test cases as it can. With
+ only two arguments, this is the same as a combinatorial join.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.PairwiseAttribute.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.SequentialAttribute">
+ <summary>
+ Marks a test to use a sequential join of any argument data
+ provided. NUnit will use arguements for each parameter in
+ sequence, generating test cases up to the largest number
+ of argument values provided and using null for any arguments
+ for which it runs out of values. Normally, this should be
+ used with the same number of arguments for each parameter.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.SequentialAttribute.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.MaxTimeAttribute">
+ <summary>
+ Summary description for MaxTimeAttribute.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.MaxTimeAttribute.#ctor(System.Int32)">
+ <summary>
+ Construct a MaxTimeAttribute, given a time in milliseconds.
+ </summary>
+ <param name="milliseconds">The maximum elapsed time in milliseconds</param>
+ </member>
+ <member name="T:NUnit.Framework.RandomAttribute">
+ <summary>
+ RandomAttribute is used to supply a set of random values
+ to a single parameter of a parameterized test.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.ValuesAttribute">
+ <summary>
+ ValuesAttribute is used to provide literal arguments for
+ an individual parameter of a test.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.ParameterDataAttribute">
+ <summary>
+ Abstract base class for attributes that apply to parameters
+ and supply data for the parameter.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.ParameterDataAttribute.GetData(System.Reflection.ParameterInfo)">
+ <summary>
+ Gets the data to be provided to the specified parameter
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.ValuesAttribute.data">
+ <summary>
+ The collection of data to be returned. Must
+ be set by any derived attribute classes.
+ We use an object[] so that the individual
+ elements may have their type changed in GetData
+ if necessary.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.ValuesAttribute.#ctor(System.Object)">
+ <summary>
+ Construct with one argument
+ </summary>
+ <param name="arg1"></param>
+ </member>
+ <member name="M:NUnit.Framework.ValuesAttribute.#ctor(System.Object,System.Object)">
+ <summary>
+ Construct with two arguments
+ </summary>
+ <param name="arg1"></param>
+ <param name="arg2"></param>
+ </member>
+ <member name="M:NUnit.Framework.ValuesAttribute.#ctor(System.Object,System.Object,System.Object)">
+ <summary>
+ Construct with three arguments
+ </summary>
+ <param name="arg1"></param>
+ <param name="arg2"></param>
+ <param name="arg3"></param>
+ </member>
+ <member name="M:NUnit.Framework.ValuesAttribute.#ctor(System.Object[])">
+ <summary>
+ Construct with an array of arguments
+ </summary>
+ <param name="args"></param>
+ </member>
+ <member name="M:NUnit.Framework.ValuesAttribute.GetData(System.Reflection.ParameterInfo)">
+ <summary>
+ Get the collection of values to be used as arguments
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.RandomAttribute.#ctor(System.Int32)">
+ <summary>
+ Construct a set of doubles from 0.0 to 1.0,
+ specifying only the count.
+ </summary>
+ <param name="count"></param>
+ </member>
+ <member name="M:NUnit.Framework.RandomAttribute.#ctor(System.Double,System.Double,System.Int32)">
+ <summary>
+ Construct a set of doubles from min to max
+ </summary>
+ <param name="min"></param>
+ <param name="max"></param>
+ <param name="count"></param>
+ </member>
+ <member name="M:NUnit.Framework.RandomAttribute.#ctor(System.Int32,System.Int32,System.Int32)">
+ <summary>
+ Construct a set of ints from min to max
+ </summary>
+ <param name="min"></param>
+ <param name="max"></param>
+ <param name="count"></param>
+ </member>
+ <member name="M:NUnit.Framework.RandomAttribute.GetData(System.Reflection.ParameterInfo)">
+ <summary>
+ Get the collection of values to be used as arguments
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.RangeAttribute">
+ <summary>
+ RangeAttribute is used to supply a range of values to an
+ individual parameter of a parameterized test.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.RangeAttribute.#ctor(System.Int32,System.Int32)">
+ <summary>
+ Construct a range of ints using default step of 1
+ </summary>
+ <param name="from"></param>
+ <param name="to"></param>
+ </member>
+ <member name="M:NUnit.Framework.RangeAttribute.#ctor(System.Int32,System.Int32,System.Int32)">
+ <summary>
+ Construct a range of ints specifying the step size
+ </summary>
+ <param name="from"></param>
+ <param name="to"></param>
+ <param name="step"></param>
+ </member>
+ <member name="M:NUnit.Framework.RangeAttribute.#ctor(System.Int64,System.Int64,System.Int64)">
+ <summary>
+ Construct a range of longs
+ </summary>
+ <param name="from"></param>
+ <param name="to"></param>
+ <param name="step"></param>
+ </member>
+ <member name="M:NUnit.Framework.RangeAttribute.#ctor(System.Double,System.Double,System.Double)">
+ <summary>
+ Construct a range of doubles
+ </summary>
+ <param name="from"></param>
+ <param name="to"></param>
+ <param name="step"></param>
+ </member>
+ <member name="M:NUnit.Framework.RangeAttribute.#ctor(System.Single,System.Single,System.Single)">
+ <summary>
+ Construct a range of floats
+ </summary>
+ <param name="from"></param>
+ <param name="to"></param>
+ <param name="step"></param>
+ </member>
+ <member name="T:NUnit.Framework.RepeatAttribute">
+ <summary>
+ RepeatAttribute may be applied to test case in order
+ to run it multiple times.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.RepeatAttribute.#ctor(System.Int32)">
+ <summary>
+ Construct a RepeatAttribute
+ </summary>
+ <param name="count">The number of times to run the test</param>
+ </member>
+ <member name="T:NUnit.Framework.RequiredAddinAttribute">
+ <summary>
+ RequiredAddinAttribute may be used to indicate the names of any addins
+ that must be present in order to run some or all of the tests in an
+ assembly. If the addin is not loaded, the entire assembly is marked
+ as NotRunnable.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.RequiredAddinAttribute.#ctor(System.String)">
+ <summary>
+ Initializes a new instance of the <see cref="T:RequiredAddinAttribute"/> class.
+ </summary>
+ <param name="requiredAddin">The required addin.</param>
+ </member>
+ <member name="P:NUnit.Framework.RequiredAddinAttribute.RequiredAddin">
+ <summary>
+ Gets the name of required addin.
+ </summary>
+ <value>The required addin name.</value>
+ </member>
+ <member name="T:NUnit.Framework.SetCultureAttribute">
+ <summary>
+ Summary description for SetCultureAttribute.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.SetCultureAttribute.#ctor(System.String)">
+ <summary>
+ Construct given the name of a culture
+ </summary>
+ <param name="culture"></param>
+ </member>
+ <member name="T:NUnit.Framework.SetUICultureAttribute">
+ <summary>
+ Summary description for SetUICultureAttribute.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.SetUICultureAttribute.#ctor(System.String)">
+ <summary>
+ Construct given the name of a culture
+ </summary>
+ <param name="culture"></param>
+ </member>
+ <member name="T:NUnit.Framework.SetUpAttribute">
+ <summary>
+ Attribute used to mark a class that contains one-time SetUp
+ and/or TearDown methods that apply to all the tests in a
+ namespace or an assembly.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.SetUpFixtureAttribute">
+ <summary>
+ SetUpFixtureAttribute is used to identify a SetUpFixture
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.SuiteAttribute">
+ <summary>
+ Attribute used to mark a static (shared in VB) property
+ that returns a list of tests.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.TearDownAttribute">
+ <summary>
+ Attribute used to identify a method that is called
+ immediately after each test is run. The method is
+ guaranteed to be called, even if an exception is thrown.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.TestAttribute">
+ <summary>
+ Adding this attribute to a method within a <seealso cref="T:NUnit.Framework.TestFixtureAttribute"/>
+ class makes the method callable from the NUnit test runner. There is a property
+ called Description which is optional which you can provide a more detailed test
+ description. This class cannot be inherited.
+ </summary>
+
+ <example>
+ [TestFixture]
+ public class Fixture
+ {
+ [Test]
+ public void MethodToTest()
+ {}
+
+ [Test(Description = "more detailed description")]
+ publc void TestDescriptionMethod()
+ {}
+ }
+ </example>
+
+ </member>
+ <member name="P:NUnit.Framework.TestAttribute.Description">
+ <summary>
+ Descriptive text for this test
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.TestCaseAttribute">
+ <summary>
+ TestCaseAttribute is used to mark parameterized test cases
+ and provide them with their arguments.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.ITestCaseData">
+ <summary>
+ The ITestCaseData interface is implemented by a class
+ that is able to return complete testcases for use by
+ a parameterized test method.
+
+ NOTE: This interface is used in both the framework
+ and the core, even though that results in two different
+ types. However, sharing the source code guarantees that
+ the various implementations will be compatible and that
+ the core is able to reflect successfully over the
+ framework implementations of ITestCaseData.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.ITestCaseData.Arguments">
+ <summary>
+ Gets the argument list to be provided to the test
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.ITestCaseData.Result">
+ <summary>
+ Gets the expected result
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.ITestCaseData.ExpectedException">
+ <summary>
+ Gets the expected exception Type
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.ITestCaseData.ExpectedExceptionName">
+ <summary>
+ Gets the FullName of the expected exception
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.ITestCaseData.TestName">
+ <summary>
+ Gets the name to be used for the test
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.ITestCaseData.Description">
+ <summary>
+ Gets the description of the test
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.ITestCaseData.Ignored">
+ <summary>
+ Gets a value indicating whether this <see cref="T:NUnit.Framework.ITestCaseData"/> is ignored.
+ </summary>
+ <value><c>true</c> if ignored; otherwise, <c>false</c>.</value>
+ </member>
+ <member name="P:NUnit.Framework.ITestCaseData.IgnoreReason">
+ <summary>
+ Gets the ignore reason.
+ </summary>
+ <value>The ignore reason.</value>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseAttribute.#ctor(System.Object[])">
+ <summary>
+ Construct a TestCaseAttribute with a list of arguments.
+ This constructor is not CLS-Compliant
+ </summary>
+ <param name="arguments"></param>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseAttribute.#ctor(System.Object)">
+ <summary>
+ Construct a TestCaseAttribute with a single argument
+ </summary>
+ <param name="arg"></param>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseAttribute.#ctor(System.Object,System.Object)">
+ <summary>
+ Construct a TestCaseAttribute with a two arguments
+ </summary>
+ <param name="arg1"></param>
+ <param name="arg2"></param>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseAttribute.#ctor(System.Object,System.Object,System.Object)">
+ <summary>
+ Construct a TestCaseAttribute with a three arguments
+ </summary>
+ <param name="arg1"></param>
+ <param name="arg2"></param>
+ <param name="arg3"></param>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseAttribute.Arguments">
+ <summary>
+ Gets the list of arguments to a test case
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseAttribute.Result">
+ <summary>
+ Gets or sets the expected result.
+ </summary>
+ <value>The result.</value>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseAttribute.Categories">
+ <summary>
+ Gets a list of categories associated with this test;
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseAttribute.Category">
+ <summary>
+ Gets or sets the category associated with this test.
+ May be a single category or a comma-separated list.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseAttribute.ExpectedException">
+ <summary>
+ Gets or sets the expected exception.
+ </summary>
+ <value>The expected exception.</value>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseAttribute.ExpectedExceptionName">
+ <summary>
+ Gets or sets the name the expected exception.
+ </summary>
+ <value>The expected name of the exception.</value>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseAttribute.ExpectedMessage">
+ <summary>
+ Gets or sets the expected message of the expected exception
+ </summary>
+ <value>The expected message of the exception.</value>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseAttribute.MatchType">
+ <summary>
+ Gets or sets the type of match to be performed on the expected message
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseAttribute.Description">
+ <summary>
+ Gets or sets the description.
+ </summary>
+ <value>The description.</value>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseAttribute.TestName">
+ <summary>
+ Gets or sets the name of the test.
+ </summary>
+ <value>The name of the test.</value>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseAttribute.Ignore">
+ <summary>
+ Gets or sets the ignored status of the test
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseAttribute.Ignored">
+ <summary>
+ Gets or sets the ignored status of the test
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseAttribute.IgnoreReason">
+ <summary>
+ Gets the ignore reason.
+ </summary>
+ <value>The ignore reason.</value>
+ </member>
+ <member name="T:NUnit.Framework.TestCaseSourceAttribute">
+ <summary>
+ FactoryAttribute indicates the source to be used to
+ provide test cases for a test method.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseSourceAttribute.#ctor(System.String)">
+ <summary>
+ Construct with the name of the factory - for use with languages
+ that don't support params arrays.
+ </summary>
+ <param name="sourceName">An array of the names of the factories that will provide data</param>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseSourceAttribute.#ctor(System.Type,System.String)">
+ <summary>
+ Construct with a Type and name - for use with languages
+ that don't support params arrays.
+ </summary>
+ <param name="sourceType">The Type that will provide data</param>
+ <param name="sourceName">The name of the method, property or field that will provide data</param>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseSourceAttribute.SourceName">
+ <summary>
+ The name of a the method, property or fiend to be used as a source
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseSourceAttribute.SourceType">
+ <summary>
+ A Type to be used as a source
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.TestFixtureAttribute">
+ <example>
+ [TestFixture]
+ public class ExampleClass
+ {}
+ </example>
+ </member>
+ <member name="M:NUnit.Framework.TestFixtureAttribute.#ctor">
+ <summary>
+ Default constructor
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.TestFixtureAttribute.#ctor(System.Object[])">
+ <summary>
+ Construct with a object[] representing a set of arguments.
+ In .NET 2.0, the arguments may later be separated into
+ type arguments and constructor arguments.
+ </summary>
+ <param name="arguments"></param>
+ </member>
+ <member name="P:NUnit.Framework.TestFixtureAttribute.Description">
+ <summary>
+ Descriptive text for this fixture
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestFixtureAttribute.Category">
+ <summary>
+ Gets and sets the category for this fixture.
+ May be a comma-separated list of categories.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestFixtureAttribute.Categories">
+ <summary>
+ Gets a list of categories for this fixture
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestFixtureAttribute.Arguments">
+ <summary>
+ The arguments originally provided to the attribute
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestFixtureAttribute.Ignore">
+ <summary>
+ Gets or sets a value indicating whether this <see cref="T:NUnit.Framework.TestFixtureAttribute"/> should be ignored.
+ </summary>
+ <value><c>true</c> if ignore; otherwise, <c>false</c>.</value>
+ </member>
+ <member name="P:NUnit.Framework.TestFixtureAttribute.IgnoreReason">
+ <summary>
+ Gets or sets the ignore reason. May set Ignored as a side effect.
+ </summary>
+ <value>The ignore reason.</value>
+ </member>
+ <member name="P:NUnit.Framework.TestFixtureAttribute.TypeArgs">
+ <summary>
+ Get or set the type arguments. If not set
+ explicitly, any leading arguments that are
+ Types are taken as type arguments.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.TestFixtureSetUpAttribute">
+ <summary>
+ Attribute used to identify a method that is
+ called before any tests in a fixture are run.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.TestFixtureTearDownAttribute">
+ <summary>
+ Attribute used to identify a method that is called after
+ all the tests in a fixture have run. The method is
+ guaranteed to be called, even if an exception is thrown.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.TheoryAttribute">
+ <summary>
+ Adding this attribute to a method within a <seealso cref="T:NUnit.Framework.TestFixtureAttribute"/>
+ class makes the method callable from the NUnit test runner. There is a property
+ called Description which is optional which you can provide a more detailed test
+ description. This class cannot be inherited.
+ </summary>
+
+ <example>
+ [TestFixture]
+ public class Fixture
+ {
+ [Test]
+ public void MethodToTest()
+ {}
+
+ [Test(Description = "more detailed description")]
+ publc void TestDescriptionMethod()
+ {}
+ }
+ </example>
+
+ </member>
+ <member name="T:NUnit.Framework.TimeoutAttribute">
+ <summary>
+ WUsed on a method, marks the test with a timeout value in milliseconds.
+ The test will be run in a separate thread and is cancelled if the timeout
+ is exceeded. Used on a method or assembly, sets the default timeout
+ for all contained test methods.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.TimeoutAttribute.#ctor(System.Int32)">
+ <summary>
+ Construct a TimeoutAttribute given a time in milliseconds
+ </summary>
+ <param name="timeout">The timeout value in milliseconds</param>
+ </member>
+ <member name="T:NUnit.Framework.RequiresSTAAttribute">
+ <summary>
+ Marks a test that must run in the STA, causing it
+ to run in a separate thread if necessary.
+
+ On methods, you may also use STAThreadAttribute
+ to serve the same purpose.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.RequiresSTAAttribute.#ctor">
+ <summary>
+ Construct a RequiresSTAAttribute
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.RequiresMTAAttribute">
+ <summary>
+ Marks a test that must run in the MTA, causing it
+ to run in a separate thread if necessary.
+
+ On methods, you may also use MTAThreadAttribute
+ to serve the same purpose.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.RequiresMTAAttribute.#ctor">
+ <summary>
+ Construct a RequiresMTAAttribute
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.RequiresThreadAttribute">
+ <summary>
+ Marks a test that must run on a separate thread.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.RequiresThreadAttribute.#ctor">
+ <summary>
+ Construct a RequiresThreadAttribute
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.RequiresThreadAttribute.#ctor(System.Threading.ApartmentState)">
+ <summary>
+ Construct a RequiresThreadAttribute, specifying the apartment
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.ValueSourceAttribute">
+ <summary>
+ ValueSourceAttribute indicates the source to be used to
+ provide data for one parameter of a test method.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.ValueSourceAttribute.#ctor(System.String)">
+ <summary>
+ Construct with the name of the factory - for use with languages
+ that don't support params arrays.
+ </summary>
+ <param name="sourceName">The name of the data source to be used</param>
+ </member>
+ <member name="M:NUnit.Framework.ValueSourceAttribute.#ctor(System.Type,System.String)">
+ <summary>
+ Construct with a Type and name - for use with languages
+ that don't support params arrays.
+ </summary>
+ <param name="sourceType">The Type that will provide data</param>
+ <param name="sourceName">The name of the method, property or field that will provide data</param>
+ </member>
+ <member name="P:NUnit.Framework.ValueSourceAttribute.SourceName">
+ <summary>
+ The name of a the method, property or fiend to be used as a source
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.ValueSourceAttribute.SourceType">
+ <summary>
+ A Type to be used as a source
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.AttributeExistsConstraint">
+ <summary>
+ AttributeExistsConstraint tests for the presence of a
+ specified attribute on a Type.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.Constraint">
+ <summary>
+ The Constraint class is the base of all built-in constraints
+ within NUnit. It provides the operator overloads used to combine
+ constraints.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.IResolveConstraint">
+ <summary>
+ The IConstraintExpression interface is implemented by all
+ complete and resolvable constraints and expressions.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.IResolveConstraint.Resolve">
+ <summary>
+ Return the top-level constraint for this expression
+ </summary>
+ <returns></returns>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.Constraint.UNSET">
+ <summary>
+ Static UnsetObject used to detect derived constraints
+ failing to set the actual value.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.Constraint.actual">
+ <summary>
+ The actual value being tested against a constraint
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.Constraint.displayName">
+ <summary>
+ The display name of this Constraint for use by ToString()
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.Constraint.argcnt">
+ <summary>
+ Argument fields used by ToString();
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.Constraint.builder">
+ <summary>
+ The builder holding this constraint
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Constraint.#ctor">
+ <summary>
+ Construct a constraint with no arguments
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Constraint.#ctor(System.Object)">
+ <summary>
+ Construct a constraint with one argument
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Constraint.#ctor(System.Object,System.Object)">
+ <summary>
+ Construct a constraint with two arguments
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Constraint.SetBuilder(NUnit.Framework.Constraints.ConstraintBuilder)">
+ <summary>
+ Sets the ConstraintBuilder holding this constraint
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Constraint.WriteMessageTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the failure message to the MessageWriter provided
+ as an argument. The default implementation simply passes
+ the constraint and the actual value to the writer, which
+ then displays the constraint description and the value.
+
+ Constraints that need to provide additional details,
+ such as where the error occured can override this.
+ </summary>
+ <param name="writer">The MessageWriter on which to display the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Constraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Constraint.Matches(NUnit.Framework.Constraints.ActualValueDelegate)">
+ <summary>
+ Test whether the constraint is satisfied by an
+ ActualValueDelegate that returns the value to be tested.
+ The default implementation simply evaluates the delegate
+ but derived classes may override it to provide for delayed
+ processing.
+ </summary>
+ <param name="del">An ActualValueDelegate</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Constraint.Matches``1(``0@)">
+ <summary>
+ Test whether the constraint is satisfied by a given reference.
+ The default implementation simply dereferences the value but
+ derived classes may override it to provide for delayed processing.
+ </summary>
+ <param name="actual">A reference to the value to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Constraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Constraint.WriteActualValueTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the actual value for a failing constraint test to a
+ MessageWriter. The default implementation simply writes
+ the raw value of actual, leaving it to the writer to
+ perform any formatting.
+ </summary>
+ <param name="writer">The writer on which the actual value is displayed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Constraint.ToString">
+ <summary>
+ Default override of ToString returns the constraint DisplayName
+ followed by any arguments within angle brackets.
+ </summary>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Constraint.GetStringRepresentation">
+ <summary>
+ Returns the string representation of this constraint
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Constraint.op_BitwiseAnd(NUnit.Framework.Constraints.Constraint,NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ This operator creates a constraint that is satisfied only if both
+ argument constraints are satisfied.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Constraint.op_BitwiseOr(NUnit.Framework.Constraints.Constraint,NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ This operator creates a constraint that is satisfied if either
+ of the argument constraints is satisfied.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Constraint.op_LogicalNot(NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ This operator creates a constraint that is satisfied if the
+ argument constraint is not satisfied.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Constraint.After(System.Int32)">
+ <summary>
+ Returns a DelayedConstraint with the specified delay time.
+ </summary>
+ <param name="delayInMilliseconds">The delay in milliseconds.</param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Constraint.After(System.Int32,System.Int32)">
+ <summary>
+ Returns a DelayedConstraint with the specified delay time
+ and polling interval.
+ </summary>
+ <param name="delayInMilliseconds">The delay in milliseconds.</param>
+ <param name="pollingInterval">The interval at which to test the constraint.</param>
+ <returns></returns>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.Constraint.DisplayName">
+ <summary>
+ The display name of this Constraint for use by ToString().
+ The default value is the name of the constraint with
+ trailing "Constraint" removed. Derived classes may set
+ this to another name in their constructors.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.Constraint.And">
+ <summary>
+ Returns a ConstraintExpression by appending And
+ to the current constraint.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.Constraint.With">
+ <summary>
+ Returns a ConstraintExpression by appending And
+ to the current constraint.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.Constraint.Or">
+ <summary>
+ Returns a ConstraintExpression by appending Or
+ to the current constraint.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.Constraint.UnsetObject">
+ <summary>
+ Class used to detect any derived constraints
+ that fail to set the actual value in their
+ Matches override.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AttributeExistsConstraint.#ctor(System.Type)">
+ <summary>
+ Constructs an AttributeExistsConstraint for a specific attribute Type
+ </summary>
+ <param name="type"></param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AttributeExistsConstraint.Matches(System.Object)">
+ <summary>
+ Tests whether the object provides the expected attribute.
+ </summary>
+ <param name="actual">A Type, MethodInfo, or other ICustomAttributeProvider</param>
+ <returns>True if the expected attribute is present, otherwise false</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AttributeExistsConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Writes the description of the constraint to the specified writer
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.AttributeConstraint">
+ <summary>
+ AttributeConstraint tests that a specified attribute is present
+ on a Type or other provider and that the value of the attribute
+ satisfies some other constraint.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.PrefixConstraint">
+ <summary>
+ Abstract base class used for prefixes
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.PrefixConstraint.baseConstraint">
+ <summary>
+ The base constraint
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PrefixConstraint.#ctor(NUnit.Framework.Constraints.IResolveConstraint)">
+ <summary>
+ Construct given a base constraint
+ </summary>
+ <param name="resolvable"></param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AttributeConstraint.#ctor(System.Type,NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Constructs an AttributeConstraint for a specified attriute
+ Type and base constraint.
+ </summary>
+ <param name="type"></param>
+ <param name="baseConstraint"></param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AttributeConstraint.Matches(System.Object)">
+ <summary>
+ Determines whether the Type or other provider has the
+ expected attribute and if its value matches the
+ additional constraint specified.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AttributeConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Writes a description of the attribute to the specified writer.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AttributeConstraint.WriteActualValueTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Writes the actual value supplied to the specified writer.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AttributeConstraint.GetStringRepresentation">
+ <summary>
+ Returns a string representation of the constraint.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.BasicConstraint">
+ <summary>
+ BasicConstraint is the abstract base for constraints that
+ perform a simple comparison to a constant value.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.BasicConstraint.#ctor(System.Object,System.String)">
+ <summary>
+ Initializes a new instance of the <see cref="T:BasicConstraint"/> class.
+ </summary>
+ <param name="expected">The expected.</param>
+ <param name="description">The description.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.BasicConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.BasicConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.NullConstraint">
+ <summary>
+ NullConstraint tests that the actual value is null
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.NullConstraint.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:NullConstraint"/> class.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.TrueConstraint">
+ <summary>
+ TrueConstraint tests that the actual value is true
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.TrueConstraint.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:TrueConstraint"/> class.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.FalseConstraint">
+ <summary>
+ FalseConstraint tests that the actual value is false
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.FalseConstraint.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:FalseConstraint"/> class.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.NaNConstraint">
+ <summary>
+ NaNConstraint tests that the actual value is a double or float NaN
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.NaNConstraint.Matches(System.Object)">
+ <summary>
+ Test that the actual value is an NaN
+ </summary>
+ <param name="actual"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.NaNConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a specified writer
+ </summary>
+ <param name="writer"></param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.BinaryConstraint">
+ <summary>
+ BinaryConstraint is the abstract base of all constraints
+ that combine two other constraints in some fashion.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.BinaryConstraint.left">
+ <summary>
+ The first constraint being combined
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.BinaryConstraint.right">
+ <summary>
+ The second constraint being combined
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.BinaryConstraint.#ctor(NUnit.Framework.Constraints.Constraint,NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Construct a BinaryConstraint from two other constraints
+ </summary>
+ <param name="left">The first constraint</param>
+ <param name="right">The second constraint</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.AndConstraint">
+ <summary>
+ AndConstraint succeeds only if both members succeed.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AndConstraint.#ctor(NUnit.Framework.Constraints.Constraint,NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Create an AndConstraint from two other constraints
+ </summary>
+ <param name="left">The first constraint</param>
+ <param name="right">The second constraint</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AndConstraint.Matches(System.Object)">
+ <summary>
+ Apply both member constraints to an actual value, succeeding
+ succeeding only if both of them succeed.
+ </summary>
+ <param name="actual">The actual value</param>
+ <returns>True if the constraints both succeeded</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AndConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write a description for this contraint to a MessageWriter
+ </summary>
+ <param name="writer">The MessageWriter to receive the description</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AndConstraint.WriteActualValueTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the actual value for a failing constraint test to a
+ MessageWriter. The default implementation simply writes
+ the raw value of actual, leaving it to the writer to
+ perform any formatting.
+ </summary>
+ <param name="writer">The writer on which the actual value is displayed</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.OrConstraint">
+ <summary>
+ OrConstraint succeeds if either member succeeds
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.OrConstraint.#ctor(NUnit.Framework.Constraints.Constraint,NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Create an OrConstraint from two other constraints
+ </summary>
+ <param name="left">The first constraint</param>
+ <param name="right">The second constraint</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.OrConstraint.Matches(System.Object)">
+ <summary>
+ Apply the member constraints to an actual value, succeeding
+ succeeding as soon as one of them succeeds.
+ </summary>
+ <param name="actual">The actual value</param>
+ <returns>True if either constraint succeeded</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.OrConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write a description for this contraint to a MessageWriter
+ </summary>
+ <param name="writer">The MessageWriter to receive the description</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.CollectionConstraint">
+ <summary>
+ CollectionConstraint is the abstract base class for
+ constraints that operate on collections.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionConstraint.#ctor">
+ <summary>
+ Construct an empty CollectionConstraint
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionConstraint.#ctor(System.Object)">
+ <summary>
+ Construct a CollectionConstraint
+ </summary>
+ <param name="arg"></param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionConstraint.IsEmpty(System.Collections.IEnumerable)">
+ <summary>
+ Determines whether the specified enumerable is empty.
+ </summary>
+ <param name="enumerable">The enumerable.</param>
+ <returns>
+ <c>true</c> if the specified enumerable is empty; otherwise, <c>false</c>.
+ </returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionConstraint.doMatch(System.Collections.IEnumerable)">
+ <summary>
+ Protected method to be implemented by derived classes
+ </summary>
+ <param name="collection"></param>
+ <returns></returns>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.CollectionItemsEqualConstraint">
+ <summary>
+ CollectionItemsEqualConstraint is the abstract base class for all
+ collection constraints that apply some notion of item equality
+ as a part of their operation.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionItemsEqualConstraint.#ctor">
+ <summary>
+ Construct an empty CollectionConstraint
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionItemsEqualConstraint.#ctor(System.Object)">
+ <summary>
+ Construct a CollectionConstraint
+ </summary>
+ <param name="arg"></param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionItemsEqualConstraint.Using(System.Collections.IComparer)">
+ <summary>
+ Flag the constraint to use the supplied IComparer object.
+ </summary>
+ <param name="comparer">The IComparer object to use.</param>
+ <returns>Self.</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionItemsEqualConstraint.Using``1(System.Collections.Generic.IComparer{``0})">
+ <summary>
+ Flag the constraint to use the supplied IComparer object.
+ </summary>
+ <param name="comparer">The IComparer object to use.</param>
+ <returns>Self.</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionItemsEqualConstraint.Using``1(System.Comparison{``0})">
+ <summary>
+ Flag the constraint to use the supplied Comparison object.
+ </summary>
+ <param name="comparer">The IComparer object to use.</param>
+ <returns>Self.</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionItemsEqualConstraint.Using(System.Collections.IEqualityComparer)">
+ <summary>
+ Flag the constraint to use the supplied IEqualityComparer object.
+ </summary>
+ <param name="comparer">The IComparer object to use.</param>
+ <returns>Self.</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionItemsEqualConstraint.Using``1(System.Collections.Generic.IEqualityComparer{``0})">
+ <summary>
+ Flag the constraint to use the supplied IEqualityComparer object.
+ </summary>
+ <param name="comparer">The IComparer object to use.</param>
+ <returns>Self.</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionItemsEqualConstraint.ItemsEqual(System.Object,System.Object)">
+ <summary>
+ Compares two collection members for equality
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionItemsEqualConstraint.Tally(System.Collections.IEnumerable)">
+ <summary>
+ Return a new CollectionTally for use in making tests
+ </summary>
+ <param name="c">The collection to be included in the tally</param>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.CollectionItemsEqualConstraint.IgnoreCase">
+ <summary>
+ Flag the constraint to ignore case and return self.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.EmptyCollectionConstraint">
+ <summary>
+ EmptyCollectionConstraint tests whether a collection is empty.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EmptyCollectionConstraint.doMatch(System.Collections.IEnumerable)">
+ <summary>
+ Check that the collection is empty
+ </summary>
+ <param name="collection"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EmptyCollectionConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer"></param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.UniqueItemsConstraint">
+ <summary>
+ UniqueItemsConstraint tests whether all the items in a
+ collection are unique.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.UniqueItemsConstraint.doMatch(System.Collections.IEnumerable)">
+ <summary>
+ Check that all items are unique.
+ </summary>
+ <param name="actual"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.UniqueItemsConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write a description of this constraint to a MessageWriter
+ </summary>
+ <param name="writer"></param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.CollectionContainsConstraint">
+ <summary>
+ CollectionContainsConstraint is used to test whether a collection
+ contains an expected object as a member.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionContainsConstraint.#ctor(System.Object)">
+ <summary>
+ Construct a CollectionContainsConstraint
+ </summary>
+ <param name="expected"></param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionContainsConstraint.doMatch(System.Collections.IEnumerable)">
+ <summary>
+ Test whether the expected item is contained in the collection
+ </summary>
+ <param name="actual"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionContainsConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write a descripton of the constraint to a MessageWriter
+ </summary>
+ <param name="writer"></param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.CollectionEquivalentConstraint">
+ <summary>
+ CollectionEquivalentCOnstraint is used to determine whether two
+ collections are equivalent.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionEquivalentConstraint.#ctor(System.Collections.IEnumerable)">
+ <summary>
+ Construct a CollectionEquivalentConstraint
+ </summary>
+ <param name="expected"></param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionEquivalentConstraint.doMatch(System.Collections.IEnumerable)">
+ <summary>
+ Test whether two collections are equivalent
+ </summary>
+ <param name="actual"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionEquivalentConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write a description of this constraint to a MessageWriter
+ </summary>
+ <param name="writer"></param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.CollectionSubsetConstraint">
+ <summary>
+ CollectionSubsetConstraint is used to determine whether
+ one collection is a subset of another
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionSubsetConstraint.#ctor(System.Collections.IEnumerable)">
+ <summary>
+ Construct a CollectionSubsetConstraint
+ </summary>
+ <param name="expected">The collection that the actual value is expected to be a subset of</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionSubsetConstraint.doMatch(System.Collections.IEnumerable)">
+ <summary>
+ Test whether the actual collection is a subset of
+ the expected collection provided.
+ </summary>
+ <param name="actual"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionSubsetConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write a description of this constraint to a MessageWriter
+ </summary>
+ <param name="writer"></param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.CollectionOrderedConstraint">
+ <summary>
+ CollectionOrderedConstraint is used to test whether a collection is ordered.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionOrderedConstraint.#ctor">
+ <summary>
+ Construct a CollectionOrderedConstraint
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionOrderedConstraint.Using(System.Collections.IComparer)">
+ <summary>
+ Modifies the constraint to use an IComparer and returns self.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionOrderedConstraint.Using``1(System.Collections.Generic.IComparer{``0})">
+ <summary>
+ Modifies the constraint to use an IComparer<T> and returns self.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionOrderedConstraint.Using``1(System.Comparison{``0})">
+ <summary>
+ Modifies the constraint to use a Comparison<T> and returns self.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionOrderedConstraint.By(System.String)">
+ <summary>
+ Modifies the constraint to test ordering by the value of
+ a specified property and returns self.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionOrderedConstraint.doMatch(System.Collections.IEnumerable)">
+ <summary>
+ Test whether the collection is ordered
+ </summary>
+ <param name="actual"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionOrderedConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write a description of the constraint to a MessageWriter
+ </summary>
+ <param name="writer"></param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionOrderedConstraint.GetStringRepresentation">
+ <summary>
+ Returns the string representation of the constraint.
+ </summary>
+ <returns></returns>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.CollectionOrderedConstraint.Descending">
+ <summary>
+ If used performs a reverse comparison
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.CollectionTally">
+ <summary>
+ CollectionTally counts (tallies) the number of
+ occurences of each object in one or more enumerations.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionTally.#ctor(NUnit.Framework.Constraints.NUnitEqualityComparer,System.Collections.IEnumerable)">
+ <summary>
+ Construct a CollectionTally object from a comparer and a collection
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionTally.TryRemove(System.Object)">
+ <summary>
+ Try to remove an object from the tally
+ </summary>
+ <param name="o">The object to remove</param>
+ <returns>True if successful, false if the object was not found</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionTally.TryRemove(System.Collections.IEnumerable)">
+ <summary>
+ Try to remove a set of objects from the tally
+ </summary>
+ <param name="c">The objects to remove</param>
+ <returns>True if successful, false if any object was not found</returns>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.CollectionTally.Count">
+ <summary>
+ The number of objects remaining in the tally
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.ComparisonAdapter">
+ <summary>
+ ComparisonAdapter class centralizes all comparisons of
+ values in NUnit, adapting to the use of any provided
+ IComparer, IComparer<T> or Comparison<T>
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ComparisonAdapter.For(System.Collections.IComparer)">
+ <summary>
+ Returns a ComparisonAdapter that wraps an IComparer
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ComparisonAdapter.For``1(System.Collections.Generic.IComparer{``0})">
+ <summary>
+ Returns a ComparisonAdapter that wraps an IComparer<T>
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ComparisonAdapter.For``1(System.Comparison{``0})">
+ <summary>
+ Returns a ComparisonAdapter that wraps a Comparison<T>
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ComparisonAdapter.Compare(System.Object,System.Object)">
+ <summary>
+ Compares two objects
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ComparisonAdapter.Default">
+ <summary>
+ Gets the default ComparisonAdapter, which wraps an
+ NUnitComparer object.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ComparisonAdapter.ComparerAdapter.#ctor(System.Collections.IComparer)">
+ <summary>
+ Construct a ComparisonAdapter for an IComparer
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ComparisonAdapter.ComparerAdapter.Compare(System.Object,System.Object)">
+ <summary>
+ Compares two objects
+ </summary>
+ <param name="expected"></param>
+ <param name="actual"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ComparisonAdapter.DefaultComparisonAdapter.#ctor">
+ <summary>
+ Construct a default ComparisonAdapter
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.ComparisonAdapter.ComparerAdapter`1">
+ <summary>
+ ComparisonAdapter<T> extends ComparisonAdapter and
+ allows use of an IComparer<T> or Comparison<T>
+ to actually perform the comparison.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ComparisonAdapter.ComparerAdapter`1.#ctor(System.Collections.Generic.IComparer{`0})">
+ <summary>
+ Construct a ComparisonAdapter for an IComparer<T>
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ComparisonAdapter.ComparerAdapter`1.Compare(System.Object,System.Object)">
+ <summary>
+ Compare a Type T to an object
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ComparisonAdapter.ComparisonAdapterForComparison`1.#ctor(System.Comparison{`0})">
+ <summary>
+ Construct a ComparisonAdapter for a Comparison<T>
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ComparisonAdapter.ComparisonAdapterForComparison`1.Compare(System.Object,System.Object)">
+ <summary>
+ Compare a Type T to an object
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.ComparisonConstraint">
+ <summary>
+ Abstract base class for constraints that compare values to
+ determine if one is greater than, equal to or less than
+ the other.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.ComparisonConstraint.expected">
+ <summary>
+ The value against which a comparison is to be made
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.ComparisonConstraint.ltOK">
+ <summary>
+ If true, less than returns success
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.ComparisonConstraint.eqOK">
+ <summary>
+ if true, equal returns success
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.ComparisonConstraint.gtOK">
+ <summary>
+ if true, greater than returns success
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.ComparisonConstraint.predicate">
+ <summary>
+ The predicate used as a part of the description
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.ComparisonConstraint.comparer">
+ <summary>
+ ComparisonAdapter to be used in making the comparison
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ComparisonConstraint.#ctor(System.Object,System.Boolean,System.Boolean,System.Boolean,System.String)">
+ <summary>
+ Initializes a new instance of the <see cref="T:ComparisonConstraint"/> class.
+ </summary>
+ <param name="value">The value against which to make a comparison.</param>
+ <param name="ltOK">if set to <c>true</c> less succeeds.</param>
+ <param name="eqOK">if set to <c>true</c> equal succeeds.</param>
+ <param name="gtOK">if set to <c>true</c> greater succeeds.</param>
+ <param name="predicate">String used in describing the constraint.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ComparisonConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ComparisonConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ComparisonConstraint.Using(System.Collections.IComparer)">
+ <summary>
+ Modifies the constraint to use an IComparer and returns self
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ComparisonConstraint.Using``1(System.Collections.Generic.IComparer{``0})">
+ <summary>
+ Modifies the constraint to use an IComparer<T> and returns self
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ComparisonConstraint.Using``1(System.Comparison{``0})">
+ <summary>
+ Modifies the constraint to use a Comparison<T> and returns self
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.GreaterThanConstraint">
+ <summary>
+ Tests whether a value is greater than the value supplied to its constructor
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.GreaterThanConstraint.#ctor(System.Object)">
+ <summary>
+ Initializes a new instance of the <see cref="T:GreaterThanConstraint"/> class.
+ </summary>
+ <param name="expected">The expected value.</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.GreaterThanOrEqualConstraint">
+ <summary>
+ Tests whether a value is greater than or equal to the value supplied to its constructor
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.GreaterThanOrEqualConstraint.#ctor(System.Object)">
+ <summary>
+ Initializes a new instance of the <see cref="T:GreaterThanOrEqualConstraint"/> class.
+ </summary>
+ <param name="expected">The expected value.</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.LessThanConstraint">
+ <summary>
+ Tests whether a value is less than the value supplied to its constructor
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.LessThanConstraint.#ctor(System.Object)">
+ <summary>
+ Initializes a new instance of the <see cref="T:LessThanConstraint"/> class.
+ </summary>
+ <param name="expected">The expected value.</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.LessThanOrEqualConstraint">
+ <summary>
+ Tests whether a value is less than or equal to the value supplied to its constructor
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.LessThanOrEqualConstraint.#ctor(System.Object)">
+ <summary>
+ Initializes a new instance of the <see cref="T:LessThanOrEqualConstraint"/> class.
+ </summary>
+ <param name="expected">The expected value.</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.ActualValueDelegate">
+ <summary>
+ Delegate used to delay evaluation of the actual value
+ to be used in evaluating a constraint
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.ConstraintBuilder">
+ <summary>
+ ConstraintBuilder maintains the stacks that are used in
+ processing a ConstraintExpression. An OperatorStack
+ is used to hold operators that are waiting for their
+ operands to be reognized. a ConstraintStack holds
+ input constraints as well as the results of each
+ operator applied.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintBuilder.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:ConstraintBuilder"/> class.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintBuilder.Append(NUnit.Framework.Constraints.ConstraintOperator)">
+ <summary>
+ Appends the specified operator to the expression by first
+ reducing the operator stack and then pushing the new
+ operator on the stack.
+ </summary>
+ <param name="op">The operator to push.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintBuilder.Append(NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Appends the specified constraint to the expresson by pushing
+ it on the constraint stack.
+ </summary>
+ <param name="constraint">The constraint to push.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintBuilder.SetTopOperatorRightContext(System.Object)">
+ <summary>
+ Sets the top operator right context.
+ </summary>
+ <param name="rightContext">The right context.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintBuilder.ReduceOperatorStack(System.Int32)">
+ <summary>
+ Reduces the operator stack until the topmost item
+ precedence is greater than or equal to the target precedence.
+ </summary>
+ <param name="targetPrecedence">The target precedence.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintBuilder.Resolve">
+ <summary>
+ Resolves this instance, returning a Constraint. If the builder
+ is not currently in a resolvable state, an exception is thrown.
+ </summary>
+ <returns>The resolved constraint</returns>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintBuilder.IsResolvable">
+ <summary>
+ Gets a value indicating whether this instance is resolvable.
+ </summary>
+ <value>
+ <c>true</c> if this instance is resolvable; otherwise, <c>false</c>.
+ </value>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.ConstraintBuilder.OperatorStack">
+ <summary>
+ OperatorStack is a type-safe stack for holding ConstraintOperators
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintBuilder.OperatorStack.#ctor(NUnit.Framework.Constraints.ConstraintBuilder)">
+ <summary>
+ Initializes a new instance of the <see cref="T:OperatorStack"/> class.
+ </summary>
+ <param name="builder">The builder.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintBuilder.OperatorStack.Push(NUnit.Framework.Constraints.ConstraintOperator)">
+ <summary>
+ Pushes the specified operator onto the stack.
+ </summary>
+ <param name="op">The op.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintBuilder.OperatorStack.Pop">
+ <summary>
+ Pops the topmost operator from the stack.
+ </summary>
+ <returns></returns>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintBuilder.OperatorStack.Empty">
+ <summary>
+ Gets a value indicating whether this <see cref="T:OpStack"/> is empty.
+ </summary>
+ <value><c>true</c> if empty; otherwise, <c>false</c>.</value>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintBuilder.OperatorStack.Top">
+ <summary>
+ Gets the topmost operator without modifying the stack.
+ </summary>
+ <value>The top.</value>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.ConstraintBuilder.ConstraintStack">
+ <summary>
+ ConstraintStack is a type-safe stack for holding Constraints
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintBuilder.ConstraintStack.#ctor(NUnit.Framework.Constraints.ConstraintBuilder)">
+ <summary>
+ Initializes a new instance of the <see cref="T:ConstraintStack"/> class.
+ </summary>
+ <param name="builder">The builder.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintBuilder.ConstraintStack.Push(NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Pushes the specified constraint. As a side effect,
+ the constraint's builder field is set to the
+ ConstraintBuilder owning this stack.
+ </summary>
+ <param name="constraint">The constraint.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintBuilder.ConstraintStack.Pop">
+ <summary>
+ Pops this topmost constrait from the stack.
+ As a side effect, the constraint's builder
+ field is set to null.
+ </summary>
+ <returns></returns>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintBuilder.ConstraintStack.Empty">
+ <summary>
+ Gets a value indicating whether this <see cref="T:ConstraintStack"/> is empty.
+ </summary>
+ <value><c>true</c> if empty; otherwise, <c>false</c>.</value>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintBuilder.ConstraintStack.Top">
+ <summary>
+ Gets the topmost constraint without modifying the stack.
+ </summary>
+ <value>The topmost constraint</value>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.ConstraintExpression">
+ <summary>
+ ConstraintExpression represents a compound constraint in the
+ process of being constructed from a series of syntactic elements.
+
+ Individual elements are appended to the expression as they are
+ reognized. Once an actual Constraint is appended, the expression
+ returns a resolvable Constraint.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.ConstraintExpressionBase">
+ <summary>
+ ConstraintExpressionBase is the abstract base class for the
+ generated ConstraintExpression class, which represents a
+ compound constraint in the process of being constructed
+ from a series of syntactic elements.
+
+ NOTE: ConstraintExpressionBase is aware of some of its
+ derived classes, which is an apparent violation of
+ encapsulation. Ideally, these classes would be a
+ single class, but they must be separated in order to
+ allow parts to be generated under .NET 1.x and to
+ provide proper user feedback in syntactically
+ aware IDEs.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.ConstraintExpressionBase.builder">
+ <summary>
+ The ConstraintBuilder holding the elements recognized so far
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpressionBase.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:ConstraintExpressionBase"/> class.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpressionBase.#ctor(NUnit.Framework.Constraints.ConstraintBuilder)">
+ <summary>
+ Initializes a new instance of the <see cref="T:ConstraintExpressionBase"/>
+ class passing in a ConstraintBuilder, which may be pre-populated.
+ </summary>
+ <param name="builder">The builder.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpressionBase.ToString">
+ <summary>
+ Returns a string representation of the expression as it
+ currently stands. This should only be used for testing,
+ since it has the side-effect of resolving the expression.
+ </summary>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpressionBase.Append(NUnit.Framework.Constraints.ConstraintOperator)">
+ <summary>
+ Appends an operator to the expression and returns the
+ resulting expression itself.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpressionBase.Append(NUnit.Framework.Constraints.SelfResolvingOperator)">
+ <summary>
+ Appends a self-resolving operator to the expression and
+ returns a new ResolvableConstraintExpression.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpressionBase.Append(NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Appends a constraint to the expression and returns that
+ constraint, which is associated with the current state
+ of the expression being built.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.#ctor">
+ <summary>
+ Initializes a new instance of the <see cref="T:ConstraintExpression"/> class.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.#ctor(NUnit.Framework.Constraints.ConstraintBuilder)">
+ <summary>
+ Initializes a new instance of the <see cref="T:ConstraintExpression"/>
+ class passing in a ConstraintBuilder, which may be pre-populated.
+ </summary>
+ <param name="builder">The builder.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.Property(System.String)">
+ <summary>
+ Returns a new PropertyConstraintExpression, which will either
+ test for the existence of the named property on the object
+ being tested or apply any following constraint to that property.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.Attribute(System.Type)">
+ <summary>
+ Returns a new AttributeConstraint checking for the
+ presence of a particular attribute on an object.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.Attribute``1">
+ <summary>
+ Returns a new AttributeConstraint checking for the
+ presence of a particular attribute on an object.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.Matches(NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Returns the constraint provided as an argument - used to allow custom
+ custom constraints to easily participate in the syntax.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.Matches``1(System.Predicate{``0})">
+ <summary>
+ Returns the constraint provided as an argument - used to allow custom
+ custom constraints to easily participate in the syntax.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.EqualTo(System.Object)">
+ <summary>
+ Returns a constraint that tests two items for equality
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.SameAs(System.Object)">
+ <summary>
+ Returns a constraint that tests that two references are the same object
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.GreaterThan(System.Object)">
+ <summary>
+ Returns a constraint that tests whether the
+ actual value is greater than the suppled argument
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.GreaterThanOrEqualTo(System.Object)">
+ <summary>
+ Returns a constraint that tests whether the
+ actual value is greater than or equal to the suppled argument
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.AtLeast(System.Object)">
+ <summary>
+ Returns a constraint that tests whether the
+ actual value is greater than or equal to the suppled argument
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.LessThan(System.Object)">
+ <summary>
+ Returns a constraint that tests whether the
+ actual value is less than the suppled argument
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.LessThanOrEqualTo(System.Object)">
+ <summary>
+ Returns a constraint that tests whether the
+ actual value is less than or equal to the suppled argument
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.AtMost(System.Object)">
+ <summary>
+ Returns a constraint that tests whether the
+ actual value is less than or equal to the suppled argument
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.TypeOf(System.Type)">
+ <summary>
+ Returns a constraint that tests whether the actual
+ value is of the exact type supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.TypeOf``1">
+ <summary>
+ Returns a constraint that tests whether the actual
+ value is of the exact type supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.InstanceOf(System.Type)">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is of the type supplied as an argument or a derived type.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.InstanceOf``1">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is of the type supplied as an argument or a derived type.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.InstanceOfType(System.Type)">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is of the type supplied as an argument or a derived type.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.InstanceOfType``1">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is of the type supplied as an argument or a derived type.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.AssignableFrom(System.Type)">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is assignable from the type supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.AssignableFrom``1">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is assignable from the type supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.AssignableTo(System.Type)">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is assignable from the type supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.AssignableTo``1">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is assignable from the type supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.EquivalentTo(System.Collections.IEnumerable)">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is a collection containing the same elements as the
+ collection supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.SubsetOf(System.Collections.IEnumerable)">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is a subset of the collection supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.Member(System.Object)">
+ <summary>
+ Returns a new CollectionContainsConstraint checking for the
+ presence of a particular object in the collection.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.Contains(System.Object)">
+ <summary>
+ Returns a new CollectionContainsConstraint checking for the
+ presence of a particular object in the collection.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.Contains(System.String)">
+ <summary>
+ Returns a new ContainsConstraint. This constraint
+ will, in turn, make use of the appropriate second-level
+ constraint, depending on the type of the actual argument.
+ This overload is only used if the item sought is a string,
+ since any other type implies that we are looking for a
+ collection member.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.StringContaining(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value contains the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.ContainsSubstring(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value contains the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.StartsWith(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value starts with the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.StringStarting(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value starts with the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.EndsWith(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value ends with the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.StringEnding(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value ends with the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.Matches(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value matches the Regex pattern supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.StringMatching(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value matches the Regex pattern supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.SamePath(System.String)">
+ <summary>
+ Returns a constraint that tests whether the path provided
+ is the same as an expected path after canonicalization.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.SubPath(System.String)">
+ <summary>
+ Returns a constraint that tests whether the path provided
+ is the same path or under an expected path after canonicalization.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.SamePathOrUnder(System.String)">
+ <summary>
+ Returns a constraint that tests whether the path provided
+ is the same path or under an expected path after canonicalization.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintExpression.InRange(System.IComparable,System.IComparable)">
+ <summary>
+ Returns a constraint that tests whether the actual value falls
+ within a specified range.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintExpression.Not">
+ <summary>
+ Returns a ConstraintExpression that negates any
+ following constraint.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintExpression.No">
+ <summary>
+ Returns a ConstraintExpression that negates any
+ following constraint.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintExpression.All">
+ <summary>
+ Returns a ConstraintExpression, which will apply
+ the following constraint to all members of a collection,
+ succeeding if all of them succeed.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintExpression.Some">
+ <summary>
+ Returns a ConstraintExpression, which will apply
+ the following constraint to all members of a collection,
+ succeeding if at least one of them succeeds.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintExpression.None">
+ <summary>
+ Returns a ConstraintExpression, which will apply
+ the following constraint to all members of a collection,
+ succeeding if all of them fail.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintExpression.Length">
+ <summary>
+ Returns a new ConstraintExpression, which will apply the following
+ constraint to the Length property of the object being tested.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintExpression.Count">
+ <summary>
+ Returns a new ConstraintExpression, which will apply the following
+ constraint to the Count property of the object being tested.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintExpression.Message">
+ <summary>
+ Returns a new ConstraintExpression, which will apply the following
+ constraint to the Message property of the object being tested.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintExpression.InnerException">
+ <summary>
+ Returns a new ConstraintExpression, which will apply the following
+ constraint to the InnerException property of the object being tested.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintExpression.With">
+ <summary>
+ With is currently a NOP - reserved for future use.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintExpression.Null">
+ <summary>
+ Returns a constraint that tests for null
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintExpression.True">
+ <summary>
+ Returns a constraint that tests for True
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintExpression.False">
+ <summary>
+ Returns a constraint that tests for False
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintExpression.NaN">
+ <summary>
+ Returns a constraint that tests for NaN
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintExpression.Empty">
+ <summary>
+ Returns a constraint that tests for empty
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintExpression.Unique">
+ <summary>
+ Returns a constraint that tests whether a collection
+ contains all unique items.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintExpression.BinarySerializable">
+ <summary>
+ Returns a constraint that tests whether an object graph is serializable in binary format.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintExpression.XmlSerializable">
+ <summary>
+ Returns a constraint that tests whether an object graph is serializable in xml format.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintExpression.Ordered">
+ <summary>
+ Returns a constraint that tests whether a collection is ordered
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.ConstraintFactory">
+ <summary>
+ Helper class with properties and methods that supply
+ a number of constraints used in Asserts.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.Property(System.String)">
+ <summary>
+ Returns a new PropertyConstraintExpression, which will either
+ test for the existence of the named property on the object
+ being tested or apply any following constraint to that property.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.Attribute(System.Type)">
+ <summary>
+ Returns a new AttributeConstraint checking for the
+ presence of a particular attribute on an object.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.Attribute``1">
+ <summary>
+ Returns a new AttributeConstraint checking for the
+ presence of a particular attribute on an object.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.EqualTo(System.Object)">
+ <summary>
+ Returns a constraint that tests two items for equality
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.SameAs(System.Object)">
+ <summary>
+ Returns a constraint that tests that two references are the same object
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.GreaterThan(System.Object)">
+ <summary>
+ Returns a constraint that tests whether the
+ actual value is greater than the suppled argument
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.GreaterThanOrEqualTo(System.Object)">
+ <summary>
+ Returns a constraint that tests whether the
+ actual value is greater than or equal to the suppled argument
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.AtLeast(System.Object)">
+ <summary>
+ Returns a constraint that tests whether the
+ actual value is greater than or equal to the suppled argument
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.LessThan(System.Object)">
+ <summary>
+ Returns a constraint that tests whether the
+ actual value is less than the suppled argument
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.LessThanOrEqualTo(System.Object)">
+ <summary>
+ Returns a constraint that tests whether the
+ actual value is less than or equal to the suppled argument
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.AtMost(System.Object)">
+ <summary>
+ Returns a constraint that tests whether the
+ actual value is less than or equal to the suppled argument
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.TypeOf(System.Type)">
+ <summary>
+ Returns a constraint that tests whether the actual
+ value is of the exact type supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.TypeOf``1">
+ <summary>
+ Returns a constraint that tests whether the actual
+ value is of the exact type supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.InstanceOf(System.Type)">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is of the type supplied as an argument or a derived type.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.InstanceOf``1">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is of the type supplied as an argument or a derived type.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.InstanceOfType(System.Type)">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is of the type supplied as an argument or a derived type.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.InstanceOfType``1">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is of the type supplied as an argument or a derived type.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.AssignableFrom(System.Type)">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is assignable from the type supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.AssignableFrom``1">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is assignable from the type supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.AssignableTo(System.Type)">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is assignable from the type supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.AssignableTo``1">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is assignable from the type supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.EquivalentTo(System.Collections.IEnumerable)">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is a collection containing the same elements as the
+ collection supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.SubsetOf(System.Collections.IEnumerable)">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is a subset of the collection supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.Member(System.Object)">
+ <summary>
+ Returns a new CollectionContainsConstraint checking for the
+ presence of a particular object in the collection.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.Contains(System.Object)">
+ <summary>
+ Returns a new CollectionContainsConstraint checking for the
+ presence of a particular object in the collection.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.Contains(System.String)">
+ <summary>
+ Returns a new ContainsConstraint. This constraint
+ will, in turn, make use of the appropriate second-level
+ constraint, depending on the type of the actual argument.
+ This overload is only used if the item sought is a string,
+ since any other type implies that we are looking for a
+ collection member.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.StringContaining(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value contains the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.ContainsSubstring(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value contains the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.DoesNotContain(System.String)">
+ <summary>
+ Returns a constraint that fails if the actual
+ value contains the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.StartsWith(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value starts with the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.StringStarting(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value starts with the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.DoesNotStartWith(System.String)">
+ <summary>
+ Returns a constraint that fails if the actual
+ value starts with the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.EndsWith(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value ends with the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.StringEnding(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value ends with the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.DoesNotEndWith(System.String)">
+ <summary>
+ Returns a constraint that fails if the actual
+ value ends with the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.Matches(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value matches the Regex pattern supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.StringMatching(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value matches the Regex pattern supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.DoesNotMatch(System.String)">
+ <summary>
+ Returns a constraint that fails if the actual
+ value matches the pattern supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.SamePath(System.String)">
+ <summary>
+ Returns a constraint that tests whether the path provided
+ is the same as an expected path after canonicalization.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.SubPath(System.String)">
+ <summary>
+ Returns a constraint that tests whether the path provided
+ is the same path or under an expected path after canonicalization.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.SamePathOrUnder(System.String)">
+ <summary>
+ Returns a constraint that tests whether the path provided
+ is the same path or under an expected path after canonicalization.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintFactory.InRange(System.IComparable,System.IComparable)">
+ <summary>
+ Returns a constraint that tests whether the actual value falls
+ within a specified range.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintFactory.Not">
+ <summary>
+ Returns a ConstraintExpression that negates any
+ following constraint.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintFactory.No">
+ <summary>
+ Returns a ConstraintExpression that negates any
+ following constraint.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintFactory.All">
+ <summary>
+ Returns a ConstraintExpression, which will apply
+ the following constraint to all members of a collection,
+ succeeding if all of them succeed.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintFactory.Some">
+ <summary>
+ Returns a ConstraintExpression, which will apply
+ the following constraint to all members of a collection,
+ succeeding if at least one of them succeeds.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintFactory.None">
+ <summary>
+ Returns a ConstraintExpression, which will apply
+ the following constraint to all members of a collection,
+ succeeding if all of them fail.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintFactory.Length">
+ <summary>
+ Returns a new ConstraintExpression, which will apply the following
+ constraint to the Length property of the object being tested.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintFactory.Count">
+ <summary>
+ Returns a new ConstraintExpression, which will apply the following
+ constraint to the Count property of the object being tested.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintFactory.Message">
+ <summary>
+ Returns a new ConstraintExpression, which will apply the following
+ constraint to the Message property of the object being tested.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintFactory.InnerException">
+ <summary>
+ Returns a new ConstraintExpression, which will apply the following
+ constraint to the InnerException property of the object being tested.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintFactory.Null">
+ <summary>
+ Returns a constraint that tests for null
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintFactory.True">
+ <summary>
+ Returns a constraint that tests for True
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintFactory.False">
+ <summary>
+ Returns a constraint that tests for False
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintFactory.NaN">
+ <summary>
+ Returns a constraint that tests for NaN
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintFactory.Empty">
+ <summary>
+ Returns a constraint that tests for empty
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintFactory.Unique">
+ <summary>
+ Returns a constraint that tests whether a collection
+ contains all unique items.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintFactory.BinarySerializable">
+ <summary>
+ Returns a constraint that tests whether an object graph is serializable in binary format.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintFactory.XmlSerializable">
+ <summary>
+ Returns a constraint that tests whether an object graph is serializable in xml format.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintFactory.Ordered">
+ <summary>
+ Returns a constraint that tests whether a collection is ordered
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.ConstraintOperator">
+ <summary>
+ The ConstraintOperator class is used internally by a
+ ConstraintBuilder to represent an operator that
+ modifies or combines constraints.
+
+ Constraint operators use left and right precedence
+ values to determine whether the top operator on the
+ stack should be reduced before pushing a new operator.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.ConstraintOperator.left_precedence">
+ <summary>
+ The precedence value used when the operator
+ is about to be pushed to the stack.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.ConstraintOperator.right_precedence">
+ <summary>
+ The precedence value used when the operator
+ is on the top of the stack.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ConstraintOperator.Reduce(NUnit.Framework.Constraints.ConstraintBuilder.ConstraintStack)">
+ <summary>
+ Reduce produces a constraint from the operator and
+ any arguments. It takes the arguments from the constraint
+ stack and pushes the resulting constraint on it.
+ </summary>
+ <param name="stack"></param>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintOperator.LeftContext">
+ <summary>
+ The syntax element preceding this operator
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintOperator.RightContext">
+ <summary>
+ The syntax element folowing this operator
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintOperator.LeftPrecedence">
+ <summary>
+ The precedence value used when the operator
+ is about to be pushed to the stack.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ConstraintOperator.RightPrecedence">
+ <summary>
+ The precedence value used when the operator
+ is on the top of the stack.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.PrefixOperator">
+ <summary>
+ PrefixOperator takes a single constraint and modifies
+ it's action in some way.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PrefixOperator.Reduce(NUnit.Framework.Constraints.ConstraintBuilder.ConstraintStack)">
+ <summary>
+ Reduce produces a constraint from the operator and
+ any arguments. It takes the arguments from the constraint
+ stack and pushes the resulting constraint on it.
+ </summary>
+ <param name="stack"></param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PrefixOperator.ApplyPrefix(NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Returns the constraint created by applying this
+ prefix to another constraint.
+ </summary>
+ <param name="constraint"></param>
+ <returns></returns>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.NotOperator">
+ <summary>
+ Negates the test of the constraint it wraps.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.NotOperator.#ctor">
+ <summary>
+ Constructs a new NotOperator
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.NotOperator.ApplyPrefix(NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Returns a NotConstraint applied to its argument.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.CollectionOperator">
+ <summary>
+ Abstract base for operators that indicate how to
+ apply a constraint to items in a collection.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.CollectionOperator.#ctor">
+ <summary>
+ Constructs a CollectionOperator
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.AllOperator">
+ <summary>
+ Represents a constraint that succeeds if all the
+ members of a collection match a base constraint.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AllOperator.ApplyPrefix(NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Returns a constraint that will apply the argument
+ to the members of a collection, succeeding if
+ they all succeed.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.SomeOperator">
+ <summary>
+ Represents a constraint that succeeds if any of the
+ members of a collection match a base constraint.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.SomeOperator.ApplyPrefix(NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Returns a constraint that will apply the argument
+ to the members of a collection, succeeding if
+ any of them succeed.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.NoneOperator">
+ <summary>
+ Represents a constraint that succeeds if none of the
+ members of a collection match a base constraint.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.NoneOperator.ApplyPrefix(NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Returns a constraint that will apply the argument
+ to the members of a collection, succeeding if
+ none of them succeed.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.WithOperator">
+ <summary>
+ Represents a constraint that simply wraps the
+ constraint provided as an argument, without any
+ further functionality, but which modifes the
+ order of evaluation because of its precedence.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.WithOperator.#ctor">
+ <summary>
+ Constructor for the WithOperator
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.WithOperator.ApplyPrefix(NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Returns a constraint that wraps its argument
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.SelfResolvingOperator">
+ <summary>
+ Abstract base class for operators that are able to reduce to a
+ constraint whether or not another syntactic element follows.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.PropOperator">
+ <summary>
+ Operator used to test for the presence of a named Property
+ on an object and optionally apply further tests to the
+ value of that property.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PropOperator.#ctor(System.String)">
+ <summary>
+ Constructs a PropOperator for a particular named property
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PropOperator.Reduce(NUnit.Framework.Constraints.ConstraintBuilder.ConstraintStack)">
+ <summary>
+ Reduce produces a constraint from the operator and
+ any arguments. It takes the arguments from the constraint
+ stack and pushes the resulting constraint on it.
+ </summary>
+ <param name="stack"></param>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.PropOperator.Name">
+ <summary>
+ Gets the name of the property to which the operator applies
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.AttributeOperator">
+ <summary>
+ Operator that tests for the presence of a particular attribute
+ on a type and optionally applies further tests to the attribute.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AttributeOperator.#ctor(System.Type)">
+ <summary>
+ Construct an AttributeOperator for a particular Type
+ </summary>
+ <param name="type">The Type of attribute tested</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AttributeOperator.Reduce(NUnit.Framework.Constraints.ConstraintBuilder.ConstraintStack)">
+ <summary>
+ Reduce produces a constraint from the operator and
+ any arguments. It takes the arguments from the constraint
+ stack and pushes the resulting constraint on it.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.ThrowsOperator">
+ <summary>
+ Operator that tests that an exception is thrown and
+ optionally applies further tests to the exception.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ThrowsOperator.#ctor">
+ <summary>
+ Construct a ThrowsOperator
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ThrowsOperator.Reduce(NUnit.Framework.Constraints.ConstraintBuilder.ConstraintStack)">
+ <summary>
+ Reduce produces a constraint from the operator and
+ any arguments. It takes the arguments from the constraint
+ stack and pushes the resulting constraint on it.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.BinaryOperator">
+ <summary>
+ Abstract base class for all binary operators
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.BinaryOperator.Reduce(NUnit.Framework.Constraints.ConstraintBuilder.ConstraintStack)">
+ <summary>
+ Reduce produces a constraint from the operator and
+ any arguments. It takes the arguments from the constraint
+ stack and pushes the resulting constraint on it.
+ </summary>
+ <param name="stack"></param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.BinaryOperator.ApplyOperator(NUnit.Framework.Constraints.Constraint,NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Abstract method that produces a constraint by applying
+ the operator to its left and right constraint arguments.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.BinaryOperator.LeftPrecedence">
+ <summary>
+ Gets the left precedence of the operator
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.BinaryOperator.RightPrecedence">
+ <summary>
+ Gets the right precedence of the operator
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.AndOperator">
+ <summary>
+ Operator that requires both it's arguments to succeed
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AndOperator.#ctor">
+ <summary>
+ Construct an AndOperator
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AndOperator.ApplyOperator(NUnit.Framework.Constraints.Constraint,NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Apply the operator to produce an AndConstraint
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.OrOperator">
+ <summary>
+ Operator that requires at least one of it's arguments to succeed
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.OrOperator.#ctor">
+ <summary>
+ Construct an OrOperator
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.OrOperator.ApplyOperator(NUnit.Framework.Constraints.Constraint,NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Apply the operator to produce an OrConstraint
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.ContainsConstraint">
+ <summary>
+ ContainsConstraint tests a whether a string contains a substring
+ or a collection contains an object. It postpones the decision of
+ which test to use until the type of the actual argument is known.
+ This allows testing whether a string is contained in a collection
+ or as a substring of another string using the same syntax.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ContainsConstraint.#ctor(System.Object)">
+ <summary>
+ Initializes a new instance of the <see cref="T:ContainsConstraint"/> class.
+ </summary>
+ <param name="expected">The expected.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ContainsConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ContainsConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ContainsConstraint.Using(System.Collections.IComparer)">
+ <summary>
+ Flag the constraint to use the supplied IComparer object.
+ </summary>
+ <param name="comparer">The IComparer object to use.</param>
+ <returns>Self.</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ContainsConstraint.Using``1(System.Collections.Generic.IComparer{``0})">
+ <summary>
+ Flag the constraint to use the supplied IComparer object.
+ </summary>
+ <param name="comparer">The IComparer object to use.</param>
+ <returns>Self.</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ContainsConstraint.Using``1(System.Comparison{``0})">
+ <summary>
+ Flag the constraint to use the supplied Comparison object.
+ </summary>
+ <param name="comparer">The IComparer object to use.</param>
+ <returns>Self.</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ContainsConstraint.Using(System.Collections.IEqualityComparer)">
+ <summary>
+ Flag the constraint to use the supplied IEqualityComparer object.
+ </summary>
+ <param name="comparer">The IComparer object to use.</param>
+ <returns>Self.</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ContainsConstraint.Using``1(System.Collections.Generic.IEqualityComparer{``0})">
+ <summary>
+ Flag the constraint to use the supplied IEqualityComparer object.
+ </summary>
+ <param name="comparer">The IComparer object to use.</param>
+ <returns>Self.</returns>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ContainsConstraint.IgnoreCase">
+ <summary>
+ Flag the constraint to ignore case and return self.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.DelayedConstraint">
+ <summary>
+ Applies a delay to the match so that a match can be evaluated in the future.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.DelayedConstraint.#ctor(NUnit.Framework.Constraints.Constraint,System.Int32)">
+ <summary>
+ Creates a new DelayedConstraint
+ </summary>
+ <param name="baseConstraint">The inner constraint two decorate</param>
+ <param name="delayInMilliseconds">The time interval after which the match is performed</param>
+ <exception cref="T:System.InvalidOperationException">If the value of <paramref name="delayInMilliseconds"/> is less than 0</exception>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.DelayedConstraint.#ctor(NUnit.Framework.Constraints.Constraint,System.Int32,System.Int32)">
+ <summary>
+ Creates a new DelayedConstraint
+ </summary>
+ <param name="baseConstraint">The inner constraint two decorate</param>
+ <param name="delayInMilliseconds">The time interval after which the match is performed</param>
+ <param name="pollingInterval">The time interval used for polling</param>
+ <exception cref="T:System.InvalidOperationException">If the value of <paramref name="delayInMilliseconds"/> is less than 0</exception>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.DelayedConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True for if the base constraint fails, false if it succeeds</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.DelayedConstraint.Matches(NUnit.Framework.Constraints.ActualValueDelegate)">
+ <summary>
+ Test whether the constraint is satisfied by a delegate
+ </summary>
+ <param name="del">The delegate whose value is to be tested</param>
+ <returns>True for if the base constraint fails, false if it succeeds</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.DelayedConstraint.Matches``1(``0@)">
+ <summary>
+ Test whether the constraint is satisfied by a given reference.
+ Overridden to wait for the specified delay period before
+ calling the base constraint with the dereferenced value.
+ </summary>
+ <param name="actual">A reference to the value to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.DelayedConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.DelayedConstraint.WriteActualValueTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the actual value for a failing constraint test to a MessageWriter.
+ </summary>
+ <param name="writer">The writer on which the actual value is displayed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.DelayedConstraint.GetStringRepresentation">
+ <summary>
+ Returns the string representation of the constraint.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.EmptyDirectoryContraint">
+ <summary>
+ EmptyDirectoryConstraint is used to test that a directory is empty
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EmptyDirectoryContraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EmptyDirectoryContraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EmptyDirectoryContraint.WriteActualValueTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the actual value for a failing constraint test to a
+ MessageWriter. The default implementation simply writes
+ the raw value of actual, leaving it to the writer to
+ perform any formatting.
+ </summary>
+ <param name="writer">The writer on which the actual value is displayed</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.EmptyConstraint">
+ <summary>
+ EmptyConstraint tests a whether a string or collection is empty,
+ postponing the decision about which test is applied until the
+ type of the actual argument is known.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EmptyConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EmptyConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.EqualConstraint">
+ <summary>
+ EqualConstraint is able to compare an actual value with the
+ expected value provided in its constructor. Two objects are
+ considered equal if both are null, or if both have the same
+ value. NUnit has special semantics for some object types.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.EqualConstraint.clipStrings">
+ <summary>
+ If true, strings in error messages will be clipped
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.EqualConstraint.comparer">
+ <summary>
+ NUnitEqualityComparer used to test equality.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EqualConstraint.#ctor(System.Object)">
+ <summary>
+ Initializes a new instance of the <see cref="T:NUnit.Framework.Constraints.EqualConstraint"/> class.
+ </summary>
+ <param name="expected">The expected value.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EqualConstraint.Within(System.Object)">
+ <summary>
+ Flag the constraint to use a tolerance when determining equality.
+ </summary>
+ <param name="amount">Tolerance value to be used</param>
+ <returns>Self.</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EqualConstraint.Comparer(System.Collections.IComparer)">
+ <summary>
+ Flag the constraint to use the supplied IComparer object.
+ </summary>
+ <param name="comparer">The IComparer object to use.</param>
+ <returns>Self.</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EqualConstraint.Using(System.Collections.IComparer)">
+ <summary>
+ Flag the constraint to use the supplied IComparer object.
+ </summary>
+ <param name="comparer">The IComparer object to use.</param>
+ <returns>Self.</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EqualConstraint.Using``1(System.Collections.Generic.IComparer{``0})">
+ <summary>
+ Flag the constraint to use the supplied IComparer object.
+ </summary>
+ <param name="comparer">The IComparer object to use.</param>
+ <returns>Self.</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EqualConstraint.Using``1(System.Comparison{``0})">
+ <summary>
+ Flag the constraint to use the supplied Comparison object.
+ </summary>
+ <param name="comparer">The IComparer object to use.</param>
+ <returns>Self.</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EqualConstraint.Using(System.Collections.IEqualityComparer)">
+ <summary>
+ Flag the constraint to use the supplied IEqualityComparer object.
+ </summary>
+ <param name="comparer">The IComparer object to use.</param>
+ <returns>Self.</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EqualConstraint.Using``1(System.Collections.Generic.IEqualityComparer{``0})">
+ <summary>
+ Flag the constraint to use the supplied IEqualityComparer object.
+ </summary>
+ <param name="comparer">The IComparer object to use.</param>
+ <returns>Self.</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EqualConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EqualConstraint.WriteMessageTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write a failure message. Overridden to provide custom
+ failure messages for EqualConstraint.
+ </summary>
+ <param name="writer">The MessageWriter to write to</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EqualConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write description of this constraint
+ </summary>
+ <param name="writer">The MessageWriter to write to</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EqualConstraint.DisplayCollectionDifferences(NUnit.Framework.Constraints.MessageWriter,System.Collections.ICollection,System.Collections.ICollection,System.Int32)">
+ <summary>
+ Display the failure information for two collections that did not match.
+ </summary>
+ <param name="writer">The MessageWriter on which to display</param>
+ <param name="expected">The expected collection.</param>
+ <param name="actual">The actual collection</param>
+ <param name="depth">The depth of this failure in a set of nested collections</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EqualConstraint.DisplayCollectionTypesAndSizes(NUnit.Framework.Constraints.MessageWriter,System.Collections.ICollection,System.Collections.ICollection,System.Int32)">
+ <summary>
+ Displays a single line showing the types and sizes of the expected
+ and actual collections or arrays. If both are identical, the value is
+ only shown once.
+ </summary>
+ <param name="writer">The MessageWriter on which to display</param>
+ <param name="expected">The expected collection or array</param>
+ <param name="actual">The actual collection or array</param>
+ <param name="indent">The indentation level for the message line</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EqualConstraint.DisplayFailurePoint(NUnit.Framework.Constraints.MessageWriter,System.Collections.ICollection,System.Collections.ICollection,System.Int32,System.Int32)">
+ <summary>
+ Displays a single line showing the point in the expected and actual
+ arrays at which the comparison failed. If the arrays have different
+ structures or dimensions, both values are shown.
+ </summary>
+ <param name="writer">The MessageWriter on which to display</param>
+ <param name="expected">The expected array</param>
+ <param name="actual">The actual array</param>
+ <param name="failurePoint">Index of the failure point in the underlying collections</param>
+ <param name="indent">The indentation level for the message line</param>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.EqualConstraint.IgnoreCase">
+ <summary>
+ Flag the constraint to ignore case and return self.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.EqualConstraint.NoClip">
+ <summary>
+ Flag the constraint to suppress string clipping
+ and return self.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.EqualConstraint.AsCollection">
+ <summary>
+ Flag the constraint to compare arrays as collections
+ and return self.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.EqualConstraint.Ulps">
+ <summary>
+ Switches the .Within() modifier to interpret its tolerance as
+ a distance in representable values (see remarks).
+ </summary>
+ <returns>Self.</returns>
+ <remarks>
+ Ulp stands for "unit in the last place" and describes the minimum
+ amount a given value can change. For any integers, an ulp is 1 whole
+ digit. For floating point values, the accuracy of which is better
+ for smaller numbers and worse for larger numbers, an ulp depends
+ on the size of the number. Using ulps for comparison of floating
+ point results instead of fixed tolerances is safer because it will
+ automatically compensate for the added inaccuracy of larger numbers.
+ </remarks>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.EqualConstraint.Percent">
+ <summary>
+ Switches the .Within() modifier to interpret its tolerance as
+ a percentage that the actual values is allowed to deviate from
+ the expected value.
+ </summary>
+ <returns>Self</returns>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.EqualConstraint.Days">
+ <summary>
+ Causes the tolerance to be interpreted as a TimeSpan in days.
+ </summary>
+ <returns>Self</returns>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.EqualConstraint.Hours">
+ <summary>
+ Causes the tolerance to be interpreted as a TimeSpan in hours.
+ </summary>
+ <returns>Self</returns>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.EqualConstraint.Minutes">
+ <summary>
+ Causes the tolerance to be interpreted as a TimeSpan in minutes.
+ </summary>
+ <returns>Self</returns>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.EqualConstraint.Seconds">
+ <summary>
+ Causes the tolerance to be interpreted as a TimeSpan in seconds.
+ </summary>
+ <returns>Self</returns>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.EqualConstraint.Milliseconds">
+ <summary>
+ Causes the tolerance to be interpreted as a TimeSpan in milliseconds.
+ </summary>
+ <returns>Self</returns>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.EqualConstraint.Ticks">
+ <summary>
+ Causes the tolerance to be interpreted as a TimeSpan in clock ticks.
+ </summary>
+ <returns>Self</returns>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.EqualityAdapter">
+ <summary>
+ EqualityAdapter class handles all equality comparisons
+ that use an IEqualityComparer, IEqualityComparer<T>
+ or a ComparisonAdapter.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EqualityAdapter.ObjectsEqual(System.Object,System.Object)">
+ <summary>
+ Compares two objects, returning true if they are equal
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EqualityAdapter.For(System.Collections.IComparer)">
+ <summary>
+ Returns an EqualityAdapter that wraps an IComparer.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EqualityAdapter.For(System.Collections.IEqualityComparer)">
+ <summary>
+ Returns an EqualityAdapter that wraps an IEqualityComparer.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EqualityAdapter.For``1(System.Collections.Generic.IEqualityComparer{``0})">
+ <summary>
+ Returns an EqualityAdapter that wraps an IEqualityComparer<T>.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EqualityAdapter.For``1(System.Collections.Generic.IComparer{``0})">
+ <summary>
+ Returns an EqualityAdapter that wraps an IComparer<T>.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EqualityAdapter.For``1(System.Comparison{``0})">
+ <summary>
+ Returns an EqualityAdapter that wraps a Comparison<T>.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.FloatingPointNumerics">
+ <summary>Helper routines for working with floating point numbers</summary>
+ <remarks>
+ <para>
+ The floating point comparison code is based on this excellent article:
+ http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
+ </para>
+ <para>
+ "ULP" means Unit in the Last Place and in the context of this library refers to
+ the distance between two adjacent floating point numbers. IEEE floating point
+ numbers can only represent a finite subset of natural numbers, with greater
+ accuracy for smaller numbers and lower accuracy for very large numbers.
+ </para>
+ <para>
+ If a comparison is allowed "2 ulps" of deviation, that means the values are
+ allowed to deviate by up to 2 adjacent floating point values, which might be
+ as low as 0.0000001 for small numbers or as high as 10.0 for large numbers.
+ </para>
+ </remarks>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.FloatingPointNumerics.AreAlmostEqualUlps(System.Single,System.Single,System.Int32)">
+ <summary>Compares two floating point values for equality</summary>
+ <param name="left">First floating point value to be compared</param>
+ <param name="right">Second floating point value t be compared</param>
+ <param name="maxUlps">
+ Maximum number of representable floating point values that are allowed to
+ be between the left and the right floating point values
+ </param>
+ <returns>True if both numbers are equal or close to being equal</returns>
+ <remarks>
+ <para>
+ Floating point values can only represent a finite subset of natural numbers.
+ For example, the values 2.00000000 and 2.00000024 can be stored in a float,
+ but nothing inbetween them.
+ </para>
+ <para>
+ This comparison will count how many possible floating point values are between
+ the left and the right number. If the number of possible values between both
+ numbers is less than or equal to maxUlps, then the numbers are considered as
+ being equal.
+ </para>
+ <para>
+ Implementation partially follows the code outlined here:
+ http://www.anttirt.net/2007/08/19/proper-floating-point-comparisons/
+ </para>
+ </remarks>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.FloatingPointNumerics.AreAlmostEqualUlps(System.Double,System.Double,System.Int64)">
+ <summary>Compares two double precision floating point values for equality</summary>
+ <param name="left">First double precision floating point value to be compared</param>
+ <param name="right">Second double precision floating point value t be compared</param>
+ <param name="maxUlps">
+ Maximum number of representable double precision floating point values that are
+ allowed to be between the left and the right double precision floating point values
+ </param>
+ <returns>True if both numbers are equal or close to being equal</returns>
+ <remarks>
+ <para>
+ Double precision floating point values can only represent a limited series of
+ natural numbers. For example, the values 2.0000000000000000 and 2.0000000000000004
+ can be stored in a double, but nothing inbetween them.
+ </para>
+ <para>
+ This comparison will count how many possible double precision floating point
+ values are between the left and the right number. If the number of possible
+ values between both numbers is less than or equal to maxUlps, then the numbers
+ are considered as being equal.
+ </para>
+ <para>
+ Implementation partially follows the code outlined here:
+ http://www.anttirt.net/2007/08/19/proper-floating-point-comparisons/
+ </para>
+ </remarks>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.FloatingPointNumerics.ReinterpretAsInt(System.Single)">
+ <summary>
+ Reinterprets the memory contents of a floating point value as an integer value
+ </summary>
+ <param name="value">
+ Floating point value whose memory contents to reinterpret
+ </param>
+ <returns>
+ The memory contents of the floating point value interpreted as an integer
+ </returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.FloatingPointNumerics.ReinterpretAsLong(System.Double)">
+ <summary>
+ Reinterprets the memory contents of a double precision floating point
+ value as an integer value
+ </summary>
+ <param name="value">
+ Double precision floating point value whose memory contents to reinterpret
+ </param>
+ <returns>
+ The memory contents of the double precision floating point value
+ interpreted as an integer
+ </returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.FloatingPointNumerics.ReinterpretAsFloat(System.Int32)">
+ <summary>
+ Reinterprets the memory contents of an integer as a floating point value
+ </summary>
+ <param name="value">Integer value whose memory contents to reinterpret</param>
+ <returns>
+ The memory contents of the integer value interpreted as a floating point value
+ </returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.FloatingPointNumerics.ReinterpretAsDouble(System.Int64)">
+ <summary>
+ Reinterprets the memory contents of an integer value as a double precision
+ floating point value
+ </summary>
+ <param name="value">Integer whose memory contents to reinterpret</param>
+ <returns>
+ The memory contents of the integer interpreted as a double precision
+ floating point value
+ </returns>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.FloatingPointNumerics.FloatIntUnion">
+ <summary>Union of a floating point variable and an integer</summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.FloatingPointNumerics.FloatIntUnion.Float">
+ <summary>The union's value as a floating point variable</summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.FloatingPointNumerics.FloatIntUnion.Int">
+ <summary>The union's value as an integer</summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.FloatingPointNumerics.FloatIntUnion.UInt">
+ <summary>The union's value as an unsigned integer</summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.FloatingPointNumerics.DoubleLongUnion">
+ <summary>Union of a double precision floating point variable and a long</summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.FloatingPointNumerics.DoubleLongUnion.Double">
+ <summary>The union's value as a double precision floating point variable</summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.FloatingPointNumerics.DoubleLongUnion.Long">
+ <summary>The union's value as a long</summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.FloatingPointNumerics.DoubleLongUnion.ULong">
+ <summary>The union's value as an unsigned long</summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.MessageWriter">
+ <summary>
+ MessageWriter is the abstract base for classes that write
+ constraint descriptions and messages in some form. The
+ class has separate methods for writing various components
+ of a message, allowing implementations to tailor the
+ presentation as needed.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MessageWriter.#ctor">
+ <summary>
+ Construct a MessageWriter given a culture
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MessageWriter.WriteMessageLine(System.String,System.Object[])">
+ <summary>
+ Method to write single line message with optional args, usually
+ written to precede the general failure message.
+ </summary>
+ <param name="message">The message to be written</param>
+ <param name="args">Any arguments used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MessageWriter.WriteMessageLine(System.Int32,System.String,System.Object[])">
+ <summary>
+ Method to write single line message with optional args, usually
+ written to precede the general failure message, at a givel
+ indentation level.
+ </summary>
+ <param name="level">The indentation level of the message</param>
+ <param name="message">The message to be written</param>
+ <param name="args">Any arguments used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MessageWriter.DisplayDifferences(NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Display Expected and Actual lines for a constraint. This
+ is called by MessageWriter's default implementation of
+ WriteMessageTo and provides the generic two-line display.
+ </summary>
+ <param name="constraint">The constraint that failed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MessageWriter.DisplayDifferences(System.Object,System.Object)">
+ <summary>
+ Display Expected and Actual lines for given values. This
+ method may be called by constraints that need more control over
+ the display of actual and expected values than is provided
+ by the default implementation.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value causing the failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MessageWriter.DisplayDifferences(System.Object,System.Object,NUnit.Framework.Constraints.Tolerance)">
+ <summary>
+ Display Expected and Actual lines for given values, including
+ a tolerance value on the Expected line.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value causing the failure</param>
+ <param name="tolerance">The tolerance within which the test was made</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MessageWriter.DisplayStringDifferences(System.String,System.String,System.Int32,System.Boolean,System.Boolean)">
+ <summary>
+ Display the expected and actual string values on separate lines.
+ If the mismatch parameter is >=0, an additional line is displayed
+ line containing a caret that points to the mismatch point.
+ </summary>
+ <param name="expected">The expected string value</param>
+ <param name="actual">The actual string value</param>
+ <param name="mismatch">The point at which the strings don't match or -1</param>
+ <param name="ignoreCase">If true, case is ignored in locating the point where the strings differ</param>
+ <param name="clipping">If true, the strings should be clipped to fit the line</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MessageWriter.WriteConnector(System.String)">
+ <summary>
+ Writes the text for a connector.
+ </summary>
+ <param name="connector">The connector.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MessageWriter.WritePredicate(System.String)">
+ <summary>
+ Writes the text for a predicate.
+ </summary>
+ <param name="predicate">The predicate.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MessageWriter.WriteExpectedValue(System.Object)">
+ <summary>
+ Writes the text for an expected value.
+ </summary>
+ <param name="expected">The expected value.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MessageWriter.WriteModifier(System.String)">
+ <summary>
+ Writes the text for a modifier
+ </summary>
+ <param name="modifier">The modifier.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MessageWriter.WriteActualValue(System.Object)">
+ <summary>
+ Writes the text for an actual value.
+ </summary>
+ <param name="actual">The actual value.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MessageWriter.WriteValue(System.Object)">
+ <summary>
+ Writes the text for a generalized value.
+ </summary>
+ <param name="val">The value.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MessageWriter.WriteCollectionElements(System.Collections.ICollection,System.Int32,System.Int32)">
+ <summary>
+ Writes the text for a collection value,
+ starting at a particular point, to a max length
+ </summary>
+ <param name="collection">The collection containing elements to write.</param>
+ <param name="start">The starting point of the elements to write</param>
+ <param name="max">The maximum number of elements to write</param>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.MessageWriter.MaxLineLength">
+ <summary>
+ Abstract method to get the max line length
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.MsgUtils">
+ <summary>
+ Static methods used in creating messages
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.MsgUtils.ELLIPSIS">
+ <summary>
+ Static string used when strings are clipped
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MsgUtils.GetTypeRepresentation(System.Object)">
+ <summary>
+ Returns the representation of a type as used in NUnitLite.
+ This is the same as Type.ToString() except for arrays,
+ which are displayed with their declared sizes.
+ </summary>
+ <param name="obj"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MsgUtils.EscapeControlChars(System.String)">
+ <summary>
+ Converts any control characters in a string
+ to their escaped representation.
+ </summary>
+ <param name="s">The string to be converted</param>
+ <returns>The converted string</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MsgUtils.GetArrayIndicesAsString(System.Int32[])">
+ <summary>
+ Return the a string representation for a set of indices into an array
+ </summary>
+ <param name="indices">Array of indices for which a string is needed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MsgUtils.GetArrayIndicesFromCollectionIndex(System.Collections.ICollection,System.Int32)">
+ <summary>
+ Get an array of indices representing the point in a collection or
+ array corresponding to a single int index into the collection.
+ </summary>
+ <param name="collection">The collection to which the indices apply</param>
+ <param name="index">Index in the collection</param>
+ <returns>Array of indices</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MsgUtils.ClipString(System.String,System.Int32,System.Int32)">
+ <summary>
+ Clip a string to a given length, starting at a particular offset, returning the clipped
+ string with ellipses representing the removed parts
+ </summary>
+ <param name="s">The string to be clipped</param>
+ <param name="maxStringLength">The maximum permitted length of the result string</param>
+ <param name="clipStart">The point at which to start clipping</param>
+ <returns>The clipped string</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MsgUtils.ClipExpectedAndActual(System.String@,System.String@,System.Int32,System.Int32)">
+ <summary>
+ Clip the expected and actual strings in a coordinated fashion,
+ so that they may be displayed together.
+ </summary>
+ <param name="expected"></param>
+ <param name="actual"></param>
+ <param name="maxDisplayLength"></param>
+ <param name="mismatch"></param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.MsgUtils.FindMismatchPosition(System.String,System.String,System.Int32,System.Boolean)">
+ <summary>
+ Shows the position two strings start to differ. Comparison
+ starts at the start index.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The actual string</param>
+ <param name="istart">The index in the strings at which comparison should start</param>
+ <param name="ignoreCase">Boolean indicating whether case should be ignored</param>
+ <returns>-1 if no mismatch found, or the index where mismatch found</returns>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.Numerics">
+ <summary>
+ The Numerics class contains common operations on numeric values.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Numerics.IsNumericType(System.Object)">
+ <summary>
+ Checks the type of the object, returning true if
+ the object is a numeric type.
+ </summary>
+ <param name="obj">The object to check</param>
+ <returns>true if the object is a numeric type</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Numerics.IsFloatingPointNumeric(System.Object)">
+ <summary>
+ Checks the type of the object, returning true if
+ the object is a floating point numeric type.
+ </summary>
+ <param name="obj">The object to check</param>
+ <returns>true if the object is a floating point numeric type</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Numerics.IsFixedPointNumeric(System.Object)">
+ <summary>
+ Checks the type of the object, returning true if
+ the object is a fixed point numeric type.
+ </summary>
+ <param name="obj">The object to check</param>
+ <returns>true if the object is a fixed point numeric type</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Numerics.AreEqual(System.Object,System.Object,NUnit.Framework.Constraints.Tolerance@)">
+ <summary>
+ Test two numeric values for equality, performing the usual numeric
+ conversions and using a provided or default tolerance. If the tolerance
+ provided is Empty, this method may set it to a default tolerance.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="tolerance">A reference to the tolerance in effect</param>
+ <returns>True if the values are equal</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Numerics.Compare(System.Object,System.Object)">
+ <summary>
+ Compare two numeric values, performing the usual numeric conversions.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <returns>The relationship of the values to each other</returns>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.NUnitComparer">
+ <summary>
+ NUnitComparer encapsulates NUnit's default behavior
+ in comparing two objects.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.NUnitComparer.Compare(System.Object,System.Object)">
+ <summary>
+ Compares two objects
+ </summary>
+ <param name="x"></param>
+ <param name="y"></param>
+ <returns></returns>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.NUnitComparer.Default">
+ <summary>
+ Returns the default NUnitComparer.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.NUnitEqualityComparer">
+ <summary>
+ NUnitEqualityComparer encapsulates NUnit's handling of
+ equality tests between objects.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.NUnitEqualityComparer.caseInsensitive">
+ <summary>
+ If true, all string comparisons will ignore case
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.NUnitEqualityComparer.compareAsCollection">
+ <summary>
+ If true, arrays will be treated as collections, allowing
+ those of different dimensions to be compared
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.NUnitEqualityComparer.tolerance">
+ <summary>
+ If non-zero, equality comparisons within the specified
+ tolerance will succeed.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.NUnitEqualityComparer.externalComparer">
+ <summary>
+ Comparison object used in comparisons for some constraints.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.NUnitEqualityComparer.ObjectsEqual(System.Object,System.Object)">
+ <summary>
+ Compares two objects for equality.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.NUnitEqualityComparer.ArraysEqual(System.Array,System.Array)">
+ <summary>
+ Helper method to compare two arrays
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.NUnitEqualityComparer.DirectoriesEqual(System.IO.DirectoryInfo,System.IO.DirectoryInfo)">
+ <summary>
+ Method to compare two DirectoryInfo objects
+ </summary>
+ <param name="x">first directory to compare</param>
+ <param name="y">second directory to compare</param>
+ <returns>true if equivalent, false if not</returns>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.NUnitEqualityComparer.Default">
+ <summary>
+ Returns the default NUnitEqualityComparer
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.NUnitEqualityComparer.IgnoreCase">
+ <summary>
+ Gets and sets a flag indicating whether case should
+ be ignored in determining equality.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.NUnitEqualityComparer.CompareAsCollection">
+ <summary>
+ Gets and sets a flag indicating that arrays should be
+ compared as collections, without regard to their shape.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.NUnitEqualityComparer.ExternalComparer">
+ <summary>
+ Gets and sets an external comparer to be used to
+ test for equality. It is applied to members of
+ collections, in place of NUnit's own logic.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.NUnitEqualityComparer.Tolerance">
+ <summary>
+ Gets and sets a tolerance used to compare objects of
+ certin types.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.NUnitEqualityComparer.FailurePoints">
+ <summary>
+ Gets the list of failure points for the last Match performed.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.PathConstraint">
+ <summary>
+ PathConstraint serves as the abstract base of constraints
+ that operate on paths and provides several helper methods.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.PathConstraint.expectedPath">
+ <summary>
+ The expected path used in the constraint
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.PathConstraint.actualPath">
+ <summary>
+ The actual path being tested
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.PathConstraint.caseInsensitive">
+ <summary>
+ Flag indicating whether a caseInsensitive comparison should be made
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PathConstraint.#ctor(System.String)">
+ <summary>
+ Construct a PathConstraint for a give expected path
+ </summary>
+ <param name="expected">The expected path</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PathConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PathConstraint.IsMatch(System.String,System.String)">
+ <summary>
+ Returns true if the expected path and actual path match
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PathConstraint.GetStringRepresentation">
+ <summary>
+ Returns the string representation of this constraint
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PathConstraint.Canonicalize(System.String)">
+ <summary>
+ Canonicalize the provided path
+ </summary>
+ <param name="path"></param>
+ <returns>The path in standardized form</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PathConstraint.IsSamePath(System.String,System.String,System.Boolean)">
+ <summary>
+ Test whether two paths are the same
+ </summary>
+ <param name="path1">The first path</param>
+ <param name="path2">The second path</param>
+ <param name="ignoreCase">Indicates whether case should be ignored</param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PathConstraint.IsSubPath(System.String,System.String,System.Boolean)">
+ <summary>
+ Test whether one path is under another path
+ </summary>
+ <param name="path1">The first path - supposed to be the parent path</param>
+ <param name="path2">The second path - supposed to be the child path</param>
+ <param name="ignoreCase">Indicates whether case should be ignored</param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PathConstraint.IsSamePathOrUnder(System.String,System.String)">
+ <summary>
+ Test whether one path is the same as or under another path
+ </summary>
+ <param name="path1">The first path - supposed to be the parent path</param>
+ <param name="path2">The second path - supposed to be the child path</param>
+ <returns></returns>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.PathConstraint.IgnoreCase">
+ <summary>
+ Modifies the current instance to be case-insensitve
+ and returns it.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.PathConstraint.RespectCase">
+ <summary>
+ Modifies the current instance to be case-sensitve
+ and returns it.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.SamePathConstraint">
+ <summary>
+ Summary description for SamePathConstraint.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.SamePathConstraint.#ctor(System.String)">
+ <summary>
+ Initializes a new instance of the <see cref="T:SamePathConstraint"/> class.
+ </summary>
+ <param name="expected">The expected path</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.SamePathConstraint.IsMatch(System.String,System.String)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="expectedPath">The expected path</param>
+ <param name="actualPath">The actual path</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.SamePathConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.SubPathConstraint">
+ <summary>
+ SubPathConstraint tests that the actual path is under the expected path
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.SubPathConstraint.#ctor(System.String)">
+ <summary>
+ Initializes a new instance of the <see cref="T:SubPathConstraint"/> class.
+ </summary>
+ <param name="expected">The expected path</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.SubPathConstraint.IsMatch(System.String,System.String)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="expectedPath">The expected path</param>
+ <param name="actualPath">The actual path</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.SubPathConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.SamePathOrUnderConstraint">
+ <summary>
+ SamePathOrUnderConstraint tests that one path is under another
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.SamePathOrUnderConstraint.#ctor(System.String)">
+ <summary>
+ Initializes a new instance of the <see cref="T:SamePathOrUnderConstraint"/> class.
+ </summary>
+ <param name="expected">The expected path</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.SamePathOrUnderConstraint.IsMatch(System.String,System.String)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="expectedPath">The expected path</param>
+ <param name="actualPath">The actual path</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.SamePathOrUnderConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.PredicateConstraint`1">
+ <summary>
+ Predicate constraint wraps a Predicate in a constraint,
+ returning success if the predicate is true.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PredicateConstraint`1.#ctor(System.Predicate{`0})">
+ <summary>
+ Construct a PredicateConstraint from a predicate
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PredicateConstraint`1.Matches(System.Object)">
+ <summary>
+ Determines whether the predicate succeeds when applied
+ to the actual value.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PredicateConstraint`1.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Writes the description to a MessageWriter
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.NotConstraint">
+ <summary>
+ NotConstraint negates the effect of some other constraint
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.NotConstraint.#ctor(NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Initializes a new instance of the <see cref="T:NotConstraint"/> class.
+ </summary>
+ <param name="baseConstraint">The base constraint to be negated.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.NotConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True for if the base constraint fails, false if it succeeds</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.NotConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.NotConstraint.WriteActualValueTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the actual value for a failing constraint test to a MessageWriter.
+ </summary>
+ <param name="writer">The writer on which the actual value is displayed</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.AllItemsConstraint">
+ <summary>
+ AllItemsConstraint applies another constraint to each
+ item in a collection, succeeding if they all succeed.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AllItemsConstraint.#ctor(NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Construct an AllItemsConstraint on top of an existing constraint
+ </summary>
+ <param name="itemConstraint"></param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AllItemsConstraint.Matches(System.Object)">
+ <summary>
+ Apply the item constraint to each item in the collection,
+ failing if any item fails.
+ </summary>
+ <param name="actual"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AllItemsConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write a description of this constraint to a MessageWriter
+ </summary>
+ <param name="writer"></param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.SomeItemsConstraint">
+ <summary>
+ SomeItemsConstraint applies another constraint to each
+ item in a collection, succeeding if any of them succeeds.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.SomeItemsConstraint.#ctor(NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Construct a SomeItemsConstraint on top of an existing constraint
+ </summary>
+ <param name="itemConstraint"></param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.SomeItemsConstraint.Matches(System.Object)">
+ <summary>
+ Apply the item constraint to each item in the collection,
+ succeeding if any item succeeds.
+ </summary>
+ <param name="actual"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.SomeItemsConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write a description of this constraint to a MessageWriter
+ </summary>
+ <param name="writer"></param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.NoItemConstraint">
+ <summary>
+ NoItemConstraint applies another constraint to each
+ item in a collection, failing if any of them succeeds.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.NoItemConstraint.#ctor(NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Construct a SomeItemsConstraint on top of an existing constraint
+ </summary>
+ <param name="itemConstraint"></param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.NoItemConstraint.Matches(System.Object)">
+ <summary>
+ Apply the item constraint to each item in the collection,
+ failing if any item fails.
+ </summary>
+ <param name="actual"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.NoItemConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write a description of this constraint to a MessageWriter
+ </summary>
+ <param name="writer"></param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.PropertyExistsConstraint">
+ <summary>
+ PropertyExistsConstraint tests that a named property
+ exists on the object provided through Match.
+
+ Originally, PropertyConstraint provided this feature
+ in addition to making optional tests on the vaue
+ of the property. The two constraints are now separate.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PropertyExistsConstraint.#ctor(System.String)">
+ <summary>
+ Initializes a new instance of the <see cref="T:PropertyExistConstraint"/> class.
+ </summary>
+ <param name="name">The name of the property.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PropertyExistsConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the property exists for a given object
+ </summary>
+ <param name="actual">The object to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PropertyExistsConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PropertyExistsConstraint.WriteActualValueTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the actual value for a failing constraint test to a
+ MessageWriter.
+ </summary>
+ <param name="writer">The writer on which the actual value is displayed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PropertyExistsConstraint.GetStringRepresentation">
+ <summary>
+ Returns the string representation of the constraint.
+ </summary>
+ <returns></returns>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.PropertyConstraint">
+ <summary>
+ PropertyConstraint extracts a named property and uses
+ its value as the actual value for a chained constraint.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PropertyConstraint.#ctor(System.String,NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Initializes a new instance of the <see cref="T:PropertyConstraint"/> class.
+ </summary>
+ <param name="name">The name.</param>
+ <param name="baseConstraint">The constraint to apply to the property.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PropertyConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PropertyConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PropertyConstraint.WriteActualValueTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the actual value for a failing constraint test to a
+ MessageWriter. The default implementation simply writes
+ the raw value of actual, leaving it to the writer to
+ perform any formatting.
+ </summary>
+ <param name="writer">The writer on which the actual value is displayed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.PropertyConstraint.GetStringRepresentation">
+ <summary>
+ Returns the string representation of the constraint.
+ </summary>
+ <returns></returns>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.RangeConstraint">
+ <summary>
+ RangeConstraint tests whethe two values are within a
+ specified range.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.RangeConstraint.#ctor(System.IComparable,System.IComparable)">
+ <summary>
+ Initializes a new instance of the <see cref="T:RangeConstraint"/> class.
+ </summary>
+ <param name="from">From.</param>
+ <param name="to">To.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.RangeConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.RangeConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.RangeConstraint.Using(System.Collections.IComparer)">
+ <summary>
+ Modifies the constraint to use an IComparer and returns self.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.RangeConstraint.Using``1(System.Collections.Generic.IComparer{``0})">
+ <summary>
+ Modifies the constraint to use an IComparer<T> and returns self.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.RangeConstraint.Using``1(System.Comparison{``0})">
+ <summary>
+ Modifies the constraint to use a Comparison<T> and returns self.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.ResolvableConstraintExpression">
+ <summary>
+ ResolvableConstraintExpression is used to represent a compound
+ constraint being constructed at a point where the last operator
+ may either terminate the expression or may have additional
+ qualifying constraints added to it.
+
+ It is used, for example, for a Property element or for
+ an Exception element, either of which may be optionally
+ followed by constraints that apply to the property or
+ exception.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ResolvableConstraintExpression.#ctor">
+ <summary>
+ Create a new instance of ResolvableConstraintExpression
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ResolvableConstraintExpression.#ctor(NUnit.Framework.Constraints.ConstraintBuilder)">
+ <summary>
+ Create a new instance of ResolvableConstraintExpression,
+ passing in a pre-populated ConstraintBuilder.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ResolvableConstraintExpression.NUnit#Framework#Constraints#IResolveConstraint#Resolve">
+ <summary>
+ Resolve the current expression to a Constraint
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ResolvableConstraintExpression.And">
+ <summary>
+ Appends an And Operator to the expression
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ResolvableConstraintExpression.Or">
+ <summary>
+ Appends an Or operator to the expression.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.ReusableConstraint">
+ <summary>
+ ReusableConstraint wraps a resolved constraint so that it
+ may be saved and reused as needed.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ReusableConstraint.#ctor(NUnit.Framework.Constraints.IResolveConstraint)">
+ <summary>
+ Construct a ReusableConstraint
+ </summary>
+ <param name="c">The constraint or expression to be reused</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ReusableConstraint.op_Implicit(NUnit.Framework.Constraints.Constraint)~NUnit.Framework.Constraints.ReusableConstraint">
+ <summary>
+ Conversion operator from a normal constraint to a ReusableConstraint.
+ </summary>
+ <param name="c">The original constraint to be wrapped as a ReusableConstraint</param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ReusableConstraint.ToString">
+ <summary>
+ Returns the string representation of the constraint.
+ </summary>
+ <returns>A string representing the constraint</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ReusableConstraint.Resolve">
+ <summary>
+ Resolves the ReusableConstraint by returning the constraint
+ that it originally wrapped.
+ </summary>
+ <returns>A resolved constraint</returns>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.SameAsConstraint">
+ <summary>
+ SameAsConstraint tests whether an object is identical to
+ the object passed to its constructor
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.SameAsConstraint.#ctor(System.Object)">
+ <summary>
+ Initializes a new instance of the <see cref="T:SameAsConstraint"/> class.
+ </summary>
+ <param name="expected">The expected object.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.SameAsConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.SameAsConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.BinarySerializableConstraint">
+ <summary>
+ BinarySerializableConstraint tests whether
+ an object is serializable in binary format.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.BinarySerializableConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.BinarySerializableConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.BinarySerializableConstraint.WriteActualValueTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the actual value for a failing constraint test to a
+ MessageWriter. The default implementation simply writes
+ the raw value of actual, leaving it to the writer to
+ perform any formatting.
+ </summary>
+ <param name="writer">The writer on which the actual value is displayed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.BinarySerializableConstraint.GetStringRepresentation">
+ <summary>
+ Returns the string representation
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.XmlSerializableConstraint">
+ <summary>
+ BinarySerializableConstraint tests whether
+ an object is serializable in binary format.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.XmlSerializableConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.XmlSerializableConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.XmlSerializableConstraint.WriteActualValueTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the actual value for a failing constraint test to a
+ MessageWriter. The default implementation simply writes
+ the raw value of actual, leaving it to the writer to
+ perform any formatting.
+ </summary>
+ <param name="writer">The writer on which the actual value is displayed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.XmlSerializableConstraint.GetStringRepresentation">
+ <summary>
+ Returns the string representation of this constraint
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.StringConstraint">
+ <summary>
+ StringConstraint is the abstract base for constraints
+ that operate on strings. It supports the IgnoreCase
+ modifier for string operations.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.StringConstraint.expected">
+ <summary>
+ The expected value
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.StringConstraint.caseInsensitive">
+ <summary>
+ Indicates whether tests should be case-insensitive
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.StringConstraint.#ctor(System.String)">
+ <summary>
+ Constructs a StringConstraint given an expected value
+ </summary>
+ <param name="expected">The expected value</param>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.StringConstraint.IgnoreCase">
+ <summary>
+ Modify the constraint to ignore case in matching.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.EmptyStringConstraint">
+ <summary>
+ EmptyStringConstraint tests whether a string is empty.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EmptyStringConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EmptyStringConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.NullOrEmptyStringConstraint">
+ <summary>
+ NullEmptyStringConstraint tests whether a string is either null or empty.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.NullOrEmptyStringConstraint.#ctor">
+ <summary>
+ Constructs a new NullOrEmptyStringConstraint
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.NullOrEmptyStringConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.NullOrEmptyStringConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.SubstringConstraint">
+ <summary>
+ SubstringConstraint can test whether a string contains
+ the expected substring.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.SubstringConstraint.#ctor(System.String)">
+ <summary>
+ Initializes a new instance of the <see cref="T:SubstringConstraint"/> class.
+ </summary>
+ <param name="expected">The expected.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.SubstringConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.SubstringConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.StartsWithConstraint">
+ <summary>
+ StartsWithConstraint can test whether a string starts
+ with an expected substring.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.StartsWithConstraint.#ctor(System.String)">
+ <summary>
+ Initializes a new instance of the <see cref="T:StartsWithConstraint"/> class.
+ </summary>
+ <param name="expected">The expected string</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.StartsWithConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is matched by the actual value.
+ This is a template method, which calls the IsMatch method
+ of the derived class.
+ </summary>
+ <param name="actual"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.StartsWithConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.EndsWithConstraint">
+ <summary>
+ EndsWithConstraint can test whether a string ends
+ with an expected substring.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EndsWithConstraint.#ctor(System.String)">
+ <summary>
+ Initializes a new instance of the <see cref="T:EndsWithConstraint"/> class.
+ </summary>
+ <param name="expected">The expected string</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EndsWithConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is matched by the actual value.
+ This is a template method, which calls the IsMatch method
+ of the derived class.
+ </summary>
+ <param name="actual"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.EndsWithConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.RegexConstraint">
+ <summary>
+ RegexConstraint can test whether a string matches
+ the pattern provided.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.RegexConstraint.#ctor(System.String)">
+ <summary>
+ Initializes a new instance of the <see cref="T:RegexConstraint"/> class.
+ </summary>
+ <param name="pattern">The pattern.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.RegexConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True for success, false for failure</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.RegexConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.ThrowsConstraint">
+ <summary>
+ ThrowsConstraint is used to test the exception thrown by
+ a delegate by applying a constraint to it.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ThrowsConstraint.#ctor(NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Initializes a new instance of the <see cref="T:ThrowsConstraint"/> class,
+ using a constraint to be applied to the exception.
+ </summary>
+ <param name="baseConstraint">A constraint to apply to the caught exception.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ThrowsConstraint.Matches(System.Object)">
+ <summary>
+ Executes the code of the delegate and captures any exception.
+ If a non-null base constraint was provided, it applies that
+ constraint to the exception.
+ </summary>
+ <param name="actual">A delegate representing the code to be tested</param>
+ <returns>True if an exception is thrown and the constraint succeeds, otherwise false</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ThrowsConstraint.Matches(NUnit.Framework.Constraints.ActualValueDelegate)">
+ <summary>
+ Converts an ActualValueDelegate to a TestDelegate
+ before calling the primary overload.
+ </summary>
+ <param name="del"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ThrowsConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ThrowsConstraint.WriteActualValueTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the actual value for a failing constraint test to a
+ MessageWriter. The default implementation simply writes
+ the raw value of actual, leaving it to the writer to
+ perform any formatting.
+ </summary>
+ <param name="writer">The writer on which the actual value is displayed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ThrowsConstraint.GetStringRepresentation">
+ <summary>
+ Returns the string representation of this constraint
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.ThrowsConstraint.ActualException">
+ <summary>
+ Get the actual exception thrown - used by Assert.Throws.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.ThrowsNothingConstraint">
+ <summary>
+ ThrowsNothingConstraint tests that a delegate does not
+ throw an exception.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ThrowsNothingConstraint.Matches(System.Object)">
+ <summary>
+ Test whether the constraint is satisfied by a given value
+ </summary>
+ <param name="actual">The value to be tested</param>
+ <returns>True if no exception is thrown, otherwise false</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ThrowsNothingConstraint.Matches(NUnit.Framework.Constraints.ActualValueDelegate)">
+ <summary>
+ Converts an ActualValueDelegate to a TestDelegate
+ before calling the primary overload.
+ </summary>
+ <param name="del"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ThrowsNothingConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the constraint description to a MessageWriter
+ </summary>
+ <param name="writer">The writer on which the description is displayed</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ThrowsNothingConstraint.WriteActualValueTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the actual value for a failing constraint test to a
+ MessageWriter. The default implementation simply writes
+ the raw value of actual, leaving it to the writer to
+ perform any formatting.
+ </summary>
+ <param name="writer">The writer on which the actual value is displayed</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.ToleranceMode">
+ <summary>
+ Modes in which the tolerance value for a comparison can
+ be interpreted.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.ToleranceMode.None">
+ <summary>
+ The tolerance was created with a value, without specifying
+ how the value would be used. This is used to prevent setting
+ the mode more than once and is generally changed to Linear
+ upon execution of the test.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.ToleranceMode.Linear">
+ <summary>
+ The tolerance is used as a numeric range within which
+ two compared values are considered to be equal.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.ToleranceMode.Percent">
+ <summary>
+ Interprets the tolerance as the percentage by which
+ the two compared values my deviate from each other.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.ToleranceMode.Ulps">
+ <summary>
+ Compares two values based in their distance in
+ representable numbers.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.Tolerance">
+ <summary>
+ The Tolerance class generalizes the notion of a tolerance
+ within which an equality test succeeds. Normally, it is
+ used with numeric types, but it can be used with any
+ type that supports taking a difference between two
+ objects and comparing that difference to a value.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Tolerance.#ctor(System.Object)">
+ <summary>
+ Constructs a linear tolerance of a specdified amount
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Tolerance.#ctor(System.Object,NUnit.Framework.Constraints.ToleranceMode)">
+ <summary>
+ Constructs a tolerance given an amount and ToleranceMode
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.Tolerance.CheckLinearAndNumeric">
+ <summary>
+ Tests that the current Tolerance is linear with a
+ numeric value, throwing an exception if it is not.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.Tolerance.Empty">
+ <summary>
+ Returns an empty Tolerance object, equivalent to
+ specifying an exact match.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.Tolerance.Mode">
+ <summary>
+ Gets the ToleranceMode for the current Tolerance
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.Tolerance.Value">
+ <summary>
+ Gets the value of the current Tolerance instance.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.Tolerance.Percent">
+ <summary>
+ Returns a new tolerance, using the current amount as a percentage.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.Tolerance.Ulps">
+ <summary>
+ Returns a new tolerance, using the current amount in Ulps.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.Tolerance.Days">
+ <summary>
+ Returns a new tolerance with a TimeSpan as the amount, using
+ the current amount as a number of days.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.Tolerance.Hours">
+ <summary>
+ Returns a new tolerance with a TimeSpan as the amount, using
+ the current amount as a number of hours.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.Tolerance.Minutes">
+ <summary>
+ Returns a new tolerance with a TimeSpan as the amount, using
+ the current amount as a number of minutes.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.Tolerance.Seconds">
+ <summary>
+ Returns a new tolerance with a TimeSpan as the amount, using
+ the current amount as a number of seconds.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.Tolerance.Milliseconds">
+ <summary>
+ Returns a new tolerance with a TimeSpan as the amount, using
+ the current amount as a number of milliseconds.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.Tolerance.Ticks">
+ <summary>
+ Returns a new tolerance with a TimeSpan as the amount, using
+ the current amount as a number of clock ticks.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Constraints.Tolerance.IsEmpty">
+ <summary>
+ Returns true if the current tolerance is empty.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.TypeConstraint">
+ <summary>
+ TypeConstraint is the abstract base for constraints
+ that take a Type as their expected value.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.Constraints.TypeConstraint.expectedType">
+ <summary>
+ The expected Type used by the constraint
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.TypeConstraint.#ctor(System.Type)">
+ <summary>
+ Construct a TypeConstraint for a given Type
+ </summary>
+ <param name="type"></param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.TypeConstraint.WriteActualValueTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the actual value for a failing constraint test to a
+ MessageWriter. TypeConstraints override this method to write
+ the name of the type.
+ </summary>
+ <param name="writer">The writer on which the actual value is displayed</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.ExactTypeConstraint">
+ <summary>
+ ExactTypeConstraint is used to test that an object
+ is of the exact type provided in the constructor
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ExactTypeConstraint.#ctor(System.Type)">
+ <summary>
+ Construct an ExactTypeConstraint for a given Type
+ </summary>
+ <param name="type">The expected Type.</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ExactTypeConstraint.Matches(System.Object)">
+ <summary>
+ Test that an object is of the exact type specified
+ </summary>
+ <param name="actual">The actual value.</param>
+ <returns>True if the tested object is of the exact type provided, otherwise false.</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.ExactTypeConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write the description of this constraint to a MessageWriter
+ </summary>
+ <param name="writer">The MessageWriter to use</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.InstanceOfTypeConstraint">
+ <summary>
+ InstanceOfTypeConstraint is used to test that an object
+ is of the same type provided or derived from it.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.InstanceOfTypeConstraint.#ctor(System.Type)">
+ <summary>
+ Construct an InstanceOfTypeConstraint for the type provided
+ </summary>
+ <param name="type">The expected Type</param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.InstanceOfTypeConstraint.Matches(System.Object)">
+ <summary>
+ Test whether an object is of the specified type or a derived type
+ </summary>
+ <param name="actual">The object to be tested</param>
+ <returns>True if the object is of the provided type or derives from it, otherwise false.</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.InstanceOfTypeConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write a description of this constraint to a MessageWriter
+ </summary>
+ <param name="writer">The MessageWriter to use</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.AssignableFromConstraint">
+ <summary>
+ AssignableFromConstraint is used to test that an object
+ can be assigned from a given Type.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AssignableFromConstraint.#ctor(System.Type)">
+ <summary>
+ Construct an AssignableFromConstraint for the type provided
+ </summary>
+ <param name="type"></param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AssignableFromConstraint.Matches(System.Object)">
+ <summary>
+ Test whether an object can be assigned from the specified type
+ </summary>
+ <param name="actual">The object to be tested</param>
+ <returns>True if the object can be assigned a value of the expected Type, otherwise false.</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AssignableFromConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write a description of this constraint to a MessageWriter
+ </summary>
+ <param name="writer">The MessageWriter to use</param>
+ </member>
+ <member name="T:NUnit.Framework.Constraints.AssignableToConstraint">
+ <summary>
+ AssignableToConstraint is used to test that an object
+ can be assigned to a given Type.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AssignableToConstraint.#ctor(System.Type)">
+ <summary>
+ Construct an AssignableToConstraint for the type provided
+ </summary>
+ <param name="type"></param>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AssignableToConstraint.Matches(System.Object)">
+ <summary>
+ Test whether an object can be assigned to the specified type
+ </summary>
+ <param name="actual">The object to be tested</param>
+ <returns>True if the object can be assigned a value of the expected Type, otherwise false.</returns>
+ </member>
+ <member name="M:NUnit.Framework.Constraints.AssignableToConstraint.WriteDescriptionTo(NUnit.Framework.Constraints.MessageWriter)">
+ <summary>
+ Write a description of this constraint to a MessageWriter
+ </summary>
+ <param name="writer">The MessageWriter to use</param>
+ </member>
+ <member name="T:NUnit.Framework.AssertionException">
+ <summary>
+ Thrown when an assertion failed.
+ </summary>
+
+ </member>
+ <member name="M:NUnit.Framework.AssertionException.#ctor(System.String)">
+ <param name="message">The error message that explains
+ the reason for the exception</param>
+ </member>
+ <member name="M:NUnit.Framework.AssertionException.#ctor(System.String,System.Exception)">
+ <param name="message">The error message that explains
+ the reason for the exception</param>
+ <param name="inner">The exception that caused the
+ current exception</param>
+ </member>
+ <member name="M:NUnit.Framework.AssertionException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)">
+ <summary>
+ Serialization Constructor
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.IgnoreException">
+ <summary>
+ Thrown when an assertion failed.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.IgnoreException.#ctor(System.String)">
+ <param name="message"></param>
+ </member>
+ <member name="M:NUnit.Framework.IgnoreException.#ctor(System.String,System.Exception)">
+ <param name="message">The error message that explains
+ the reason for the exception</param>
+ <param name="inner">The exception that caused the
+ current exception</param>
+ </member>
+ <member name="M:NUnit.Framework.IgnoreException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)">
+ <summary>
+ Serialization Constructor
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.InconclusiveException">
+ <summary>
+ Thrown when a test executes inconclusively.
+ </summary>
+
+ </member>
+ <member name="M:NUnit.Framework.InconclusiveException.#ctor(System.String)">
+ <param name="message">The error message that explains
+ the reason for the exception</param>
+ </member>
+ <member name="M:NUnit.Framework.InconclusiveException.#ctor(System.String,System.Exception)">
+ <param name="message">The error message that explains
+ the reason for the exception</param>
+ <param name="inner">The exception that caused the
+ current exception</param>
+ </member>
+ <member name="M:NUnit.Framework.InconclusiveException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)">
+ <summary>
+ Serialization Constructor
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.SuccessException">
+ <summary>
+ Thrown when an assertion failed.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.SuccessException.#ctor(System.String)">
+ <param name="message"></param>
+ </member>
+ <member name="M:NUnit.Framework.SuccessException.#ctor(System.String,System.Exception)">
+ <param name="message">The error message that explains
+ the reason for the exception</param>
+ <param name="inner">The exception that caused the
+ current exception</param>
+ </member>
+ <member name="M:NUnit.Framework.SuccessException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)">
+ <summary>
+ Serialization Constructor
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.TestDelegate">
+ <summary>
+ Delegate used by tests that execute code and
+ capture any thrown exception.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Assert">
+ <summary>
+ The Assert class contains a collection of static methods that
+ implement the most common assertions used in NUnit.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Assert.#ctor">
+ <summary>
+ We don't actually want any instances of this object, but some people
+ like to inherit from it to add other static methods. Hence, the
+ protected constructor disallows any instances of this object.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Equals(System.Object,System.Object)">
+ <summary>
+ The Equals method throws an AssertionException. This is done
+ to make sure there is no mistake by calling this function.
+ </summary>
+ <param name="a"></param>
+ <param name="b"></param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.ReferenceEquals(System.Object,System.Object)">
+ <summary>
+ override the default ReferenceEquals to throw an AssertionException. This
+ implementation makes sure there is no mistake in calling this function
+ as part of Assert.
+ </summary>
+ <param name="a"></param>
+ <param name="b"></param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AssertDoublesAreEqual(System.Double,System.Double,System.Double,System.String,System.Object[])">
+ <summary>
+ Helper for Assert.AreEqual(double expected, double actual, ...)
+ allowing code generation to work consistently.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="delta">The maximum acceptable difference between the
+ the expected and the actual</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Pass(System.String,System.Object[])">
+ <summary>
+ Throws a <see cref="T:NUnit.Framework.SuccessException"/> with the message and arguments
+ that are passed in. This allows a test to be cut short, with a result
+ of success returned to NUnit.
+ </summary>
+ <param name="message">The message to initialize the <see cref="T:NUnit.Framework.AssertionException"/> with.</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Pass(System.String)">
+ <summary>
+ Throws a <see cref="T:NUnit.Framework.SuccessException"/> with the message and arguments
+ that are passed in. This allows a test to be cut short, with a result
+ of success returned to NUnit.
+ </summary>
+ <param name="message">The message to initialize the <see cref="T:NUnit.Framework.AssertionException"/> with.</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Pass">
+ <summary>
+ Throws a <see cref="T:NUnit.Framework.SuccessException"/> with the message and arguments
+ that are passed in. This allows a test to be cut short, with a result
+ of success returned to NUnit.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Fail(System.String,System.Object[])">
+ <summary>
+ Throws an <see cref="T:NUnit.Framework.AssertionException"/> with the message and arguments
+ that are passed in. This is used by the other Assert functions.
+ </summary>
+ <param name="message">The message to initialize the <see cref="T:NUnit.Framework.AssertionException"/> with.</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Fail(System.String)">
+ <summary>
+ Throws an <see cref="T:NUnit.Framework.AssertionException"/> with the message that is
+ passed in. This is used by the other Assert functions.
+ </summary>
+ <param name="message">The message to initialize the <see cref="T:NUnit.Framework.AssertionException"/> with.</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Fail">
+ <summary>
+ Throws an <see cref="T:NUnit.Framework.AssertionException"/>.
+ This is used by the other Assert functions.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Ignore(System.String,System.Object[])">
+ <summary>
+ Throws an <see cref="T:NUnit.Framework.IgnoreException"/> with the message and arguments
+ that are passed in. This causes the test to be reported as ignored.
+ </summary>
+ <param name="message">The message to initialize the <see cref="T:NUnit.Framework.AssertionException"/> with.</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Ignore(System.String)">
+ <summary>
+ Throws an <see cref="T:NUnit.Framework.IgnoreException"/> with the message that is
+ passed in. This causes the test to be reported as ignored.
+ </summary>
+ <param name="message">The message to initialize the <see cref="T:NUnit.Framework.AssertionException"/> with.</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Ignore">
+ <summary>
+ Throws an <see cref="T:NUnit.Framework.IgnoreException"/>.
+ This causes the test to be reported as ignored.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Inconclusive(System.String,System.Object[])">
+ <summary>
+ Throws an <see cref="T:NUnit.Framework.InconclusiveException"/> with the message and arguments
+ that are passed in. This causes the test to be reported as inconclusive.
+ </summary>
+ <param name="message">The message to initialize the <see cref="T:NUnit.Framework.InconclusiveException"/> with.</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Inconclusive(System.String)">
+ <summary>
+ Throws an <see cref="T:NUnit.Framework.InconclusiveException"/> with the message that is
+ passed in. This causes the test to be reported as inconclusive.
+ </summary>
+ <param name="message">The message to initialize the <see cref="T:NUnit.Framework.InconclusiveException"/> with.</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Inconclusive">
+ <summary>
+ Throws an <see cref="T:NUnit.Framework.InconclusiveException"/>.
+ This causes the test to be reported as Inconclusive.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Assert.That(System.Object,NUnit.Framework.Constraints.IResolveConstraint)">
+ <summary>
+ Apply a constraint to an actual value, succeeding if the constraint
+ is satisfied and throwing an assertion exception on failure.
+ </summary>
+ <param name="expression">A Constraint to be applied</param>
+ <param name="actual">The actual value to test</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.That(System.Object,NUnit.Framework.Constraints.IResolveConstraint,System.String)">
+ <summary>
+ Apply a constraint to an actual value, succeeding if the constraint
+ is satisfied and throwing an assertion exception on failure.
+ </summary>
+ <param name="expression">A Constraint to be applied</param>
+ <param name="actual">The actual value to test</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.That(System.Object,NUnit.Framework.Constraints.IResolveConstraint,System.String,System.Object[])">
+ <summary>
+ Apply a constraint to an actual value, succeeding if the constraint
+ is satisfied and throwing an assertion exception on failure.
+ </summary>
+ <param name="expression">A Constraint expression to be applied</param>
+ <param name="actual">The actual value to test</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.That(NUnit.Framework.Constraints.ActualValueDelegate,NUnit.Framework.Constraints.IResolveConstraint)">
+ <summary>
+ Apply a constraint to an actual value, succeeding if the constraint
+ is satisfied and throwing an assertion exception on failure.
+ </summary>
+ <param name="expr">A Constraint expression to be applied</param>
+ <param name="del">An ActualValueDelegate returning the value to be tested</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.That(NUnit.Framework.Constraints.ActualValueDelegate,NUnit.Framework.Constraints.IResolveConstraint,System.String)">
+ <summary>
+ Apply a constraint to an actual value, succeeding if the constraint
+ is satisfied and throwing an assertion exception on failure.
+ </summary>
+ <param name="expr">A Constraint expression to be applied</param>
+ <param name="del">An ActualValueDelegate returning the value to be tested</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.That(NUnit.Framework.Constraints.ActualValueDelegate,NUnit.Framework.Constraints.IResolveConstraint,System.String,System.Object[])">
+ <summary>
+ Apply a constraint to an actual value, succeeding if the constraint
+ is satisfied and throwing an assertion exception on failure.
+ </summary>
+ <param name="del">An ActualValueDelegate returning the value to be tested</param>
+ <param name="expr">A Constraint expression to be applied</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.That``1(``0@,NUnit.Framework.Constraints.IResolveConstraint)">
+ <summary>
+ Apply a constraint to a referenced value, succeeding if the constraint
+ is satisfied and throwing an assertion exception on failure.
+ </summary>
+ <param name="expression">A Constraint to be applied</param>
+ <param name="actual">The actual value to test</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.That``1(``0@,NUnit.Framework.Constraints.IResolveConstraint,System.String)">
+ <summary>
+ Apply a constraint to a referenced value, succeeding if the constraint
+ is satisfied and throwing an assertion exception on failure.
+ </summary>
+ <param name="expression">A Constraint to be applied</param>
+ <param name="actual">The actual value to test</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.That``1(``0@,NUnit.Framework.Constraints.IResolveConstraint,System.String,System.Object[])">
+ <summary>
+ Apply a constraint to a referenced value, succeeding if the constraint
+ is satisfied and throwing an assertion exception on failure.
+ </summary>
+ <param name="expression">A Constraint to be applied</param>
+ <param name="actual">The actual value to test</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.That(System.Boolean,System.String,System.Object[])">
+ <summary>
+ Asserts that a condition is true. If the condition is false the method throws
+ an <see cref="T:NUnit.Framework.AssertionException"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ <param name="message">The message to display if the condition is false</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.That(System.Boolean,System.String)">
+ <summary>
+ Asserts that a condition is true. If the condition is false the method throws
+ an <see cref="T:NUnit.Framework.AssertionException"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ <param name="message">The message to display if the condition is false</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.That(System.Boolean)">
+ <summary>
+ Asserts that a condition is true. If the condition is false the method throws
+ an <see cref="T:NUnit.Framework.AssertionException"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.That(NUnit.Framework.TestDelegate,NUnit.Framework.Constraints.IResolveConstraint)">
+ <summary>
+ Asserts that the code represented by a delegate throws an exception
+ that satisfies the constraint provided.
+ </summary>
+ <param name="code">A TestDelegate to be executed</param>
+ <param name="constraint">A ThrowsConstraint used in the test</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Throws(NUnit.Framework.Constraints.IResolveConstraint,NUnit.Framework.TestDelegate,System.String,System.Object[])">
+ <summary>
+ Verifies that a delegate throws a particular exception when called.
+ </summary>
+ <param name="expression">A constraint to be satisfied by the exception</param>
+ <param name="code">A TestSnippet delegate</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Throws(NUnit.Framework.Constraints.IResolveConstraint,NUnit.Framework.TestDelegate,System.String)">
+ <summary>
+ Verifies that a delegate throws a particular exception when called.
+ </summary>
+ <param name="expression">A constraint to be satisfied by the exception</param>
+ <param name="code">A TestSnippet delegate</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Throws(NUnit.Framework.Constraints.IResolveConstraint,NUnit.Framework.TestDelegate)">
+ <summary>
+ Verifies that a delegate throws a particular exception when called.
+ </summary>
+ <param name="expression">A constraint to be satisfied by the exception</param>
+ <param name="code">A TestSnippet delegate</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Throws(System.Type,NUnit.Framework.TestDelegate,System.String,System.Object[])">
+ <summary>
+ Verifies that a delegate throws a particular exception when called.
+ </summary>
+ <param name="expectedExceptionType">The exception Type expected</param>
+ <param name="code">A TestSnippet delegate</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Throws(System.Type,NUnit.Framework.TestDelegate,System.String)">
+ <summary>
+ Verifies that a delegate throws a particular exception when called.
+ </summary>
+ <param name="expectedExceptionType">The exception Type expected</param>
+ <param name="code">A TestSnippet delegate</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Throws(System.Type,NUnit.Framework.TestDelegate)">
+ <summary>
+ Verifies that a delegate throws a particular exception when called.
+ </summary>
+ <param name="expectedExceptionType">The exception Type expected</param>
+ <param name="code">A TestSnippet delegate</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Throws``1(NUnit.Framework.TestDelegate,System.String,System.Object[])">
+ <summary>
+ Verifies that a delegate throws a particular exception when called.
+ </summary>
+ <typeparam name="T">Type of the expected exception</typeparam>
+ <param name="code">A TestSnippet delegate</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Throws``1(NUnit.Framework.TestDelegate,System.String)">
+ <summary>
+ Verifies that a delegate throws a particular exception when called.
+ </summary>
+ <typeparam name="T">Type of the expected exception</typeparam>
+ <param name="code">A TestSnippet delegate</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Throws``1(NUnit.Framework.TestDelegate)">
+ <summary>
+ Verifies that a delegate throws a particular exception when called.
+ </summary>
+ <typeparam name="T">Type of the expected exception</typeparam>
+ <param name="code">A TestSnippet delegate</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Catch(NUnit.Framework.TestDelegate,System.String,System.Object[])">
+ <summary>
+ Verifies that a delegate throws an exception when called
+ and returns it.
+ </summary>
+ <param name="code">A TestDelegate</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Catch(NUnit.Framework.TestDelegate,System.String)">
+ <summary>
+ Verifies that a delegate throws an exception when called
+ and returns it.
+ </summary>
+ <param name="code">A TestDelegate</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Catch(NUnit.Framework.TestDelegate)">
+ <summary>
+ Verifies that a delegate throws an exception when called
+ and returns it.
+ </summary>
+ <param name="code">A TestDelegate</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Catch(System.Type,NUnit.Framework.TestDelegate,System.String,System.Object[])">
+ <summary>
+ Verifies that a delegate throws an exception of a certain Type
+ or one derived from it when called and returns it.
+ </summary>
+ <param name="expectedExceptionType">The expected Exception Type</param>
+ <param name="code">A TestDelegate</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Catch(System.Type,NUnit.Framework.TestDelegate,System.String)">
+ <summary>
+ Verifies that a delegate throws an exception of a certain Type
+ or one derived from it when called and returns it.
+ </summary>
+ <param name="expectedExceptionType">The expected Exception Type</param>
+ <param name="code">A TestDelegate</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Catch(System.Type,NUnit.Framework.TestDelegate)">
+ <summary>
+ Verifies that a delegate throws an exception of a certain Type
+ or one derived from it when called and returns it.
+ </summary>
+ <param name="expectedExceptionType">The expected Exception Type</param>
+ <param name="code">A TestDelegate</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Catch``1(NUnit.Framework.TestDelegate,System.String,System.Object[])">
+ <summary>
+ Verifies that a delegate throws an exception of a certain Type
+ or one derived from it when called and returns it.
+ </summary>
+ <typeparam name="T">The expected Exception Type</typeparam>
+ <param name="code">A TestDelegate</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Catch``1(NUnit.Framework.TestDelegate,System.String)">
+ <summary>
+ Verifies that a delegate throws an exception of a certain Type
+ or one derived from it when called and returns it.
+ </summary>
+ <typeparam name="T">The expected Exception Type</typeparam>
+ <param name="code">A TestDelegate</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Catch``1(NUnit.Framework.TestDelegate)">
+ <summary>
+ Verifies that a delegate throws an exception of a certain Type
+ or one derived from it when called and returns it.
+ </summary>
+ <typeparam name="T">The expected Exception Type</typeparam>
+ <param name="code">A TestDelegate</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.DoesNotThrow(NUnit.Framework.TestDelegate,System.String,System.Object[])">
+ <summary>
+ Verifies that a delegate does not throw an exception
+ </summary>
+ <param name="code">A TestSnippet delegate</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.DoesNotThrow(NUnit.Framework.TestDelegate,System.String)">
+ <summary>
+ Verifies that a delegate does not throw an exception.
+ </summary>
+ <param name="code">A TestSnippet delegate</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.DoesNotThrow(NUnit.Framework.TestDelegate)">
+ <summary>
+ Verifies that a delegate does not throw an exception.
+ </summary>
+ <param name="code">A TestSnippet delegate</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.True(System.Boolean,System.String,System.Object[])">
+ <summary>
+ Asserts that a condition is true. If the condition is false the method throws
+ an <see cref="T:NUnit.Framework.AssertionException"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.True(System.Boolean,System.String)">
+ <summary>
+ Asserts that a condition is true. If the condition is false the method throws
+ an <see cref="T:NUnit.Framework.AssertionException"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.True(System.Boolean)">
+ <summary>
+ Asserts that a condition is true. If the condition is false the method throws
+ an <see cref="T:NUnit.Framework.AssertionException"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsTrue(System.Boolean,System.String,System.Object[])">
+ <summary>
+ Asserts that a condition is true. If the condition is false the method throws
+ an <see cref="T:NUnit.Framework.AssertionException"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsTrue(System.Boolean,System.String)">
+ <summary>
+ Asserts that a condition is true. If the condition is false the method throws
+ an <see cref="T:NUnit.Framework.AssertionException"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsTrue(System.Boolean)">
+ <summary>
+ Asserts that a condition is true. If the condition is false the method throws
+ an <see cref="T:NUnit.Framework.AssertionException"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.False(System.Boolean,System.String,System.Object[])">
+ <summary>
+ Asserts that a condition is false. If the condition is true the method throws
+ an <see cref="T:NUnit.Framework.AssertionException"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.False(System.Boolean,System.String)">
+ <summary>
+ Asserts that a condition is false. If the condition is true the method throws
+ an <see cref="T:NUnit.Framework.AssertionException"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.False(System.Boolean)">
+ <summary>
+ Asserts that a condition is false. If the condition is true the method throws
+ an <see cref="T:NUnit.Framework.AssertionException"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsFalse(System.Boolean,System.String,System.Object[])">
+ <summary>
+ Asserts that a condition is false. If the condition is true the method throws
+ an <see cref="T:NUnit.Framework.AssertionException"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsFalse(System.Boolean,System.String)">
+ <summary>
+ Asserts that a condition is false. If the condition is true the method throws
+ an <see cref="T:NUnit.Framework.AssertionException"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsFalse(System.Boolean)">
+ <summary>
+ Asserts that a condition is false. If the condition is true the method throws
+ an <see cref="T:NUnit.Framework.AssertionException"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.NotNull(System.Object,System.String,System.Object[])">
+ <summary>
+ Verifies that the object that is passed in is not equal to <code>null</code>
+ If the object is <code>null</code> then an <see cref="T:NUnit.Framework.AssertionException"/>
+ is thrown.
+ </summary>
+ <param name="anObject">The object that is to be tested</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.NotNull(System.Object,System.String)">
+ <summary>
+ Verifies that the object that is passed in is not equal to <code>null</code>
+ If the object is <code>null</code> then an <see cref="T:NUnit.Framework.AssertionException"/>
+ is thrown.
+ </summary>
+ <param name="anObject">The object that is to be tested</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.NotNull(System.Object)">
+ <summary>
+ Verifies that the object that is passed in is not equal to <code>null</code>
+ If the object is <code>null</code> then an <see cref="T:NUnit.Framework.AssertionException"/>
+ is thrown.
+ </summary>
+ <param name="anObject">The object that is to be tested</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotNull(System.Object,System.String,System.Object[])">
+ <summary>
+ Verifies that the object that is passed in is not equal to <code>null</code>
+ If the object is <code>null</code> then an <see cref="T:NUnit.Framework.AssertionException"/>
+ is thrown.
+ </summary>
+ <param name="anObject">The object that is to be tested</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotNull(System.Object,System.String)">
+ <summary>
+ Verifies that the object that is passed in is not equal to <code>null</code>
+ If the object is <code>null</code> then an <see cref="T:NUnit.Framework.AssertionException"/>
+ is thrown.
+ </summary>
+ <param name="anObject">The object that is to be tested</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotNull(System.Object)">
+ <summary>
+ Verifies that the object that is passed in is not equal to <code>null</code>
+ If the object is <code>null</code> then an <see cref="T:NUnit.Framework.AssertionException"/>
+ is thrown.
+ </summary>
+ <param name="anObject">The object that is to be tested</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Null(System.Object,System.String,System.Object[])">
+ <summary>
+ Verifies that the object that is passed in is equal to <code>null</code>
+ If the object is not <code>null</code> then an <see cref="T:NUnit.Framework.AssertionException"/>
+ is thrown.
+ </summary>
+ <param name="anObject">The object that is to be tested</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Null(System.Object,System.String)">
+ <summary>
+ Verifies that the object that is passed in is equal to <code>null</code>
+ If the object is not <code>null</code> then an <see cref="T:NUnit.Framework.AssertionException"/>
+ is thrown.
+ </summary>
+ <param name="anObject">The object that is to be tested</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Null(System.Object)">
+ <summary>
+ Verifies that the object that is passed in is equal to <code>null</code>
+ If the object is not <code>null</code> then an <see cref="T:NUnit.Framework.AssertionException"/>
+ is thrown.
+ </summary>
+ <param name="anObject">The object that is to be tested</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNull(System.Object,System.String,System.Object[])">
+ <summary>
+ Verifies that the object that is passed in is equal to <code>null</code>
+ If the object is not <code>null</code> then an <see cref="T:NUnit.Framework.AssertionException"/>
+ is thrown.
+ </summary>
+ <param name="anObject">The object that is to be tested</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNull(System.Object,System.String)">
+ <summary>
+ Verifies that the object that is passed in is equal to <code>null</code>
+ If the object is not <code>null</code> then an <see cref="T:NUnit.Framework.AssertionException"/>
+ is thrown.
+ </summary>
+ <param name="anObject">The object that is to be tested</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNull(System.Object)">
+ <summary>
+ Verifies that the object that is passed in is equal to <code>null</code>
+ If the object is not <code>null</code> then an <see cref="T:NUnit.Framework.AssertionException"/>
+ is thrown.
+ </summary>
+ <param name="anObject">The object that is to be tested</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNaN(System.Double,System.String,System.Object[])">
+ <summary>
+ Verifies that the double that is passed in is an <code>NaN</code> value.
+ If the object is not <code>NaN</code> then an <see cref="T:NUnit.Framework.AssertionException"/>
+ is thrown.
+ </summary>
+ <param name="aDouble">The value that is to be tested</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNaN(System.Double,System.String)">
+ <summary>
+ Verifies that the double that is passed in is an <code>NaN</code> value.
+ If the object is not <code>NaN</code> then an <see cref="T:NUnit.Framework.AssertionException"/>
+ is thrown.
+ </summary>
+ <param name="aDouble">The value that is to be tested</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNaN(System.Double)">
+ <summary>
+ Verifies that the double that is passed in is an <code>NaN</code> value.
+ If the object is not <code>NaN</code> then an <see cref="T:NUnit.Framework.AssertionException"/>
+ is thrown.
+ </summary>
+ <param name="aDouble">The value that is to be tested</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNaN(System.Nullable{System.Double},System.String,System.Object[])">
+ <summary>
+ Verifies that the double that is passed in is an <code>NaN</code> value.
+ If the object is not <code>NaN</code> then an <see cref="T:NUnit.Framework.AssertionException"/>
+ is thrown.
+ </summary>
+ <param name="aDouble">The value that is to be tested</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNaN(System.Nullable{System.Double},System.String)">
+ <summary>
+ Verifies that the double that is passed in is an <code>NaN</code> value.
+ If the object is not <code>NaN</code> then an <see cref="T:NUnit.Framework.AssertionException"/>
+ is thrown.
+ </summary>
+ <param name="aDouble">The value that is to be tested</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNaN(System.Nullable{System.Double})">
+ <summary>
+ Verifies that the double that is passed in is an <code>NaN</code> value.
+ If the object is not <code>NaN</code> then an <see cref="T:NUnit.Framework.AssertionException"/>
+ is thrown.
+ </summary>
+ <param name="aDouble">The value that is to be tested</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsEmpty(System.String,System.String,System.Object[])">
+ <summary>
+ Assert that a string is empty - that is equal to string.Empty
+ </summary>
+ <param name="aString">The string to be tested</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsEmpty(System.String,System.String)">
+ <summary>
+ Assert that a string is empty - that is equal to string.Empty
+ </summary>
+ <param name="aString">The string to be tested</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsEmpty(System.String)">
+ <summary>
+ Assert that a string is empty - that is equal to string.Empty
+ </summary>
+ <param name="aString">The string to be tested</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsEmpty(System.Collections.ICollection,System.String,System.Object[])">
+ <summary>
+ Assert that an array, list or other collection is empty
+ </summary>
+ <param name="collection">An array, list or other collection implementing ICollection</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsEmpty(System.Collections.ICollection,System.String)">
+ <summary>
+ Assert that an array, list or other collection is empty
+ </summary>
+ <param name="collection">An array, list or other collection implementing ICollection</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsEmpty(System.Collections.ICollection)">
+ <summary>
+ Assert that an array, list or other collection is empty
+ </summary>
+ <param name="collection">An array, list or other collection implementing ICollection</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotEmpty(System.String,System.String,System.Object[])">
+ <summary>
+ Assert that a string is not empty - that is not equal to string.Empty
+ </summary>
+ <param name="aString">The string to be tested</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotEmpty(System.String,System.String)">
+ <summary>
+ Assert that a string is not empty - that is not equal to string.Empty
+ </summary>
+ <param name="aString">The string to be tested</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotEmpty(System.String)">
+ <summary>
+ Assert that a string is not empty - that is not equal to string.Empty
+ </summary>
+ <param name="aString">The string to be tested</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotEmpty(System.Collections.ICollection,System.String,System.Object[])">
+ <summary>
+ Assert that an array, list or other collection is not empty
+ </summary>
+ <param name="collection">An array, list or other collection implementing ICollection</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotEmpty(System.Collections.ICollection,System.String)">
+ <summary>
+ Assert that an array, list or other collection is not empty
+ </summary>
+ <param name="collection">An array, list or other collection implementing ICollection</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotEmpty(System.Collections.ICollection)">
+ <summary>
+ Assert that an array, list or other collection is not empty
+ </summary>
+ <param name="collection">An array, list or other collection implementing ICollection</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNullOrEmpty(System.String,System.String,System.Object[])">
+ <summary>
+ Assert that a string is either null or equal to string.Empty
+ </summary>
+ <param name="aString">The string to be tested</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNullOrEmpty(System.String,System.String)">
+ <summary>
+ Assert that a string is either null or equal to string.Empty
+ </summary>
+ <param name="aString">The string to be tested</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNullOrEmpty(System.String)">
+ <summary>
+ Assert that a string is either null or equal to string.Empty
+ </summary>
+ <param name="aString">The string to be tested</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotNullOrEmpty(System.String,System.String,System.Object[])">
+ <summary>
+ Assert that a string is not null or empty
+ </summary>
+ <param name="aString">The string to be tested</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotNullOrEmpty(System.String,System.String)">
+ <summary>
+ Assert that a string is not null or empty
+ </summary>
+ <param name="aString">The string to be tested</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotNullOrEmpty(System.String)">
+ <summary>
+ Assert that a string is not null or empty
+ </summary>
+ <param name="aString">The string to be tested</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsAssignableFrom(System.Type,System.Object,System.String,System.Object[])">
+ <summary>
+ Asserts that an object may be assigned a value of a given Type.
+ </summary>
+ <param name="expected">The expected Type.</param>
+ <param name="actual">The object under examination</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsAssignableFrom(System.Type,System.Object,System.String)">
+ <summary>
+ Asserts that an object may be assigned a value of a given Type.
+ </summary>
+ <param name="expected">The expected Type.</param>
+ <param name="actual">The object under examination</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsAssignableFrom(System.Type,System.Object)">
+ <summary>
+ Asserts that an object may be assigned a value of a given Type.
+ </summary>
+ <param name="expected">The expected Type.</param>
+ <param name="actual">The object under examination</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsAssignableFrom``1(System.Object,System.String,System.Object[])">
+ <summary>
+ Asserts that an object may be assigned a value of a given Type.
+ </summary>
+ <typeparam name="T">The expected Type.</typeparam>
+ <param name="actual">The object under examination</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsAssignableFrom``1(System.Object,System.String)">
+ <summary>
+ Asserts that an object may be assigned a value of a given Type.
+ </summary>
+ <typeparam name="T">The expected Type.</typeparam>
+ <param name="actual">The object under examination</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsAssignableFrom``1(System.Object)">
+ <summary>
+ Asserts that an object may be assigned a value of a given Type.
+ </summary>
+ <typeparam name="T">The expected Type.</typeparam>
+ <param name="actual">The object under examination</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotAssignableFrom(System.Type,System.Object,System.String,System.Object[])">
+ <summary>
+ Asserts that an object may not be assigned a value of a given Type.
+ </summary>
+ <param name="expected">The expected Type.</param>
+ <param name="actual">The object under examination</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotAssignableFrom(System.Type,System.Object,System.String)">
+ <summary>
+ Asserts that an object may not be assigned a value of a given Type.
+ </summary>
+ <param name="expected">The expected Type.</param>
+ <param name="actual">The object under examination</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotAssignableFrom(System.Type,System.Object)">
+ <summary>
+ Asserts that an object may not be assigned a value of a given Type.
+ </summary>
+ <param name="expected">The expected Type.</param>
+ <param name="actual">The object under examination</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotAssignableFrom``1(System.Object,System.String,System.Object[])">
+ <summary>
+ Asserts that an object may not be assigned a value of a given Type.
+ </summary>
+ <typeparam name="T">The expected Type.</typeparam>
+ <param name="actual">The object under examination</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotAssignableFrom``1(System.Object,System.String)">
+ <summary>
+ Asserts that an object may not be assigned a value of a given Type.
+ </summary>
+ <typeparam name="T">The expected Type.</typeparam>
+ <param name="actual">The object under examination</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotAssignableFrom``1(System.Object)">
+ <summary>
+ Asserts that an object may not be assigned a value of a given Type.
+ </summary>
+ <typeparam name="T">The expected Type.</typeparam>
+ <param name="actual">The object under examination</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsInstanceOf(System.Type,System.Object,System.String,System.Object[])">
+ <summary>
+ Asserts that an object is an instance of a given type.
+ </summary>
+ <param name="expected">The expected Type</param>
+ <param name="actual">The object being examined</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsInstanceOf(System.Type,System.Object,System.String)">
+ <summary>
+ Asserts that an object is an instance of a given type.
+ </summary>
+ <param name="expected">The expected Type</param>
+ <param name="actual">The object being examined</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsInstanceOf(System.Type,System.Object)">
+ <summary>
+ Asserts that an object is an instance of a given type.
+ </summary>
+ <param name="expected">The expected Type</param>
+ <param name="actual">The object being examined</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsInstanceOfType(System.Type,System.Object,System.String,System.Object[])">
+ <summary>
+ Asserts that an object is an instance of a given type.
+ </summary>
+ <param name="expected">The expected Type</param>
+ <param name="actual">The object being examined</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsInstanceOfType(System.Type,System.Object,System.String)">
+ <summary>
+ Asserts that an object is an instance of a given type.
+ </summary>
+ <param name="expected">The expected Type</param>
+ <param name="actual">The object being examined</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsInstanceOfType(System.Type,System.Object)">
+ <summary>
+ Asserts that an object is an instance of a given type.
+ </summary>
+ <param name="expected">The expected Type</param>
+ <param name="actual">The object being examined</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsInstanceOf``1(System.Object,System.String,System.Object[])">
+ <summary>
+ Asserts that an object is an instance of a given type.
+ </summary>
+ <typeparam name="T">The expected Type</typeparam>
+ <param name="actual">The object being examined</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsInstanceOf``1(System.Object,System.String)">
+ <summary>
+ Asserts that an object is an instance of a given type.
+ </summary>
+ <typeparam name="T">The expected Type</typeparam>
+ <param name="actual">The object being examined</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsInstanceOf``1(System.Object)">
+ <summary>
+ Asserts that an object is an instance of a given type.
+ </summary>
+ <typeparam name="T">The expected Type</typeparam>
+ <param name="actual">The object being examined</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotInstanceOf(System.Type,System.Object,System.String,System.Object[])">
+ <summary>
+ Asserts that an object is not an instance of a given type.
+ </summary>
+ <param name="expected">The expected Type</param>
+ <param name="actual">The object being examined</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotInstanceOf(System.Type,System.Object,System.String)">
+ <summary>
+ Asserts that an object is not an instance of a given type.
+ </summary>
+ <param name="expected">The expected Type</param>
+ <param name="actual">The object being examined</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotInstanceOf(System.Type,System.Object)">
+ <summary>
+ Asserts that an object is not an instance of a given type.
+ </summary>
+ <param name="expected">The expected Type</param>
+ <param name="actual">The object being examined</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotInstanceOfType(System.Type,System.Object,System.String,System.Object[])">
+ <summary>
+ Asserts that an object is not an instance of a given type.
+ </summary>
+ <param name="expected">The expected Type</param>
+ <param name="actual">The object being examined</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotInstanceOfType(System.Type,System.Object,System.String)">
+ <summary>
+ Asserts that an object is not an instance of a given type.
+ </summary>
+ <param name="expected">The expected Type</param>
+ <param name="actual">The object being examined</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotInstanceOfType(System.Type,System.Object)">
+ <summary>
+ Asserts that an object is not an instance of a given type.
+ </summary>
+ <param name="expected">The expected Type</param>
+ <param name="actual">The object being examined</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotInstanceOf``1(System.Object,System.String,System.Object[])">
+ <summary>
+ Asserts that an object is not an instance of a given type.
+ </summary>
+ <typeparam name="T">The expected Type</typeparam>
+ <param name="actual">The object being examined</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotInstanceOf``1(System.Object,System.String)">
+ <summary>
+ Asserts that an object is not an instance of a given type.
+ </summary>
+ <typeparam name="T">The expected Type</typeparam>
+ <param name="actual">The object being examined</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.IsNotInstanceOf``1(System.Object)">
+ <summary>
+ Asserts that an object is not an instance of a given type.
+ </summary>
+ <typeparam name="T">The expected Type</typeparam>
+ <param name="actual">The object being examined</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.Int32,System.Int32,System.String,System.Object[])">
+ <summary>
+ Verifies that two values are equal. If they are not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.Int32,System.Int32,System.String)">
+ <summary>
+ Verifies that two values are equal. If they are not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.Int32,System.Int32)">
+ <summary>
+ Verifies that two values are equal. If they are not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.Int64,System.Int64,System.String,System.Object[])">
+ <summary>
+ Verifies that two values are equal. If they are not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.Int64,System.Int64,System.String)">
+ <summary>
+ Verifies that two values are equal. If they are not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.Int64,System.Int64)">
+ <summary>
+ Verifies that two values are equal. If they are not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.UInt32,System.UInt32,System.String,System.Object[])">
+ <summary>
+ Verifies that two values are equal. If they are not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.UInt32,System.UInt32,System.String)">
+ <summary>
+ Verifies that two values are equal. If they are not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.UInt32,System.UInt32)">
+ <summary>
+ Verifies that two values are equal. If they are not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.UInt64,System.UInt64,System.String,System.Object[])">
+ <summary>
+ Verifies that two values are equal. If they are not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.UInt64,System.UInt64,System.String)">
+ <summary>
+ Verifies that two values are equal. If they are not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.UInt64,System.UInt64)">
+ <summary>
+ Verifies that two values are equal. If they are not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.Decimal,System.Decimal,System.String,System.Object[])">
+ <summary>
+ Verifies that two values are equal. If they are not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.Decimal,System.Decimal,System.String)">
+ <summary>
+ Verifies that two values are equal. If they are not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.Decimal,System.Decimal)">
+ <summary>
+ Verifies that two values are equal. If they are not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.Double,System.Double,System.Double,System.String,System.Object[])">
+ <summary>
+ Verifies that two doubles are equal considering a delta. If the
+ expected value is infinity then the delta value is ignored. If
+ they are not equal then an <see cref="T:NUnit.Framework.AssertionException"/> is
+ thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="delta">The maximum acceptable difference between the
+ the expected and the actual</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.Double,System.Double,System.Double,System.String)">
+ <summary>
+ Verifies that two doubles are equal considering a delta. If the
+ expected value is infinity then the delta value is ignored. If
+ they are not equal then an <see cref="T:NUnit.Framework.AssertionException"/> is
+ thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="delta">The maximum acceptable difference between the
+ the expected and the actual</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.Double,System.Double,System.Double)">
+ <summary>
+ Verifies that two doubles are equal considering a delta. If the
+ expected value is infinity then the delta value is ignored. If
+ they are not equal then an <see cref="T:NUnit.Framework.AssertionException"/> is
+ thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="delta">The maximum acceptable difference between the
+ the expected and the actual</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.Double,System.Nullable{System.Double},System.Double,System.String,System.Object[])">
+ <summary>
+ Verifies that two doubles are equal considering a delta. If the
+ expected value is infinity then the delta value is ignored. If
+ they are not equal then an <see cref="T:NUnit.Framework.AssertionException"/> is
+ thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="delta">The maximum acceptable difference between the
+ the expected and the actual</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.Double,System.Nullable{System.Double},System.Double,System.String)">
+ <summary>
+ Verifies that two doubles are equal considering a delta. If the
+ expected value is infinity then the delta value is ignored. If
+ they are not equal then an <see cref="T:NUnit.Framework.AssertionException"/> is
+ thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="delta">The maximum acceptable difference between the
+ the expected and the actual</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.Double,System.Nullable{System.Double},System.Double)">
+ <summary>
+ Verifies that two doubles are equal considering a delta. If the
+ expected value is infinity then the delta value is ignored. If
+ they are not equal then an <see cref="T:NUnit.Framework.AssertionException"/> is
+ thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="delta">The maximum acceptable difference between the
+ the expected and the actual</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.Object,System.Object,System.String,System.Object[])">
+ <summary>
+ Verifies that two objects are equal. Two objects are considered
+ equal if both are null, or if both have the same value. NUnit
+ has special semantics for some object types.
+ If they are not equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The value that is expected</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.Object,System.Object,System.String)">
+ <summary>
+ Verifies that two objects are equal. Two objects are considered
+ equal if both are null, or if both have the same value. NUnit
+ has special semantics for some object types.
+ If they are not equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The value that is expected</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreEqual(System.Object,System.Object)">
+ <summary>
+ Verifies that two objects are equal. Two objects are considered
+ equal if both are null, or if both have the same value. NUnit
+ has special semantics for some object types.
+ If they are not equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The value that is expected</param>
+ <param name="actual">The actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.Int32,System.Int32,System.String,System.Object[])">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.Int32,System.Int32,System.String)">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.Int32,System.Int32)">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.Int64,System.Int64,System.String,System.Object[])">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.Int64,System.Int64,System.String)">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.Int64,System.Int64)">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.UInt32,System.UInt32,System.String,System.Object[])">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.UInt32,System.UInt32,System.String)">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.UInt32,System.UInt32)">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.UInt64,System.UInt64,System.String,System.Object[])">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.UInt64,System.UInt64,System.String)">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.UInt64,System.UInt64)">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.Decimal,System.Decimal,System.String,System.Object[])">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.Decimal,System.Decimal,System.String)">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.Decimal,System.Decimal)">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.Single,System.Single,System.String,System.Object[])">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.Single,System.Single,System.String)">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.Single,System.Single)">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.Double,System.Double,System.String,System.Object[])">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.Double,System.Double,System.String)">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.Double,System.Double)">
+ <summary>
+ Verifies that two values are not equal. If they are equal, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.Object,System.Object,System.String,System.Object[])">
+ <summary>
+ Verifies that two objects are not equal. Two objects are considered
+ equal if both are null, or if both have the same value. NUnit
+ has special semantics for some object types.
+ If they are equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The value that is expected</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.Object,System.Object,System.String)">
+ <summary>
+ Verifies that two objects are not equal. Two objects are considered
+ equal if both are null, or if both have the same value. NUnit
+ has special semantics for some object types.
+ If they are equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The value that is expected</param>
+ <param name="actual">The actual value</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotEqual(System.Object,System.Object)">
+ <summary>
+ Verifies that two objects are not equal. Two objects are considered
+ equal if both are null, or if both have the same value. NUnit
+ has special semantics for some object types.
+ If they are equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The value that is expected</param>
+ <param name="actual">The actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreSame(System.Object,System.Object,System.String,System.Object[])">
+ <summary>
+ Asserts that two objects refer to the same object. If they
+ are not the same an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected object</param>
+ <param name="actual">The actual object</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreSame(System.Object,System.Object,System.String)">
+ <summary>
+ Asserts that two objects refer to the same object. If they
+ are not the same an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected object</param>
+ <param name="actual">The actual object</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreSame(System.Object,System.Object)">
+ <summary>
+ Asserts that two objects refer to the same object. If they
+ are not the same an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected object</param>
+ <param name="actual">The actual object</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotSame(System.Object,System.Object,System.String,System.Object[])">
+ <summary>
+ Asserts that two objects do not refer to the same object. If they
+ are the same an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected object</param>
+ <param name="actual">The actual object</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotSame(System.Object,System.Object,System.String)">
+ <summary>
+ Asserts that two objects do not refer to the same object. If they
+ are the same an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected object</param>
+ <param name="actual">The actual object</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.AreNotSame(System.Object,System.Object)">
+ <summary>
+ Asserts that two objects do not refer to the same object. If they
+ are the same an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected object</param>
+ <param name="actual">The actual object</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.Int32,System.Int32,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.Int32,System.Int32,System.String)">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.Int32,System.Int32)">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.UInt32,System.UInt32,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.UInt32,System.UInt32,System.String)">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.UInt32,System.UInt32)">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.Int64,System.Int64,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.Int64,System.Int64,System.String)">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.Int64,System.Int64)">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.UInt64,System.UInt64,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.UInt64,System.UInt64,System.String)">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.UInt64,System.UInt64)">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.Decimal,System.Decimal,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.Decimal,System.Decimal,System.String)">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.Decimal,System.Decimal)">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.Double,System.Double,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.Double,System.Double,System.String)">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.Double,System.Double)">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.Single,System.Single,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.Single,System.Single,System.String)">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.Single,System.Single)">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.IComparable,System.IComparable,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.IComparable,System.IComparable,System.String)">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Greater(System.IComparable,System.IComparable)">
+ <summary>
+ Verifies that the first value is greater than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.Int32,System.Int32,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.Int32,System.Int32,System.String)">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.Int32,System.Int32)">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.UInt32,System.UInt32,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.UInt32,System.UInt32,System.String)">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.UInt32,System.UInt32)">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.Int64,System.Int64,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.Int64,System.Int64,System.String)">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.Int64,System.Int64)">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.UInt64,System.UInt64,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.UInt64,System.UInt64,System.String)">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.UInt64,System.UInt64)">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.Decimal,System.Decimal,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.Decimal,System.Decimal,System.String)">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.Decimal,System.Decimal)">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.Double,System.Double,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.Double,System.Double,System.String)">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.Double,System.Double)">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.Single,System.Single,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.Single,System.Single,System.String)">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.Single,System.Single)">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.IComparable,System.IComparable,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.IComparable,System.IComparable,System.String)">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Less(System.IComparable,System.IComparable)">
+ <summary>
+ Verifies that the first value is less than the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.Int32,System.Int32,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.Int32,System.Int32,System.String)">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.Int32,System.Int32)">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.UInt32,System.UInt32,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.UInt32,System.UInt32,System.String)">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.UInt32,System.UInt32)">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.Int64,System.Int64,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.Int64,System.Int64,System.String)">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.Int64,System.Int64)">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.UInt64,System.UInt64,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.UInt64,System.UInt64,System.String)">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.UInt64,System.UInt64)">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.Decimal,System.Decimal,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.Decimal,System.Decimal,System.String)">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.Decimal,System.Decimal)">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.Double,System.Double,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.Double,System.Double,System.String)">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.Double,System.Double)">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.Single,System.Single,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.Single,System.Single,System.String)">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.Single,System.Single)">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.IComparable,System.IComparable,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.IComparable,System.IComparable,System.String)">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.GreaterOrEqual(System.IComparable,System.IComparable)">
+ <summary>
+ Verifies that the first value is greater than or equal tothe second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be greater</param>
+ <param name="arg2">The second value, expected to be less</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.Int32,System.Int32,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.Int32,System.Int32,System.String)">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.Int32,System.Int32)">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.UInt32,System.UInt32,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.UInt32,System.UInt32,System.String)">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.UInt32,System.UInt32)">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.Int64,System.Int64,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.Int64,System.Int64,System.String)">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.Int64,System.Int64)">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.UInt64,System.UInt64,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.UInt64,System.UInt64,System.String)">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.UInt64,System.UInt64)">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.Decimal,System.Decimal,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.Decimal,System.Decimal,System.String)">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.Decimal,System.Decimal)">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.Double,System.Double,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.Double,System.Double,System.String)">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.Double,System.Double)">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.Single,System.Single,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.Single,System.Single,System.String)">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.Single,System.Single)">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.IComparable,System.IComparable,System.String,System.Object[])">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.IComparable,System.IComparable,System.String)">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.LessOrEqual(System.IComparable,System.IComparable)">
+ <summary>
+ Verifies that the first value is less than or equal to the second
+ value. If it is not, then an
+ <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="arg1">The first value, expected to be less</param>
+ <param name="arg2">The second value, expected to be greater</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Contains(System.Object,System.Collections.ICollection,System.String,System.Object[])">
+ <summary>
+ Asserts that an object is contained in a list.
+ </summary>
+ <param name="expected">The expected object</param>
+ <param name="actual">The list to be examined</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Array of objects to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Contains(System.Object,System.Collections.ICollection,System.String)">
+ <summary>
+ Asserts that an object is contained in a list.
+ </summary>
+ <param name="expected">The expected object</param>
+ <param name="actual">The list to be examined</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assert.Contains(System.Object,System.Collections.ICollection)">
+ <summary>
+ Asserts that an object is contained in a list.
+ </summary>
+ <param name="expected">The expected object</param>
+ <param name="actual">The list to be examined</param>
+ </member>
+ <member name="P:NUnit.Framework.Assert.Counter">
+ <summary>
+ Gets the number of assertions executed so far and
+ resets the counter to zero.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.AssertionHelper">
+ <summary>
+ AssertionHelper is an optional base class for user tests,
+ allowing the use of shorter names for constraints and
+ asserts and avoiding conflict with the definition of
+ <see cref="T:NUnit.Framework.Is"/>, from which it inherits much of its
+ behavior, in certain mock object frameworks.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.AssertionHelper.Expect(System.Object,NUnit.Framework.Constraints.IResolveConstraint)">
+ <summary>
+ Apply a constraint to an actual value, succeeding if the constraint
+ is satisfied and throwing an assertion exception on failure. Works
+ identically to <see cref="M:NUnit.Framework.Assert.That(System.Object,NUnit.Framework.Constraints.IResolveConstraint)"/>
+ </summary>
+ <param name="constraint">A Constraint to be applied</param>
+ <param name="actual">The actual value to test</param>
+ </member>
+ <member name="M:NUnit.Framework.AssertionHelper.Expect(System.Object,NUnit.Framework.Constraints.IResolveConstraint,System.String)">
+ <summary>
+ Apply a constraint to an actual value, succeeding if the constraint
+ is satisfied and throwing an assertion exception on failure. Works
+ identically to <see cref="M:NUnit.Framework.Assert.That(System.Object,NUnit.Framework.Constraints.IResolveConstraint,System.String)"/>
+ </summary>
+ <param name="constraint">A Constraint to be applied</param>
+ <param name="actual">The actual value to test</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.AssertionHelper.Expect(System.Object,NUnit.Framework.Constraints.IResolveConstraint,System.String,System.Object[])">
+ <summary>
+ Apply a constraint to an actual value, succeeding if the constraint
+ is satisfied and throwing an assertion exception on failure. Works
+ identically to <see cref="M:NUnit.Framework.Assert.That(System.Object,NUnit.Framework.Constraints.IResolveConstraint,System.String,System.Object[])"/>
+ </summary>
+ <param name="constraint">A Constraint to be applied</param>
+ <param name="actual">The actual value to test</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.AssertionHelper.Expect(NUnit.Framework.Constraints.ActualValueDelegate,NUnit.Framework.Constraints.IResolveConstraint)">
+ <summary>
+ Apply a constraint to an actual value, succeeding if the constraint
+ is satisfied and throwing an assertion exception on failure.
+ </summary>
+ <param name="expr">A Constraint expression to be applied</param>
+ <param name="del">An ActualValueDelegate returning the value to be tested</param>
+ </member>
+ <member name="M:NUnit.Framework.AssertionHelper.Expect(NUnit.Framework.Constraints.ActualValueDelegate,NUnit.Framework.Constraints.IResolveConstraint,System.String)">
+ <summary>
+ Apply a constraint to an actual value, succeeding if the constraint
+ is satisfied and throwing an assertion exception on failure.
+ </summary>
+ <param name="expr">A Constraint expression to be applied</param>
+ <param name="del">An ActualValueDelegate returning the value to be tested</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.AssertionHelper.Expect(NUnit.Framework.Constraints.ActualValueDelegate,NUnit.Framework.Constraints.IResolveConstraint,System.String,System.Object[])">
+ <summary>
+ Apply a constraint to an actual value, succeeding if the constraint
+ is satisfied and throwing an assertion exception on failure.
+ </summary>
+ <param name="del">An ActualValueDelegate returning the value to be tested</param>
+ <param name="expr">A Constraint expression to be applied</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.AssertionHelper.Expect``1(``0@,NUnit.Framework.Constraints.IResolveConstraint)">
+ <summary>
+ Apply a constraint to a referenced value, succeeding if the constraint
+ is satisfied and throwing an assertion exception on failure.
+ </summary>
+ <param name="constraint">A Constraint to be applied</param>
+ <param name="actual">The actual value to test</param>
+ </member>
+ <member name="M:NUnit.Framework.AssertionHelper.Expect``1(``0@,NUnit.Framework.Constraints.IResolveConstraint,System.String)">
+ <summary>
+ Apply a constraint to a referenced value, succeeding if the constraint
+ is satisfied and throwing an assertion exception on failure.
+ </summary>
+ <param name="constraint">A Constraint to be applied</param>
+ <param name="actual">The actual value to test</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.AssertionHelper.Expect``1(``0@,NUnit.Framework.Constraints.IResolveConstraint,System.String,System.Object[])">
+ <summary>
+ Apply a constraint to a referenced value, succeeding if the constraint
+ is satisfied and throwing an assertion exception on failure.
+ </summary>
+ <param name="expression">A Constraint to be applied</param>
+ <param name="actual">The actual value to test</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.AssertionHelper.Expect(System.Boolean,System.String,System.Object[])">
+ <summary>
+ Asserts that a condition is true. If the condition is false the method throws
+ an <see cref="T:NUnit.Framework.AssertionException"/>. Works Identically to
+ <see cref="M:NUnit.Framework.Assert.That(System.Boolean,System.String,System.Object[])"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ <param name="message">The message to display if the condition is false</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.AssertionHelper.Expect(System.Boolean,System.String)">
+ <summary>
+ Asserts that a condition is true. If the condition is false the method throws
+ an <see cref="T:NUnit.Framework.AssertionException"/>. Works Identically to
+ <see cref="M:NUnit.Framework.Assert.That(System.Boolean,System.String)"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ <param name="message">The message to display if the condition is false</param>
+ </member>
+ <member name="M:NUnit.Framework.AssertionHelper.Expect(System.Boolean)">
+ <summary>
+ Asserts that a condition is true. If the condition is false the method throws
+ an <see cref="T:NUnit.Framework.AssertionException"/>. Works Identically to <see cref="M:NUnit.Framework.Assert.That(System.Boolean)"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ </member>
+ <member name="M:NUnit.Framework.AssertionHelper.Expect(NUnit.Framework.TestDelegate,NUnit.Framework.Constraints.IResolveConstraint)">
+ <summary>
+ Asserts that the code represented by a delegate throws an exception
+ that satisfies the constraint provided.
+ </summary>
+ <param name="code">A TestDelegate to be executed</param>
+ <param name="constraint">A ThrowsConstraint used in the test</param>
+ </member>
+ <member name="M:NUnit.Framework.AssertionHelper.Map(System.Collections.ICollection)">
+ <summary>
+ Returns a ListMapper based on a collection.
+ </summary>
+ <param name="original">The original collection</param>
+ <returns></returns>
+ </member>
+ <member name="T:NUnit.Framework.Assume">
+ <summary>
+ Provides static methods to express the assumptions
+ that must be met for a test to give a meaningful
+ result. If an assumption is not met, the test
+ should produce an inconclusive result.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Assume.Equals(System.Object,System.Object)">
+ <summary>
+ The Equals method throws an AssertionException. This is done
+ to make sure there is no mistake by calling this function.
+ </summary>
+ <param name="a"></param>
+ <param name="b"></param>
+ </member>
+ <member name="M:NUnit.Framework.Assume.ReferenceEquals(System.Object,System.Object)">
+ <summary>
+ override the default ReferenceEquals to throw an AssertionException. This
+ implementation makes sure there is no mistake in calling this function
+ as part of Assert.
+ </summary>
+ <param name="a"></param>
+ <param name="b"></param>
+ </member>
+ <member name="M:NUnit.Framework.Assume.That(System.Object,NUnit.Framework.Constraints.IResolveConstraint)">
+ <summary>
+ Apply a constraint to an actual value, succeeding if the constraint
+ is satisfied and throwing an InconclusiveException on failure.
+ </summary>
+ <param name="expression">A Constraint expression to be applied</param>
+ <param name="actual">The actual value to test</param>
+ </member>
+ <member name="M:NUnit.Framework.Assume.That(System.Object,NUnit.Framework.Constraints.IResolveConstraint,System.String)">
+ <summary>
+ Apply a constraint to an actual value, succeeding if the constraint
+ is satisfied and throwing an InconclusiveException on failure.
+ </summary>
+ <param name="expression">A Constraint expression to be applied</param>
+ <param name="actual">The actual value to test</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assume.That(System.Object,NUnit.Framework.Constraints.IResolveConstraint,System.String,System.Object[])">
+ <summary>
+ Apply a constraint to an actual value, succeeding if the constraint
+ is satisfied and throwing an InconclusiveException on failure.
+ </summary>
+ <param name="expression">A Constraint expression to be applied</param>
+ <param name="actual">The actual value to test</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assume.That(NUnit.Framework.Constraints.ActualValueDelegate,NUnit.Framework.Constraints.IResolveConstraint)">
+ <summary>
+ Apply a constraint to an actual value, succeeding if the constraint
+ is satisfied and throwing an InconclusiveException on failure.
+ </summary>
+ <param name="expr">A Constraint expression to be applied</param>
+ <param name="del">An ActualValueDelegate returning the value to be tested</param>
+ </member>
+ <member name="M:NUnit.Framework.Assume.That(NUnit.Framework.Constraints.ActualValueDelegate,NUnit.Framework.Constraints.IResolveConstraint,System.String)">
+ <summary>
+ Apply a constraint to an actual value, succeeding if the constraint
+ is satisfied and throwing an InconclusiveException on failure.
+ </summary>
+ <param name="expr">A Constraint expression to be applied</param>
+ <param name="del">An ActualValueDelegate returning the value to be tested</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assume.That(NUnit.Framework.Constraints.ActualValueDelegate,NUnit.Framework.Constraints.IResolveConstraint,System.String,System.Object[])">
+ <summary>
+ Apply a constraint to an actual value, succeeding if the constraint
+ is satisfied and throwing an InconclusiveException on failure.
+ </summary>
+ <param name="del">An ActualValueDelegate returning the value to be tested</param>
+ <param name="expr">A Constraint expression to be applied</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assume.That``1(``0@,NUnit.Framework.Constraints.IResolveConstraint)">
+ <summary>
+ Apply a constraint to a referenced value, succeeding if the constraint
+ is satisfied and throwing an InconclusiveException on failure.
+ </summary>
+ <param name="expression">A Constraint expression to be applied</param>
+ <param name="actual">The actual value to test</param>
+ </member>
+ <member name="M:NUnit.Framework.Assume.That``1(``0@,NUnit.Framework.Constraints.IResolveConstraint,System.String)">
+ <summary>
+ Apply a constraint to a referenced value, succeeding if the constraint
+ is satisfied and throwing an InconclusiveException on failure.
+ </summary>
+ <param name="expression">A Constraint expression to be applied</param>
+ <param name="actual">The actual value to test</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.Assume.That``1(``0@,NUnit.Framework.Constraints.IResolveConstraint,System.String,System.Object[])">
+ <summary>
+ Apply a constraint to a referenced value, succeeding if the constraint
+ is satisfied and throwing an InconclusiveException on failure.
+ </summary>
+ <param name="expression">A Constraint expression to be applied</param>
+ <param name="actual">The actual value to test</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assume.That(System.Boolean,System.String,System.Object[])">
+ <summary>
+ Asserts that a condition is true. If the condition is false the method throws
+ an <see cref="T:NUnit.Framework.InconclusiveException"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ <param name="message">The message to display if the condition is false</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.Assume.That(System.Boolean,System.String)">
+ <summary>
+ Asserts that a condition is true. If the condition is false the method throws
+ an <see cref="T:NUnit.Framework.InconclusiveException"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ <param name="message">The message to display if the condition is false</param>
+ </member>
+ <member name="M:NUnit.Framework.Assume.That(System.Boolean)">
+ <summary>
+ Asserts that a condition is true. If the condition is false the
+ method throws an <see cref="T:NUnit.Framework.InconclusiveException"/>.
+ </summary>
+ <param name="condition">The evaluated condition</param>
+ </member>
+ <member name="M:NUnit.Framework.Assume.That(NUnit.Framework.TestDelegate,NUnit.Framework.Constraints.IResolveConstraint)">
+ <summary>
+ Asserts that the code represented by a delegate throws an exception
+ that satisfies the constraint provided.
+ </summary>
+ <param name="code">A TestDelegate to be executed</param>
+ <param name="constraint">A ThrowsConstraint used in the test</param>
+ </member>
+ <member name="T:NUnit.Framework.CollectionAssert">
+ <summary>
+ A set of Assert methods operationg on one or more collections
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.Equals(System.Object,System.Object)">
+ <summary>
+ The Equals method throws an AssertionException. This is done
+ to make sure there is no mistake by calling this function.
+ </summary>
+ <param name="a"></param>
+ <param name="b"></param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.ReferenceEquals(System.Object,System.Object)">
+ <summary>
+ override the default ReferenceEquals to throw an AssertionException. This
+ implementation makes sure there is no mistake in calling this function
+ as part of Assert.
+ </summary>
+ <param name="a"></param>
+ <param name="b"></param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AllItemsAreInstancesOfType(System.Collections.IEnumerable,System.Type)">
+ <summary>
+ Asserts that all items contained in collection are of the type specified by expectedType.
+ </summary>
+ <param name="collection">IEnumerable containing objects to be considered</param>
+ <param name="expectedType">System.Type that all objects in collection must be instances of</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AllItemsAreInstancesOfType(System.Collections.IEnumerable,System.Type,System.String)">
+ <summary>
+ Asserts that all items contained in collection are of the type specified by expectedType.
+ </summary>
+ <param name="collection">IEnumerable containing objects to be considered</param>
+ <param name="expectedType">System.Type that all objects in collection must be instances of</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AllItemsAreInstancesOfType(System.Collections.IEnumerable,System.Type,System.String,System.Object[])">
+ <summary>
+ Asserts that all items contained in collection are of the type specified by expectedType.
+ </summary>
+ <param name="collection">IEnumerable containing objects to be considered</param>
+ <param name="expectedType">System.Type that all objects in collection must be instances of</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AllItemsAreNotNull(System.Collections.IEnumerable)">
+ <summary>
+ Asserts that all items contained in collection are not equal to null.
+ </summary>
+ <param name="collection">IEnumerable containing objects to be considered</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AllItemsAreNotNull(System.Collections.IEnumerable,System.String)">
+ <summary>
+ Asserts that all items contained in collection are not equal to null.
+ </summary>
+ <param name="collection">IEnumerable containing objects to be considered</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AllItemsAreNotNull(System.Collections.IEnumerable,System.String,System.Object[])">
+ <summary>
+ Asserts that all items contained in collection are not equal to null.
+ </summary>
+ <param name="collection">IEnumerable of objects to be considered</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AllItemsAreUnique(System.Collections.IEnumerable)">
+ <summary>
+ Ensures that every object contained in collection exists within the collection
+ once and only once.
+ </summary>
+ <param name="collection">IEnumerable of objects to be considered</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AllItemsAreUnique(System.Collections.IEnumerable,System.String)">
+ <summary>
+ Ensures that every object contained in collection exists within the collection
+ once and only once.
+ </summary>
+ <param name="collection">IEnumerable of objects to be considered</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AllItemsAreUnique(System.Collections.IEnumerable,System.String,System.Object[])">
+ <summary>
+ Ensures that every object contained in collection exists within the collection
+ once and only once.
+ </summary>
+ <param name="collection">IEnumerable of objects to be considered</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AreEqual(System.Collections.IEnumerable,System.Collections.IEnumerable)">
+ <summary>
+ Asserts that expected and actual are exactly equal. The collections must have the same count,
+ and contain the exact same objects in the same order.
+ </summary>
+ <param name="expected">The first IEnumerable of objects to be considered</param>
+ <param name="actual">The second IEnumerable of objects to be considered</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AreEqual(System.Collections.IEnumerable,System.Collections.IEnumerable,System.Collections.IComparer)">
+ <summary>
+ Asserts that expected and actual are exactly equal. The collections must have the same count,
+ and contain the exact same objects in the same order.
+ If comparer is not null then it will be used to compare the objects.
+ </summary>
+ <param name="expected">The first IEnumerable of objects to be considered</param>
+ <param name="actual">The second IEnumerable of objects to be considered</param>
+ <param name="comparer">The IComparer to use in comparing objects from each IEnumerable</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AreEqual(System.Collections.IEnumerable,System.Collections.IEnumerable,System.String)">
+ <summary>
+ Asserts that expected and actual are exactly equal. The collections must have the same count,
+ and contain the exact same objects in the same order.
+ </summary>
+ <param name="expected">The first IEnumerable of objects to be considered</param>
+ <param name="actual">The second IEnumerable of objects to be considered</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AreEqual(System.Collections.IEnumerable,System.Collections.IEnumerable,System.Collections.IComparer,System.String)">
+ <summary>
+ Asserts that expected and actual are exactly equal. The collections must have the same count,
+ and contain the exact same objects in the same order.
+ If comparer is not null then it will be used to compare the objects.
+ </summary>
+ <param name="expected">The first IEnumerable of objects to be considered</param>
+ <param name="actual">The second IEnumerable of objects to be considered</param>
+ <param name="comparer">The IComparer to use in comparing objects from each IEnumerable</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AreEqual(System.Collections.IEnumerable,System.Collections.IEnumerable,System.String,System.Object[])">
+ <summary>
+ Asserts that expected and actual are exactly equal. The collections must have the same count,
+ and contain the exact same objects in the same order.
+ </summary>
+ <param name="expected">The first IEnumerable of objects to be considered</param>
+ <param name="actual">The second IEnumerable of objects to be considered</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AreEqual(System.Collections.IEnumerable,System.Collections.IEnumerable,System.Collections.IComparer,System.String,System.Object[])">
+ <summary>
+ Asserts that expected and actual are exactly equal. The collections must have the same count,
+ and contain the exact same objects in the same order.
+ If comparer is not null then it will be used to compare the objects.
+ </summary>
+ <param name="expected">The first IEnumerable of objects to be considered</param>
+ <param name="actual">The second IEnumerable of objects to be considered</param>
+ <param name="comparer">The IComparer to use in comparing objects from each IEnumerable</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AreEquivalent(System.Collections.IEnumerable,System.Collections.IEnumerable)">
+ <summary>
+ Asserts that expected and actual are equivalent, containing the same objects but the match may be in any order.
+ </summary>
+ <param name="expected">The first IEnumerable of objects to be considered</param>
+ <param name="actual">The second IEnumerable of objects to be considered</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AreEquivalent(System.Collections.IEnumerable,System.Collections.IEnumerable,System.String)">
+ <summary>
+ Asserts that expected and actual are equivalent, containing the same objects but the match may be in any order.
+ </summary>
+ <param name="expected">The first IEnumerable of objects to be considered</param>
+ <param name="actual">The second IEnumerable of objects to be considered</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AreEquivalent(System.Collections.IEnumerable,System.Collections.IEnumerable,System.String,System.Object[])">
+ <summary>
+ Asserts that expected and actual are equivalent, containing the same objects but the match may be in any order.
+ </summary>
+ <param name="expected">The first IEnumerable of objects to be considered</param>
+ <param name="actual">The second IEnumerable of objects to be considered</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AreNotEqual(System.Collections.IEnumerable,System.Collections.IEnumerable)">
+ <summary>
+ Asserts that expected and actual are not exactly equal.
+ </summary>
+ <param name="expected">The first IEnumerable of objects to be considered</param>
+ <param name="actual">The second IEnumerable of objects to be considered</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AreNotEqual(System.Collections.IEnumerable,System.Collections.IEnumerable,System.Collections.IComparer)">
+ <summary>
+ Asserts that expected and actual are not exactly equal.
+ If comparer is not null then it will be used to compare the objects.
+ </summary>
+ <param name="expected">The first IEnumerable of objects to be considered</param>
+ <param name="actual">The second IEnumerable of objects to be considered</param>
+ <param name="comparer">The IComparer to use in comparing objects from each IEnumerable</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AreNotEqual(System.Collections.IEnumerable,System.Collections.IEnumerable,System.String)">
+ <summary>
+ Asserts that expected and actual are not exactly equal.
+ </summary>
+ <param name="expected">The first IEnumerable of objects to be considered</param>
+ <param name="actual">The second IEnumerable of objects to be considered</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AreNotEqual(System.Collections.IEnumerable,System.Collections.IEnumerable,System.Collections.IComparer,System.String)">
+ <summary>
+ Asserts that expected and actual are not exactly equal.
+ If comparer is not null then it will be used to compare the objects.
+ </summary>
+ <param name="expected">The first IEnumerable of objects to be considered</param>
+ <param name="actual">The second IEnumerable of objects to be considered</param>
+ <param name="comparer">The IComparer to use in comparing objects from each IEnumerable</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AreNotEqual(System.Collections.IEnumerable,System.Collections.IEnumerable,System.String,System.Object[])">
+ <summary>
+ Asserts that expected and actual are not exactly equal.
+ </summary>
+ <param name="expected">The first IEnumerable of objects to be considered</param>
+ <param name="actual">The second IEnumerable of objects to be considered</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AreNotEqual(System.Collections.IEnumerable,System.Collections.IEnumerable,System.Collections.IComparer,System.String,System.Object[])">
+ <summary>
+ Asserts that expected and actual are not exactly equal.
+ If comparer is not null then it will be used to compare the objects.
+ </summary>
+ <param name="expected">The first IEnumerable of objects to be considered</param>
+ <param name="actual">The second IEnumerable of objects to be considered</param>
+ <param name="comparer">The IComparer to use in comparing objects from each IEnumerable</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AreNotEquivalent(System.Collections.IEnumerable,System.Collections.IEnumerable)">
+ <summary>
+ Asserts that expected and actual are not equivalent.
+ </summary>
+ <param name="expected">The first IEnumerable of objects to be considered</param>
+ <param name="actual">The second IEnumerable of objects to be considered</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AreNotEquivalent(System.Collections.IEnumerable,System.Collections.IEnumerable,System.String)">
+ <summary>
+ Asserts that expected and actual are not equivalent.
+ </summary>
+ <param name="expected">The first IEnumerable of objects to be considered</param>
+ <param name="actual">The second IEnumerable of objects to be considered</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.AreNotEquivalent(System.Collections.IEnumerable,System.Collections.IEnumerable,System.String,System.Object[])">
+ <summary>
+ Asserts that expected and actual are not equivalent.
+ </summary>
+ <param name="expected">The first IEnumerable of objects to be considered</param>
+ <param name="actual">The second IEnumerable of objects to be considered</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.Contains(System.Collections.IEnumerable,System.Object)">
+ <summary>
+ Asserts that collection contains actual as an item.
+ </summary>
+ <param name="collection">IEnumerable of objects to be considered</param>
+ <param name="actual">Object to be found within collection</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.Contains(System.Collections.IEnumerable,System.Object,System.String)">
+ <summary>
+ Asserts that collection contains actual as an item.
+ </summary>
+ <param name="collection">IEnumerable of objects to be considered</param>
+ <param name="actual">Object to be found within collection</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.Contains(System.Collections.IEnumerable,System.Object,System.String,System.Object[])">
+ <summary>
+ Asserts that collection contains actual as an item.
+ </summary>
+ <param name="collection">IEnumerable of objects to be considered</param>
+ <param name="actual">Object to be found within collection</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.DoesNotContain(System.Collections.IEnumerable,System.Object)">
+ <summary>
+ Asserts that collection does not contain actual as an item.
+ </summary>
+ <param name="collection">IEnumerable of objects to be considered</param>
+ <param name="actual">Object that cannot exist within collection</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.DoesNotContain(System.Collections.IEnumerable,System.Object,System.String)">
+ <summary>
+ Asserts that collection does not contain actual as an item.
+ </summary>
+ <param name="collection">IEnumerable of objects to be considered</param>
+ <param name="actual">Object that cannot exist within collection</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.DoesNotContain(System.Collections.IEnumerable,System.Object,System.String,System.Object[])">
+ <summary>
+ Asserts that collection does not contain actual as an item.
+ </summary>
+ <param name="collection">IEnumerable of objects to be considered</param>
+ <param name="actual">Object that cannot exist within collection</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.IsNotSubsetOf(System.Collections.IEnumerable,System.Collections.IEnumerable)">
+ <summary>
+ Asserts that superset is not a subject of subset.
+ </summary>
+ <param name="subset">The IEnumerable superset to be considered</param>
+ <param name="superset">The IEnumerable subset to be considered</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.IsNotSubsetOf(System.Collections.IEnumerable,System.Collections.IEnumerable,System.String)">
+ <summary>
+ Asserts that superset is not a subject of subset.
+ </summary>
+ <param name="subset">The IEnumerable superset to be considered</param>
+ <param name="superset">The IEnumerable subset to be considered</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.IsNotSubsetOf(System.Collections.IEnumerable,System.Collections.IEnumerable,System.String,System.Object[])">
+ <summary>
+ Asserts that superset is not a subject of subset.
+ </summary>
+ <param name="subset">The IEnumerable superset to be considered</param>
+ <param name="superset">The IEnumerable subset to be considered</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.IsSubsetOf(System.Collections.IEnumerable,System.Collections.IEnumerable)">
+ <summary>
+ Asserts that superset is a subset of subset.
+ </summary>
+ <param name="subset">The IEnumerable superset to be considered</param>
+ <param name="superset">The IEnumerable subset to be considered</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.IsSubsetOf(System.Collections.IEnumerable,System.Collections.IEnumerable,System.String)">
+ <summary>
+ Asserts that superset is a subset of subset.
+ </summary>
+ <param name="subset">The IEnumerable superset to be considered</param>
+ <param name="superset">The IEnumerable subset to be considered</param>
+ <param name="message">The message that will be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.IsSubsetOf(System.Collections.IEnumerable,System.Collections.IEnumerable,System.String,System.Object[])">
+ <summary>
+ Asserts that superset is a subset of subset.
+ </summary>
+ <param name="subset">The IEnumerable superset to be considered</param>
+ <param name="superset">The IEnumerable subset to be considered</param>
+ <param name="message">The message that will be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.IsEmpty(System.Collections.IEnumerable,System.String,System.Object[])">
+ <summary>
+ Assert that an array, list or other collection is empty
+ </summary>
+ <param name="collection">An array, list or other collection implementing IEnumerable</param>
+ <param name="message">The message to be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.IsEmpty(System.Collections.IEnumerable,System.String)">
+ <summary>
+ Assert that an array, list or other collection is empty
+ </summary>
+ <param name="collection">An array, list or other collection implementing IEnumerable</param>
+ <param name="message">The message to be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.IsEmpty(System.Collections.IEnumerable)">
+ <summary>
+ Assert that an array,list or other collection is empty
+ </summary>
+ <param name="collection">An array, list or other collection implementing IEnumerable</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.IsNotEmpty(System.Collections.IEnumerable,System.String,System.Object[])">
+ <summary>
+ Assert that an array, list or other collection is empty
+ </summary>
+ <param name="collection">An array, list or other collection implementing IEnumerable</param>
+ <param name="message">The message to be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.IsNotEmpty(System.Collections.IEnumerable,System.String)">
+ <summary>
+ Assert that an array, list or other collection is empty
+ </summary>
+ <param name="collection">An array, list or other collection implementing IEnumerable</param>
+ <param name="message">The message to be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.IsNotEmpty(System.Collections.IEnumerable)">
+ <summary>
+ Assert that an array,list or other collection is empty
+ </summary>
+ <param name="collection">An array, list or other collection implementing IEnumerable</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.IsOrdered(System.Collections.IEnumerable,System.String,System.Object[])">
+ <summary>
+ Assert that an array, list or other collection is ordered
+ </summary>
+ <param name="collection">An array, list or other collection implementing IEnumerable</param>
+ <param name="message">The message to be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.IsOrdered(System.Collections.IEnumerable,System.String)">
+ <summary>
+ Assert that an array, list or other collection is ordered
+ </summary>
+ <param name="collection">An array, list or other collection implementing IEnumerable</param>
+ <param name="message">The message to be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.IsOrdered(System.Collections.IEnumerable)">
+ <summary>
+ Assert that an array, list or other collection is ordered
+ </summary>
+ <param name="collection">An array, list or other collection implementing IEnumerable</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.IsOrdered(System.Collections.IEnumerable,System.Collections.IComparer,System.String,System.Object[])">
+ <summary>
+ Assert that an array, list or other collection is ordered
+ </summary>
+ <param name="collection">An array, list or other collection implementing IEnumerable</param>
+ <param name="comparer">A custom comparer to perform the comparisons</param>
+ <param name="message">The message to be displayed on failure</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.IsOrdered(System.Collections.IEnumerable,System.Collections.IComparer,System.String)">
+ <summary>
+ Assert that an array, list or other collection is ordered
+ </summary>
+ <param name="collection">An array, list or other collection implementing IEnumerable</param>
+ <param name="comparer">A custom comparer to perform the comparisons</param>
+ <param name="message">The message to be displayed on failure</param>
+ </member>
+ <member name="M:NUnit.Framework.CollectionAssert.IsOrdered(System.Collections.IEnumerable,System.Collections.IComparer)">
+ <summary>
+ Assert that an array, list or other collection is ordered
+ </summary>
+ <param name="collection">An array, list or other collection implementing IEnumerable</param>
+ <param name="comparer">A custom comparer to perform the comparisons</param>
+ </member>
+ <member name="T:NUnit.Framework.Contains">
+ <summary>
+ Static helper class used in the constraint-based syntax
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Contains.Substring(System.String)">
+ <summary>
+ Creates a new SubstringConstraint
+ </summary>
+ <param name="substring">The value of the substring</param>
+ <returns>A SubstringConstraint</returns>
+ </member>
+ <member name="M:NUnit.Framework.Contains.Item(System.Object)">
+ <summary>
+ Creates a new CollectionContainsConstraint.
+ </summary>
+ <param name="item">The item that should be found.</param>
+ <returns>A new CollectionContainsConstraint</returns>
+ </member>
+ <member name="T:NUnit.Framework.DirectoryAssert">
+ <summary>
+ Summary description for DirectoryAssert
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.Equals(System.Object,System.Object)">
+ <summary>
+ The Equals method throws an AssertionException. This is done
+ to make sure there is no mistake by calling this function.
+ </summary>
+ <param name="a"></param>
+ <param name="b"></param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.ReferenceEquals(System.Object,System.Object)">
+ <summary>
+ override the default ReferenceEquals to throw an AssertionException. This
+ implementation makes sure there is no mistake in calling this function
+ as part of Assert.
+ </summary>
+ <param name="a"></param>
+ <param name="b"></param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.#ctor">
+ <summary>
+ We don't actually want any instances of this object, but some people
+ like to inherit from it to add other static methods. Hence, the
+ protected constructor disallows any instances of this object.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.AreEqual(System.IO.DirectoryInfo,System.IO.DirectoryInfo,System.String,System.Object[])">
+ <summary>
+ Verifies that two directories are equal. Two directories are considered
+ equal if both are null, or if both have the same value byte for byte.
+ If they are not equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">A directory containing the value that is expected</param>
+ <param name="actual">A directory containing the actual value</param>
+ <param name="message">The message to display if directories are not equal</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.AreEqual(System.IO.DirectoryInfo,System.IO.DirectoryInfo,System.String)">
+ <summary>
+ Verifies that two directories are equal. Two directories are considered
+ equal if both are null, or if both have the same value byte for byte.
+ If they are not equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">A directory containing the value that is expected</param>
+ <param name="actual">A directory containing the actual value</param>
+ <param name="message">The message to display if directories are not equal</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.AreEqual(System.IO.DirectoryInfo,System.IO.DirectoryInfo)">
+ <summary>
+ Verifies that two directories are equal. Two directories are considered
+ equal if both are null, or if both have the same value byte for byte.
+ If they are not equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">A directory containing the value that is expected</param>
+ <param name="actual">A directory containing the actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.AreEqual(System.String,System.String,System.String,System.Object[])">
+ <summary>
+ Verifies that two directories are equal. Two directories are considered
+ equal if both are null, or if both have the same value byte for byte.
+ If they are not equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">A directory path string containing the value that is expected</param>
+ <param name="actual">A directory path string containing the actual value</param>
+ <param name="message">The message to display if directories are not equal</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.AreEqual(System.String,System.String,System.String)">
+ <summary>
+ Verifies that two directories are equal. Two directories are considered
+ equal if both are null, or if both have the same value byte for byte.
+ If they are not equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">A directory path string containing the value that is expected</param>
+ <param name="actual">A directory path string containing the actual value</param>
+ <param name="message">The message to display if directories are not equal</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.AreEqual(System.String,System.String)">
+ <summary>
+ Verifies that two directories are equal. Two directories are considered
+ equal if both are null, or if both have the same value byte for byte.
+ If they are not equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">A directory path string containing the value that is expected</param>
+ <param name="actual">A directory path string containing the actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.AreNotEqual(System.IO.DirectoryInfo,System.IO.DirectoryInfo,System.String,System.Object[])">
+ <summary>
+ Asserts that two directories are not equal. If they are equal
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">A directory containing the value that is expected</param>
+ <param name="actual">A directory containing the actual value</param>
+ <param name="message">The message to display if directories are not equal</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.AreNotEqual(System.IO.DirectoryInfo,System.IO.DirectoryInfo,System.String)">
+ <summary>
+ Asserts that two directories are not equal. If they are equal
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">A directory containing the value that is expected</param>
+ <param name="actual">A directory containing the actual value</param>
+ <param name="message">The message to display if directories are not equal</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.AreNotEqual(System.IO.DirectoryInfo,System.IO.DirectoryInfo)">
+ <summary>
+ Asserts that two directories are not equal. If they are equal
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">A directory containing the value that is expected</param>
+ <param name="actual">A directory containing the actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.AreNotEqual(System.String,System.String,System.String,System.Object[])">
+ <summary>
+ Asserts that two directories are not equal. If they are equal
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">A directory path string containing the value that is expected</param>
+ <param name="actual">A directory path string containing the actual value</param>
+ <param name="message">The message to display if directories are equal</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.AreNotEqual(System.String,System.String,System.String)">
+ <summary>
+ Asserts that two directories are not equal. If they are equal
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">A directory path string containing the value that is expected</param>
+ <param name="actual">A directory path string containing the actual value</param>
+ <param name="message">The message to display if directories are equal</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.AreNotEqual(System.String,System.String)">
+ <summary>
+ Asserts that two directories are not equal. If they are equal
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">A directory path string containing the value that is expected</param>
+ <param name="actual">A directory path string containing the actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsEmpty(System.IO.DirectoryInfo,System.String,System.Object[])">
+ <summary>
+ Asserts that the directory is empty. If it is not empty
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ <param name="message">The message to display if directories are not equal</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsEmpty(System.IO.DirectoryInfo,System.String)">
+ <summary>
+ Asserts that the directory is empty. If it is not empty
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ <param name="message">The message to display if directories are not equal</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsEmpty(System.IO.DirectoryInfo)">
+ <summary>
+ Asserts that the directory is empty. If it is not empty
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsEmpty(System.String,System.String,System.Object[])">
+ <summary>
+ Asserts that the directory is empty. If it is not empty
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ <param name="message">The message to display if directories are not equal</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsEmpty(System.String,System.String)">
+ <summary>
+ Asserts that the directory is empty. If it is not empty
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ <param name="message">The message to display if directories are not equal</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsEmpty(System.String)">
+ <summary>
+ Asserts that the directory is empty. If it is not empty
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsNotEmpty(System.IO.DirectoryInfo,System.String,System.Object[])">
+ <summary>
+ Asserts that the directory is not empty. If it is empty
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ <param name="message">The message to display if directories are not equal</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsNotEmpty(System.IO.DirectoryInfo,System.String)">
+ <summary>
+ Asserts that the directory is not empty. If it is empty
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ <param name="message">The message to display if directories are not equal</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsNotEmpty(System.IO.DirectoryInfo)">
+ <summary>
+ Asserts that the directory is not empty. If it is empty
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsNotEmpty(System.String,System.String,System.Object[])">
+ <summary>
+ Asserts that the directory is not empty. If it is empty
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ <param name="message">The message to display if directories are not equal</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsNotEmpty(System.String,System.String)">
+ <summary>
+ Asserts that the directory is not empty. If it is empty
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ <param name="message">The message to display if directories are not equal</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsNotEmpty(System.String)">
+ <summary>
+ Asserts that the directory is not empty. If it is empty
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsWithin(System.IO.DirectoryInfo,System.IO.DirectoryInfo,System.String,System.Object[])">
+ <summary>
+ Asserts that path contains actual as a subdirectory or
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ <param name="actual">sub-directory asserted to exist under directory</param>
+ <param name="message">The message to display if directory is not within the path</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsWithin(System.IO.DirectoryInfo,System.IO.DirectoryInfo,System.String)">
+ <summary>
+ Asserts that path contains actual as a subdirectory or
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ <param name="actual">sub-directory asserted to exist under directory</param>
+ <param name="message">The message to display if directory is not within the path</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsWithin(System.IO.DirectoryInfo,System.IO.DirectoryInfo)">
+ <summary>
+ Asserts that path contains actual as a subdirectory or
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ <param name="actual">sub-directory asserted to exist under directory</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsWithin(System.String,System.String,System.String,System.Object[])">
+ <summary>
+ Asserts that path contains actual as a subdirectory or
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ <param name="actual">sub-directory asserted to exist under directory</param>
+ <param name="message">The message to display if directory is not within the path</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsWithin(System.String,System.String,System.String)">
+ <summary>
+ Asserts that path contains actual as a subdirectory or
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ <param name="actual">sub-directory asserted to exist under directory</param>
+ <param name="message">The message to display if directory is not within the path</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsWithin(System.String,System.String)">
+ <summary>
+ Asserts that path contains actual as a subdirectory or
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ <param name="actual">sub-directory asserted to exist under directory</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsNotWithin(System.IO.DirectoryInfo,System.IO.DirectoryInfo,System.String,System.Object[])">
+ <summary>
+ Asserts that path does not contain actual as a subdirectory or
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ <param name="actual">sub-directory asserted to exist under directory</param>
+ <param name="message">The message to display if directory is not within the path</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsNotWithin(System.IO.DirectoryInfo,System.IO.DirectoryInfo,System.String)">
+ <summary>
+ Asserts that path does not contain actual as a subdirectory or
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ <param name="actual">sub-directory asserted to exist under directory</param>
+ <param name="message">The message to display if directory is not within the path</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsNotWithin(System.IO.DirectoryInfo,System.IO.DirectoryInfo)">
+ <summary>
+ Asserts that path does not contain actual as a subdirectory or
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ <param name="actual">sub-directory asserted to exist under directory</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsNotWithin(System.String,System.String,System.String,System.Object[])">
+ <summary>
+ Asserts that path does not contain actual as a subdirectory or
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ <param name="actual">sub-directory asserted to exist under directory</param>
+ <param name="message">The message to display if directory is not within the path</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsNotWithin(System.String,System.String,System.String)">
+ <summary>
+ Asserts that path does not contain actual as a subdirectory or
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ <param name="actual">sub-directory asserted to exist under directory</param>
+ <param name="message">The message to display if directory is not within the path</param>
+ </member>
+ <member name="M:NUnit.Framework.DirectoryAssert.IsNotWithin(System.String,System.String)">
+ <summary>
+ Asserts that path does not contain actual as a subdirectory or
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="directory">A directory to search</param>
+ <param name="actual">sub-directory asserted to exist under directory</param>
+ </member>
+ <member name="T:NUnit.Framework.FileAssert">
+ <summary>
+ Summary description for FileAssert.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.Equals(System.Object,System.Object)">
+ <summary>
+ The Equals method throws an AssertionException. This is done
+ to make sure there is no mistake by calling this function.
+ </summary>
+ <param name="a"></param>
+ <param name="b"></param>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.ReferenceEquals(System.Object,System.Object)">
+ <summary>
+ override the default ReferenceEquals to throw an AssertionException. This
+ implementation makes sure there is no mistake in calling this function
+ as part of Assert.
+ </summary>
+ <param name="a"></param>
+ <param name="b"></param>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.#ctor">
+ <summary>
+ We don't actually want any instances of this object, but some people
+ like to inherit from it to add other static methods. Hence, the
+ protected constructor disallows any instances of this object.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.AreEqual(System.IO.Stream,System.IO.Stream,System.String,System.Object[])">
+ <summary>
+ Verifies that two Streams are equal. Two Streams are considered
+ equal if both are null, or if both have the same value byte for byte.
+ If they are not equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected Stream</param>
+ <param name="actual">The actual Stream</param>
+ <param name="message">The message to display if Streams are not equal</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.AreEqual(System.IO.Stream,System.IO.Stream,System.String)">
+ <summary>
+ Verifies that two Streams are equal. Two Streams are considered
+ equal if both are null, or if both have the same value byte for byte.
+ If they are not equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected Stream</param>
+ <param name="actual">The actual Stream</param>
+ <param name="message">The message to display if objects are not equal</param>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.AreEqual(System.IO.Stream,System.IO.Stream)">
+ <summary>
+ Verifies that two Streams are equal. Two Streams are considered
+ equal if both are null, or if both have the same value byte for byte.
+ If they are not equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected Stream</param>
+ <param name="actual">The actual Stream</param>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.AreEqual(System.IO.FileInfo,System.IO.FileInfo,System.String,System.Object[])">
+ <summary>
+ Verifies that two files are equal. Two files are considered
+ equal if both are null, or if both have the same value byte for byte.
+ If they are not equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">A file containing the value that is expected</param>
+ <param name="actual">A file containing the actual value</param>
+ <param name="message">The message to display if Streams are not equal</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.AreEqual(System.IO.FileInfo,System.IO.FileInfo,System.String)">
+ <summary>
+ Verifies that two files are equal. Two files are considered
+ equal if both are null, or if both have the same value byte for byte.
+ If they are not equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">A file containing the value that is expected</param>
+ <param name="actual">A file containing the actual value</param>
+ <param name="message">The message to display if objects are not equal</param>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.AreEqual(System.IO.FileInfo,System.IO.FileInfo)">
+ <summary>
+ Verifies that two files are equal. Two files are considered
+ equal if both are null, or if both have the same value byte for byte.
+ If they are not equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">A file containing the value that is expected</param>
+ <param name="actual">A file containing the actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.AreEqual(System.String,System.String,System.String,System.Object[])">
+ <summary>
+ Verifies that two files are equal. Two files are considered
+ equal if both are null, or if both have the same value byte for byte.
+ If they are not equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The path to a file containing the value that is expected</param>
+ <param name="actual">The path to a file containing the actual value</param>
+ <param name="message">The message to display if Streams are not equal</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.AreEqual(System.String,System.String,System.String)">
+ <summary>
+ Verifies that two files are equal. Two files are considered
+ equal if both are null, or if both have the same value byte for byte.
+ If they are not equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The path to a file containing the value that is expected</param>
+ <param name="actual">The path to a file containing the actual value</param>
+ <param name="message">The message to display if objects are not equal</param>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.AreEqual(System.String,System.String)">
+ <summary>
+ Verifies that two files are equal. Two files are considered
+ equal if both are null, or if both have the same value byte for byte.
+ If they are not equal an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The path to a file containing the value that is expected</param>
+ <param name="actual">The path to a file containing the actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.AreNotEqual(System.IO.Stream,System.IO.Stream,System.String,System.Object[])">
+ <summary>
+ Asserts that two Streams are not equal. If they are equal
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected Stream</param>
+ <param name="actual">The actual Stream</param>
+ <param name="message">The message to be displayed when the two Stream are the same.</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.AreNotEqual(System.IO.Stream,System.IO.Stream,System.String)">
+ <summary>
+ Asserts that two Streams are not equal. If they are equal
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected Stream</param>
+ <param name="actual">The actual Stream</param>
+ <param name="message">The message to be displayed when the Streams are the same.</param>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.AreNotEqual(System.IO.Stream,System.IO.Stream)">
+ <summary>
+ Asserts that two Streams are not equal. If they are equal
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The expected Stream</param>
+ <param name="actual">The actual Stream</param>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.AreNotEqual(System.IO.FileInfo,System.IO.FileInfo,System.String,System.Object[])">
+ <summary>
+ Asserts that two files are not equal. If they are equal
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">A file containing the value that is expected</param>
+ <param name="actual">A file containing the actual value</param>
+ <param name="message">The message to display if Streams are not equal</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.AreNotEqual(System.IO.FileInfo,System.IO.FileInfo,System.String)">
+ <summary>
+ Asserts that two files are not equal. If they are equal
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">A file containing the value that is expected</param>
+ <param name="actual">A file containing the actual value</param>
+ <param name="message">The message to display if objects are not equal</param>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.AreNotEqual(System.IO.FileInfo,System.IO.FileInfo)">
+ <summary>
+ Asserts that two files are not equal. If they are equal
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">A file containing the value that is expected</param>
+ <param name="actual">A file containing the actual value</param>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.AreNotEqual(System.String,System.String,System.String,System.Object[])">
+ <summary>
+ Asserts that two files are not equal. If they are equal
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The path to a file containing the value that is expected</param>
+ <param name="actual">The path to a file containing the actual value</param>
+ <param name="message">The message to display if Streams are not equal</param>
+ <param name="args">Arguments to be used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.AreNotEqual(System.String,System.String,System.String)">
+ <summary>
+ Asserts that two files are not equal. If they are equal
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The path to a file containing the value that is expected</param>
+ <param name="actual">The path to a file containing the actual value</param>
+ <param name="message">The message to display if objects are not equal</param>
+ </member>
+ <member name="M:NUnit.Framework.FileAssert.AreNotEqual(System.String,System.String)">
+ <summary>
+ Asserts that two files are not equal. If they are equal
+ an <see cref="T:NUnit.Framework.AssertionException"/> is thrown.
+ </summary>
+ <param name="expected">The path to a file containing the value that is expected</param>
+ <param name="actual">The path to a file containing the actual value</param>
+ </member>
+ <member name="T:NUnit.Framework.GlobalSettings">
+ <summary>
+ GlobalSettings is a place for setting default values used
+ by the framework in performing asserts.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.GlobalSettings.DefaultFloatingPointTolerance">
+ <summary>
+ Default tolerance for floating point equality
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Has">
+ <summary>
+ Helper class with properties and methods that supply
+ a number of constraints used in Asserts.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Has.Property(System.String)">
+ <summary>
+ Returns a new PropertyConstraintExpression, which will either
+ test for the existence of the named property on the object
+ being tested or apply any following constraint to that property.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Has.Attribute(System.Type)">
+ <summary>
+ Returns a new AttributeConstraint checking for the
+ presence of a particular attribute on an object.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Has.Attribute``1">
+ <summary>
+ Returns a new AttributeConstraint checking for the
+ presence of a particular attribute on an object.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Has.Member(System.Object)">
+ <summary>
+ Returns a new CollectionContainsConstraint checking for the
+ presence of a particular object in the collection.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Has.No">
+ <summary>
+ Returns a ConstraintExpression that negates any
+ following constraint.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Has.All">
+ <summary>
+ Returns a ConstraintExpression, which will apply
+ the following constraint to all members of a collection,
+ succeeding if all of them succeed.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Has.Some">
+ <summary>
+ Returns a ConstraintExpression, which will apply
+ the following constraint to all members of a collection,
+ succeeding if at least one of them succeeds.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Has.None">
+ <summary>
+ Returns a ConstraintExpression, which will apply
+ the following constraint to all members of a collection,
+ succeeding if all of them fail.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Has.Length">
+ <summary>
+ Returns a new ConstraintExpression, which will apply the following
+ constraint to the Length property of the object being tested.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Has.Count">
+ <summary>
+ Returns a new ConstraintExpression, which will apply the following
+ constraint to the Count property of the object being tested.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Has.Message">
+ <summary>
+ Returns a new ConstraintExpression, which will apply the following
+ constraint to the Message property of the object being tested.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Has.InnerException">
+ <summary>
+ Returns a new ConstraintExpression, which will apply the following
+ constraint to the InnerException property of the object being tested.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.IExpectException">
+ <summary>
+ Interface implemented by a user fixture in order to
+ validate any expected exceptions. It is only called
+ for test methods marked with the ExpectedException
+ attribute.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.IExpectException.HandleException(System.Exception)">
+ <summary>
+ Method to handle an expected exception
+ </summary>
+ <param name="ex">The exception to be handled</param>
+ </member>
+ <member name="T:NUnit.Framework.Is">
+ <summary>
+ Helper class with properties and methods that supply
+ a number of constraints used in Asserts.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.EqualTo(System.Object)">
+ <summary>
+ Returns a constraint that tests two items for equality
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.SameAs(System.Object)">
+ <summary>
+ Returns a constraint that tests that two references are the same object
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.GreaterThan(System.Object)">
+ <summary>
+ Returns a constraint that tests whether the
+ actual value is greater than the suppled argument
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.GreaterThanOrEqualTo(System.Object)">
+ <summary>
+ Returns a constraint that tests whether the
+ actual value is greater than or equal to the suppled argument
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.AtLeast(System.Object)">
+ <summary>
+ Returns a constraint that tests whether the
+ actual value is greater than or equal to the suppled argument
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.LessThan(System.Object)">
+ <summary>
+ Returns a constraint that tests whether the
+ actual value is less than the suppled argument
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.LessThanOrEqualTo(System.Object)">
+ <summary>
+ Returns a constraint that tests whether the
+ actual value is less than or equal to the suppled argument
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.AtMost(System.Object)">
+ <summary>
+ Returns a constraint that tests whether the
+ actual value is less than or equal to the suppled argument
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.TypeOf(System.Type)">
+ <summary>
+ Returns a constraint that tests whether the actual
+ value is of the exact type supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.TypeOf``1">
+ <summary>
+ Returns a constraint that tests whether the actual
+ value is of the exact type supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.InstanceOf(System.Type)">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is of the type supplied as an argument or a derived type.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.InstanceOf``1">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is of the type supplied as an argument or a derived type.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.InstanceOfType(System.Type)">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is of the type supplied as an argument or a derived type.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.InstanceOfType``1">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is of the type supplied as an argument or a derived type.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.AssignableFrom(System.Type)">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is assignable from the type supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.AssignableFrom``1">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is assignable from the type supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.AssignableTo(System.Type)">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is assignable from the type supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.AssignableTo``1">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is assignable from the type supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.EquivalentTo(System.Collections.IEnumerable)">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is a collection containing the same elements as the
+ collection supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.SubsetOf(System.Collections.IEnumerable)">
+ <summary>
+ Returns a constraint that tests whether the actual value
+ is a subset of the collection supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.StringContaining(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value contains the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.StringStarting(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value starts with the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.StringEnding(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value ends with the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.StringMatching(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value matches the Regex pattern supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.SamePath(System.String)">
+ <summary>
+ Returns a constraint that tests whether the path provided
+ is the same as an expected path after canonicalization.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.SubPath(System.String)">
+ <summary>
+ Returns a constraint that tests whether the path provided
+ is the same path or under an expected path after canonicalization.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.SamePathOrUnder(System.String)">
+ <summary>
+ Returns a constraint that tests whether the path provided
+ is the same path or under an expected path after canonicalization.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Is.InRange(System.IComparable,System.IComparable)">
+ <summary>
+ Returns a constraint that tests whether the actual value falls
+ within a specified range.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Is.Not">
+ <summary>
+ Returns a ConstraintExpression that negates any
+ following constraint.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Is.All">
+ <summary>
+ Returns a ConstraintExpression, which will apply
+ the following constraint to all members of a collection,
+ succeeding if all of them succeed.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Is.Null">
+ <summary>
+ Returns a constraint that tests for null
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Is.True">
+ <summary>
+ Returns a constraint that tests for True
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Is.False">
+ <summary>
+ Returns a constraint that tests for False
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Is.NaN">
+ <summary>
+ Returns a constraint that tests for NaN
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Is.Empty">
+ <summary>
+ Returns a constraint that tests for empty
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Is.Unique">
+ <summary>
+ Returns a constraint that tests whether a collection
+ contains all unique items.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Is.BinarySerializable">
+ <summary>
+ Returns a constraint that tests whether an object graph is serializable in binary format.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Is.XmlSerializable">
+ <summary>
+ Returns a constraint that tests whether an object graph is serializable in xml format.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Is.Ordered">
+ <summary>
+ Returns a constraint that tests whether a collection is ordered
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Iz">
+ <summary>
+ The Iz class is a synonym for Is intended for use in VB,
+ which regards Is as a keyword.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.List">
+ <summary>
+ The List class is a helper class with properties and methods
+ that supply a number of constraints used with lists and collections.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.List.Map(System.Collections.ICollection)">
+ <summary>
+ List.Map returns a ListMapper, which can be used to map
+ the original collection to another collection.
+ </summary>
+ <param name="actual"></param>
+ <returns></returns>
+ </member>
+ <member name="T:NUnit.Framework.ListMapper">
+ <summary>
+ ListMapper is used to transform a collection used as an actual argument
+ producing another collection to be used in the assertion.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.ListMapper.#ctor(System.Collections.ICollection)">
+ <summary>
+ Construct a ListMapper based on a collection
+ </summary>
+ <param name="original">The collection to be transformed</param>
+ </member>
+ <member name="M:NUnit.Framework.ListMapper.Property(System.String)">
+ <summary>
+ Produces a collection containing all the values of a property
+ </summary>
+ <param name="name">The collection of property values</param>
+ <returns></returns>
+ </member>
+ <member name="T:NUnit.Framework.Randomizer">
+ <summary>
+ Randomizer returns a set of random values in a repeatable
+ way, to allow re-running of tests if necessary.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Randomizer.GetRandomizer(System.Reflection.MemberInfo)">
+ <summary>
+ Get a randomizer for a particular member, returning
+ one that has already been created if it exists.
+ This ensures that the same values are generated
+ each time the tests are reloaded.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Randomizer.GetRandomizer(System.Reflection.ParameterInfo)">
+ <summary>
+ Get a randomizer for a particular parameter, returning
+ one that has already been created if it exists.
+ This ensures that the same values are generated
+ each time the tests are reloaded.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Randomizer.#ctor">
+ <summary>
+ Construct a randomizer using a random seed
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Randomizer.#ctor(System.Int32)">
+ <summary>
+ Construct a randomizer using a specified seed
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Randomizer.GetDoubles(System.Int32)">
+ <summary>
+ Return an array of random doubles between 0.0 and 1.0.
+ </summary>
+ <param name="count"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.Randomizer.GetDoubles(System.Double,System.Double,System.Int32)">
+ <summary>
+ Return an array of random doubles with values in a specified range.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Randomizer.GetInts(System.Int32,System.Int32,System.Int32)">
+ <summary>
+ Return an array of random ints with values in a specified range.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Randomizer.RandomSeed">
+ <summary>
+ Get a random seed for use in creating a randomizer.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.SpecialValue">
+ <summary>
+ The SpecialValue enum is used to represent TestCase arguments
+ that cannot be used as arguments to an Attribute.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.SpecialValue.Null">
+ <summary>
+ Null represents a null value, which cannot be used as an
+ argument to an attriute under .NET 1.x
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.StringAssert">
+ <summary>
+ Basic Asserts on strings.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.Equals(System.Object,System.Object)">
+ <summary>
+ The Equals method throws an AssertionException. This is done
+ to make sure there is no mistake by calling this function.
+ </summary>
+ <param name="a"></param>
+ <param name="b"></param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.ReferenceEquals(System.Object,System.Object)">
+ <summary>
+ override the default ReferenceEquals to throw an AssertionException. This
+ implementation makes sure there is no mistake in calling this function
+ as part of Assert.
+ </summary>
+ <param name="a"></param>
+ <param name="b"></param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.Contains(System.String,System.String,System.String,System.Object[])">
+ <summary>
+ Asserts that a string is found within another string.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The string to be examined</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Arguments used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.Contains(System.String,System.String,System.String)">
+ <summary>
+ Asserts that a string is found within another string.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The string to be examined</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.Contains(System.String,System.String)">
+ <summary>
+ Asserts that a string is found within another string.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The string to be examined</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.DoesNotContain(System.String,System.String,System.String,System.Object[])">
+ <summary>
+ Asserts that a string is not found within another string.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The string to be examined</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Arguments used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.DoesNotContain(System.String,System.String,System.String)">
+ <summary>
+ Asserts that a string is found within another string.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The string to be examined</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.DoesNotContain(System.String,System.String)">
+ <summary>
+ Asserts that a string is found within another string.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The string to be examined</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.StartsWith(System.String,System.String,System.String,System.Object[])">
+ <summary>
+ Asserts that a string starts with another string.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The string to be examined</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Arguments used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.StartsWith(System.String,System.String,System.String)">
+ <summary>
+ Asserts that a string starts with another string.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The string to be examined</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.StartsWith(System.String,System.String)">
+ <summary>
+ Asserts that a string starts with another string.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The string to be examined</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.DoesNotStartWith(System.String,System.String,System.String,System.Object[])">
+ <summary>
+ Asserts that a string does not start with another string.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The string to be examined</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Arguments used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.DoesNotStartWith(System.String,System.String,System.String)">
+ <summary>
+ Asserts that a string does not start with another string.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The string to be examined</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.DoesNotStartWith(System.String,System.String)">
+ <summary>
+ Asserts that a string does not start with another string.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The string to be examined</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.EndsWith(System.String,System.String,System.String,System.Object[])">
+ <summary>
+ Asserts that a string ends with another string.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The string to be examined</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Arguments used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.EndsWith(System.String,System.String,System.String)">
+ <summary>
+ Asserts that a string ends with another string.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The string to be examined</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.EndsWith(System.String,System.String)">
+ <summary>
+ Asserts that a string ends with another string.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The string to be examined</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.DoesNotEndWith(System.String,System.String,System.String,System.Object[])">
+ <summary>
+ Asserts that a string does not end with another string.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The string to be examined</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Arguments used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.DoesNotEndWith(System.String,System.String,System.String)">
+ <summary>
+ Asserts that a string does not end with another string.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The string to be examined</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.DoesNotEndWith(System.String,System.String)">
+ <summary>
+ Asserts that a string does not end with another string.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The string to be examined</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.AreEqualIgnoringCase(System.String,System.String,System.String,System.Object[])">
+ <summary>
+ Asserts that two strings are equal, without regard to case.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The actual string</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Arguments used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.AreEqualIgnoringCase(System.String,System.String,System.String)">
+ <summary>
+ Asserts that two strings are equal, without regard to case.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The actual string</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.AreEqualIgnoringCase(System.String,System.String)">
+ <summary>
+ Asserts that two strings are equal, without regard to case.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The actual string</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.AreNotEqualIgnoringCase(System.String,System.String,System.String,System.Object[])">
+ <summary>
+ Asserts that two strings are not equal, without regard to case.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The actual string</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Arguments used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.AreNotEqualIgnoringCase(System.String,System.String,System.String)">
+ <summary>
+ Asserts that two strings are Notequal, without regard to case.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The actual string</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.AreNotEqualIgnoringCase(System.String,System.String)">
+ <summary>
+ Asserts that two strings are not equal, without regard to case.
+ </summary>
+ <param name="expected">The expected string</param>
+ <param name="actual">The actual string</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.IsMatch(System.String,System.String,System.String,System.Object[])">
+ <summary>
+ Asserts that a string matches an expected regular expression pattern.
+ </summary>
+ <param name="pattern">The regex pattern to be matched</param>
+ <param name="actual">The actual string</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Arguments used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.IsMatch(System.String,System.String,System.String)">
+ <summary>
+ Asserts that a string matches an expected regular expression pattern.
+ </summary>
+ <param name="pattern">The regex pattern to be matched</param>
+ <param name="actual">The actual string</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.IsMatch(System.String,System.String)">
+ <summary>
+ Asserts that a string matches an expected regular expression pattern.
+ </summary>
+ <param name="pattern">The regex pattern to be matched</param>
+ <param name="actual">The actual string</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.DoesNotMatch(System.String,System.String,System.String,System.Object[])">
+ <summary>
+ Asserts that a string does not match an expected regular expression pattern.
+ </summary>
+ <param name="pattern">The regex pattern to be used</param>
+ <param name="actual">The actual string</param>
+ <param name="message">The message to display in case of failure</param>
+ <param name="args">Arguments used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.DoesNotMatch(System.String,System.String,System.String)">
+ <summary>
+ Asserts that a string does not match an expected regular expression pattern.
+ </summary>
+ <param name="pattern">The regex pattern to be used</param>
+ <param name="actual">The actual string</param>
+ <param name="message">The message to display in case of failure</param>
+ </member>
+ <member name="M:NUnit.Framework.StringAssert.DoesNotMatch(System.String,System.String)">
+ <summary>
+ Asserts that a string does not match an expected regular expression pattern.
+ </summary>
+ <param name="pattern">The regex pattern to be used</param>
+ <param name="actual">The actual string</param>
+ </member>
+ <member name="T:NUnit.Framework.TestCaseData">
+ <summary>
+ The TestCaseData class represents a set of arguments
+ and other parameter info to be used for a parameterized
+ test case. It provides a number of instance modifiers
+ for use in initializing the test case.
+
+ Note: Instance modifiers are getters that return
+ the same instance after modifying it's state.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestCaseData.arguments">
+ <summary>
+ The argument list to be provided to the test
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestCaseData.result">
+ <summary>
+ The expected result to be returned
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestCaseData.expectedExceptionType">
+ <summary>
+ The expected exception Type
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestCaseData.expectedExceptionName">
+ <summary>
+ The FullName of the expected exception
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestCaseData.testName">
+ <summary>
+ The name to be used for the test
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestCaseData.description">
+ <summary>
+ The description of the test
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestCaseData.properties">
+ <summary>
+ A dictionary of properties, used to add information
+ to tests without requiring the class to change.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestCaseData.isIgnored">
+ <summary>
+ If true, indicates that the test case is to be ignored
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestCaseData.ignoreReason">
+ <summary>
+ The reason for ignoring a test case
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseData.#ctor(System.Object[])">
+ <summary>
+ Initializes a new instance of the <see cref="T:TestCaseData"/> class.
+ </summary>
+ <param name="args">The arguments.</param>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseData.#ctor(System.Object)">
+ <summary>
+ Initializes a new instance of the <see cref="T:TestCaseData"/> class.
+ </summary>
+ <param name="arg">The argument.</param>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseData.#ctor(System.Object,System.Object)">
+ <summary>
+ Initializes a new instance of the <see cref="T:TestCaseData"/> class.
+ </summary>
+ <param name="arg1">The first argument.</param>
+ <param name="arg2">The second argument.</param>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseData.#ctor(System.Object,System.Object,System.Object)">
+ <summary>
+ Initializes a new instance of the <see cref="T:TestCaseData"/> class.
+ </summary>
+ <param name="arg1">The first argument.</param>
+ <param name="arg2">The second argument.</param>
+ <param name="arg3">The third argument.</param>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseData.Returns(System.Object)">
+ <summary>
+ Sets the expected result for the test
+ </summary>
+ <param name="result">The expected result</param>
+ <returns>A modified TestCaseData</returns>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseData.Throws(System.Type)">
+ <summary>
+ Sets the expected exception type for the test
+ </summary>
+ <param name="exceptionType">Type of the expected exception.</param>
+ <returns>The modified TestCaseData instance</returns>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseData.Throws(System.String)">
+ <summary>
+ Sets the expected exception type for the test
+ </summary>
+ <param name="exceptionName">FullName of the expected exception.</param>
+ <returns>The modified TestCaseData instance</returns>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseData.SetName(System.String)">
+ <summary>
+ Sets the name of the test case
+ </summary>
+ <returns>The modified TestCaseData instance</returns>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseData.SetDescription(System.String)">
+ <summary>
+ Sets the description for the test case
+ being constructed.
+ </summary>
+ <param name="description">The description.</param>
+ <returns>The modified TestCaseData instance.</returns>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseData.SetCategory(System.String)">
+ <summary>
+ Applies a category to the test
+ </summary>
+ <param name="category"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseData.SetProperty(System.String,System.String)">
+ <summary>
+ Applies a named property to the test
+ </summary>
+ <param name="propName"></param>
+ <param name="propValue"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseData.SetProperty(System.String,System.Int32)">
+ <summary>
+ Applies a named property to the test
+ </summary>
+ <param name="propName"></param>
+ <param name="propValue"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseData.SetProperty(System.String,System.Double)">
+ <summary>
+ Applies a named property to the test
+ </summary>
+ <param name="propName"></param>
+ <param name="propValue"></param>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseData.Ignore">
+ <summary>
+ Ignores this TestCase.
+ </summary>
+ <returns></returns>
+ </member>
+ <member name="M:NUnit.Framework.TestCaseData.Ignore(System.String)">
+ <summary>
+ Ignores this TestCase, specifying the reason.
+ </summary>
+ <param name="reason">The reason.</param>
+ <returns></returns>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseData.Arguments">
+ <summary>
+ Gets the argument list to be provided to the test
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseData.Result">
+ <summary>
+ Gets the expected result
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseData.ExpectedException">
+ <summary>
+ Gets the expected exception Type
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseData.ExpectedExceptionName">
+ <summary>
+ Gets the FullName of the expected exception
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseData.TestName">
+ <summary>
+ Gets the name to be used for the test
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseData.Description">
+ <summary>
+ Gets the description of the test
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseData.Ignored">
+ <summary>
+ Gets a value indicating whether this <see cref="T:NUnit.Framework.ITestCaseData"/> is ignored.
+ </summary>
+ <value><c>true</c> if ignored; otherwise, <c>false</c>.</value>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseData.IgnoreReason">
+ <summary>
+ Gets the ignore reason.
+ </summary>
+ <value>The ignore reason.</value>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseData.Categories">
+ <summary>
+ Gets a list of categories associated with this test.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestCaseData.Properties">
+ <summary>
+ Gets the property dictionary for this test
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.TestContext">
+ <summary>
+ Provide the context information of the current test
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.TestContext.#ctor(System.Collections.IDictionary)">
+ <summary>
+ Constructs a TestContext using the provided context dictionary
+ </summary>
+ <param name="context">A context dictionary</param>
+ </member>
+ <member name="P:NUnit.Framework.TestContext.CurrentContext">
+ <summary>
+ Get the current test context. This is created
+ as needed. The user may save the context for
+ use within a test, but it should not be used
+ outside the test for which it is created.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestContext.Test">
+ <summary>
+ Gets a TestAdapter representing the currently executing test in this context.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestContext.Result">
+ <summary>
+ Gets a ResultAdapter representing the current result for the test
+ executing in this context.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestContext.TestDirectory">
+ <summary>
+ Gets the current directory for this TestContext
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.TestContext.TestAdapter">
+ <summary>
+ TestAdapter adapts a Test for consumption by
+ the user test code.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.TestContext.TestAdapter.#ctor(System.Collections.IDictionary)">
+ <summary>
+ Constructs a TestAdapter for this context
+ </summary>
+ <param name="context">The context dictionary</param>
+ </member>
+ <member name="P:NUnit.Framework.TestContext.TestAdapter.Name">
+ <summary>
+ The name of the test.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestContext.TestAdapter.FullName">
+ <summary>
+ The FullName of the test
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestContext.TestAdapter.Properties">
+ <summary>
+ The properties of the test.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.TestContext.ResultAdapter">
+ <summary>
+ ResultAdapter adapts a TestResult for consumption by
+ the user test code.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.TestContext.ResultAdapter.#ctor(System.Collections.IDictionary)">
+ <summary>
+ Construct a ResultAdapter for a context
+ </summary>
+ <param name="context">The context holding the result</param>
+ </member>
+ <member name="P:NUnit.Framework.TestContext.ResultAdapter.State">
+ <summary>
+ The TestState of current test. This maps to the ResultState
+ used in nunit.core and is subject to change in the future.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.TestContext.ResultAdapter.Status">
+ <summary>
+ The TestStatus of current test. This enum will be used
+ in future versions of NUnit and so is to be preferred
+ to the TestState value.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.TestState">
+ <summary>
+ The ResultState enum indicates the result of running a test
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestState.Inconclusive">
+ <summary>
+ The result is inconclusive
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestState.NotRunnable">
+ <summary>
+ The test was not runnable.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestState.Skipped">
+ <summary>
+ The test has been skipped.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestState.Ignored">
+ <summary>
+ The test has been ignored.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestState.Success">
+ <summary>
+ The test succeeded
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestState.Failure">
+ <summary>
+ The test failed
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestState.Error">
+ <summary>
+ The test encountered an unexpected exception
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestState.Cancelled">
+ <summary>
+ The test was cancelled by the user
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.TestStatus">
+ <summary>
+ The TestStatus enum indicates the result of running a test
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestStatus.Inconclusive">
+ <summary>
+ The test was inconclusive
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestStatus.Skipped">
+ <summary>
+ The test has skipped
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestStatus.Passed">
+ <summary>
+ The test succeeded
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TestStatus.Failed">
+ <summary>
+ The test failed
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Text">
+ <summary>
+ Helper class with static methods used to supply constraints
+ that operate on strings.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Text.Contains(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value contains the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Text.DoesNotContain(System.String)">
+ <summary>
+ Returns a constraint that fails if the actual
+ value contains the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Text.StartsWith(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value starts with the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Text.DoesNotStartWith(System.String)">
+ <summary>
+ Returns a constraint that fails if the actual
+ value starts with the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Text.EndsWith(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value ends with the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Text.DoesNotEndWith(System.String)">
+ <summary>
+ Returns a constraint that fails if the actual
+ value ends with the substring supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Text.Matches(System.String)">
+ <summary>
+ Returns a constraint that succeeds if the actual
+ value matches the Regex pattern supplied as an argument.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Text.DoesNotMatch(System.String)">
+ <summary>
+ Returns a constraint that fails if the actual
+ value matches the pattern supplied as an argument.
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Text.All">
+ <summary>
+ Returns a ConstraintExpression, which will apply
+ the following constraint to all members of a collection,
+ succeeding if all of them succeed.
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.TextMessageWriter">
+ <summary>
+ TextMessageWriter writes constraint descriptions and messages
+ in displayable form as a text stream. It tailors the display
+ of individual message components to form the standard message
+ format of NUnit assertion failure messages.
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TextMessageWriter.Pfx_Expected">
+ <summary>
+ Prefix used for the expected value line of a message
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TextMessageWriter.Pfx_Actual">
+ <summary>
+ Prefix used for the actual value line of a message
+ </summary>
+ </member>
+ <member name="F:NUnit.Framework.TextMessageWriter.PrefixLength">
+ <summary>
+ Length of a message prefix
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.TextMessageWriter.#ctor">
+ <summary>
+ Construct a TextMessageWriter
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.TextMessageWriter.#ctor(System.String,System.Object[])">
+ <summary>
+ Construct a TextMessageWriter, specifying a user message
+ and optional formatting arguments.
+ </summary>
+ <param name="userMessage"></param>
+ <param name="args"></param>
+ </member>
+ <member name="M:NUnit.Framework.TextMessageWriter.WriteMessageLine(System.Int32,System.String,System.Object[])">
+ <summary>
+ Method to write single line message with optional args, usually
+ written to precede the general failure message, at a givel
+ indentation level.
+ </summary>
+ <param name="level">The indentation level of the message</param>
+ <param name="message">The message to be written</param>
+ <param name="args">Any arguments used in formatting the message</param>
+ </member>
+ <member name="M:NUnit.Framework.TextMessageWriter.DisplayDifferences(NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Display Expected and Actual lines for a constraint. This
+ is called by MessageWriter's default implementation of
+ WriteMessageTo and provides the generic two-line display.
+ </summary>
+ <param name="constraint">The constraint that failed</param>
+ </member>
+ <member name="M:NUnit.Framework.TextMessageWriter.DisplayDifferences(System.Object,System.Object)">
+ <summary>
+ Display Expected and Actual lines for given values. This
+ method may be called by constraints that need more control over
+ the display of actual and expected values than is provided
+ by the default implementation.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value causing the failure</param>
+ </member>
+ <member name="M:NUnit.Framework.TextMessageWriter.DisplayDifferences(System.Object,System.Object,NUnit.Framework.Constraints.Tolerance)">
+ <summary>
+ Display Expected and Actual lines for given values, including
+ a tolerance value on the expected line.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="actual">The actual value causing the failure</param>
+ <param name="tolerance">The tolerance within which the test was made</param>
+ </member>
+ <member name="M:NUnit.Framework.TextMessageWriter.DisplayStringDifferences(System.String,System.String,System.Int32,System.Boolean,System.Boolean)">
+ <summary>
+ Display the expected and actual string values on separate lines.
+ If the mismatch parameter is >=0, an additional line is displayed
+ line containing a caret that points to the mismatch point.
+ </summary>
+ <param name="expected">The expected string value</param>
+ <param name="actual">The actual string value</param>
+ <param name="mismatch">The point at which the strings don't match or -1</param>
+ <param name="ignoreCase">If true, case is ignored in string comparisons</param>
+ <param name="clipping">If true, clip the strings to fit the max line length</param>
+ </member>
+ <member name="M:NUnit.Framework.TextMessageWriter.WriteConnector(System.String)">
+ <summary>
+ Writes the text for a connector.
+ </summary>
+ <param name="connector">The connector.</param>
+ </member>
+ <member name="M:NUnit.Framework.TextMessageWriter.WritePredicate(System.String)">
+ <summary>
+ Writes the text for a predicate.
+ </summary>
+ <param name="predicate">The predicate.</param>
+ </member>
+ <member name="M:NUnit.Framework.TextMessageWriter.WriteModifier(System.String)">
+ <summary>
+ Write the text for a modifier.
+ </summary>
+ <param name="modifier">The modifier.</param>
+ </member>
+ <member name="M:NUnit.Framework.TextMessageWriter.WriteExpectedValue(System.Object)">
+ <summary>
+ Writes the text for an expected value.
+ </summary>
+ <param name="expected">The expected value.</param>
+ </member>
+ <member name="M:NUnit.Framework.TextMessageWriter.WriteActualValue(System.Object)">
+ <summary>
+ Writes the text for an actual value.
+ </summary>
+ <param name="actual">The actual value.</param>
+ </member>
+ <member name="M:NUnit.Framework.TextMessageWriter.WriteValue(System.Object)">
+ <summary>
+ Writes the text for a generalized value.
+ </summary>
+ <param name="val">The value.</param>
+ </member>
+ <member name="M:NUnit.Framework.TextMessageWriter.WriteCollectionElements(System.Collections.ICollection,System.Int32,System.Int32)">
+ <summary>
+ Writes the text for a collection value,
+ starting at a particular point, to a max length
+ </summary>
+ <param name="collection">The collection containing elements to write.</param>
+ <param name="start">The starting point of the elements to write</param>
+ <param name="max">The maximum number of elements to write</param>
+ </member>
+ <member name="M:NUnit.Framework.TextMessageWriter.WriteExpectedLine(NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Write the generic 'Expected' line for a constraint
+ </summary>
+ <param name="constraint">The constraint that failed</param>
+ </member>
+ <member name="M:NUnit.Framework.TextMessageWriter.WriteExpectedLine(System.Object)">
+ <summary>
+ Write the generic 'Expected' line for a given value
+ </summary>
+ <param name="expected">The expected value</param>
+ </member>
+ <member name="M:NUnit.Framework.TextMessageWriter.WriteExpectedLine(System.Object,NUnit.Framework.Constraints.Tolerance)">
+ <summary>
+ Write the generic 'Expected' line for a given value
+ and tolerance.
+ </summary>
+ <param name="expected">The expected value</param>
+ <param name="tolerance">The tolerance within which the test was made</param>
+ </member>
+ <member name="M:NUnit.Framework.TextMessageWriter.WriteActualLine(NUnit.Framework.Constraints.Constraint)">
+ <summary>
+ Write the generic 'Actual' line for a constraint
+ </summary>
+ <param name="constraint">The constraint for which the actual value is to be written</param>
+ </member>
+ <member name="M:NUnit.Framework.TextMessageWriter.WriteActualLine(System.Object)">
+ <summary>
+ Write the generic 'Actual' line for a given value
+ </summary>
+ <param name="actual">The actual value causing a failure</param>
+ </member>
+ <member name="P:NUnit.Framework.TextMessageWriter.MaxLineLength">
+ <summary>
+ Gets or sets the maximum line length for this writer
+ </summary>
+ </member>
+ <member name="T:NUnit.Framework.Throws">
+ <summary>
+ Helper class with properties and methods that supply
+ constraints that operate on exceptions.
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Throws.TypeOf(System.Type)">
+ <summary>
+ Creates a constraint specifying the exact type of exception expected
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Throws.TypeOf``1">
+ <summary>
+ Creates a constraint specifying the exact type of exception expected
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Throws.InstanceOf(System.Type)">
+ <summary>
+ Creates a constraint specifying the type of exception expected
+ </summary>
+ </member>
+ <member name="M:NUnit.Framework.Throws.InstanceOf``1">
+ <summary>
+ Creates a constraint specifying the type of exception expected
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Throws.Exception">
+ <summary>
+ Creates a constraint specifying an expected exception
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Throws.InnerException">
+ <summary>
+ Creates a constraint specifying an exception with a given InnerException
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Throws.TargetInvocationException">
+ <summary>
+ Creates a constraint specifying an expected TargetInvocationException
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Throws.ArgumentException">
+ <summary>
+ Creates a constraint specifying an expected TargetInvocationException
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Throws.InvalidOperationException">
+ <summary>
+ Creates a constraint specifying an expected TargetInvocationException
+ </summary>
+ </member>
+ <member name="P:NUnit.Framework.Throws.Nothing">
+ <summary>
+ Creates a constraint specifying that no exception is thrown
+ </summary>
+ </member>
+ </members>
+</doc>
--- /dev/null
+Copyright © 2002-2008 Charlie Poole
+Copyright © 2002-2004 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov
+Copyright © 2000-2002 Philip A. Craig
+
+This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment (see the following) in the product documentation is required.
+
+Portions Copyright © 2002-2008 Charlie Poole or Copyright © 2002-2004 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov or Copyright © 2000-2002 Philip A. Craig
+
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source distribution.
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<VisualState xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ShowCheckBoxes="false">
+ <TopNode>[0-1000]D:\Dev\NUnit\nunit-2.5\work\build\net\2.0\release\NUnitTests.nunit</TopNode>
+ <SelectedNode>[0-1000]D:\Dev\NUnit\nunit-2.5\work\build\net\2.0\release\NUnitTests.nunit</SelectedNode>
+ <ExcludeCategories>false</ExcludeCategories>
+ <Nodes>
+ <Node UniqueName="[0-1000]D:\Dev\NUnit\nunit-2.5\work\build\net\2.0\release\NUnitTests.nunit" Expanded="true" />
+ <Node UniqueName="[0-2832]D:\Dev\NUnit\nunit-2.5\work\build\net\2.0\release\tests/nunit.framework.tests.dll" Expanded="true" />
+ <Node UniqueName="[0-2833]NUnit" Expanded="true" />
+ <Node UniqueName="[0-2834]NUnit.Framework" Expanded="true" />
+ <Node UniqueName="[0-2835]NUnit.Framework.Constraints" Expanded="true" />
+ <Node UniqueName="[0-1001]NUnit.Framework.Constraints.AfterConstraintTest" Expanded="true" />
+ <Node UniqueName="[0-1023]NUnit.Framework.Constraints.AndTest" Expanded="true" />
+ <Node UniqueName="[0-1914]NUnit.Framework.Constraints.AssignableFromTest" Expanded="true" />
+ <Node UniqueName="[0-1924]NUnit.Framework.Constraints.AssignableToTest" Expanded="true" />
+ <Node UniqueName="[0-1934]NUnit.Framework.Constraints.AttributeExistsConstraintTest" Expanded="true" />
+ <Node UniqueName="[0-1697]NUnit.Framework.Constraints.BinarySerializableTest" Expanded="true" />
+ <Node UniqueName="[0-1144]NUnit.Framework.Constraints.ComparerTests" Expanded="true" />
+ <Node UniqueName="[0-1271]NUnit.Framework.Constraints.EmptyConstraintTest" Expanded="true" />
+ <Node UniqueName="[0-1806]NUnit.Framework.Constraints.EndsWithTest" Expanded="true" />
+ <Node UniqueName="[0-1826]NUnit.Framework.Constraints.EndsWithTestIgnoringCase" Expanded="true" />
+ <Node UniqueName="[0-1300]NUnit.Framework.Constraints.EqualConstraintTest" Expanded="true" />
+ <Node UniqueName="[0-1893]NUnit.Framework.Constraints.ExactTypeTest" Expanded="true" />
+ <Node UniqueName="[0-1060]NUnit.Framework.Constraints.FalseConstraintTest" Expanded="true" />
+ <Node UniqueName="[0-1196]NUnit.Framework.Constraints.GreaterThanOrEqualTest" Expanded="true" />
+ <Node UniqueName="[0-1176]NUnit.Framework.Constraints.GreaterThanTest" Expanded="true" />
+ <Node UniqueName="[0-1904]NUnit.Framework.Constraints.InstanceOfTypeTest" Expanded="true" />
+ <Node UniqueName="[0-1234]NUnit.Framework.Constraints.LessThanOrEqualTest" Expanded="true" />
+ <Node UniqueName="[0-1214]NUnit.Framework.Constraints.LessThanTest" Expanded="true" />
+ <Node UniqueName="[0-1398]NUnit.Framework.Constraints.MsgUtilTests" Expanded="true" />
+ <Node UniqueName="[0-1076]NUnit.Framework.Constraints.NaNConstraintTest" Expanded="true" />
+ <Node UniqueName="[0-1429]NUnit.Framework.Constraints.NotTest" Expanded="true" />
+ <Node UniqueName="[0-1035]NUnit.Framework.Constraints.NullConstraintTest" Expanded="true" />
+ <Node UniqueName="[0-1288]NUnit.Framework.Constraints.NullOrEmptyStringConstraintTest" Expanded="true" />
+ <Node UniqueName="[0-1443]NUnit.Framework.Constraints.NumericsTest" Expanded="true" />
+ <Node UniqueName="[0-1477]NUnit.Framework.Constraints.OrTest" Expanded="true" />
+ <Node UniqueName="[0-1643]NUnit.Framework.Constraints.PropertyExistsTest" Expanded="true" />
+ <Node UniqueName="[0-1660]NUnit.Framework.Constraints.PropertyTest" Expanded="true" />
+ <Node UniqueName="[0-1252]NUnit.Framework.Constraints.RangeConstraintTest" Expanded="true" />
+ <Node UniqueName="[0-1677]NUnit.Framework.Constraints.ReusableConstraintTests" Expanded="true" />
+ <Node UniqueName="[0-1684]NUnit.Framework.Constraints.SameAsTest" Expanded="true" />
+ <Node UniqueName="[0-1615]NUnit.Framework.Constraints.SamePathOrUnderTest_Linux" Expanded="true" />
+ <Node UniqueName="[0-1592]NUnit.Framework.Constraints.SamePathOrUnderTest_Windows" Expanded="true" />
+ <Node UniqueName="[0-1507]NUnit.Framework.Constraints.SamePathTest_Linux" Expanded="true" />
+ <Node UniqueName="[0-1488]NUnit.Framework.Constraints.SamePathTest_Windows" Expanded="true" />
+ <Node UniqueName="[0-1766]NUnit.Framework.Constraints.StartsWithTest" Expanded="true" />
+ <Node UniqueName="[0-1786]NUnit.Framework.Constraints.StartsWithTestIgnoringCase" Expanded="true" />
+ <Node UniqueName="[0-1559]NUnit.Framework.Constraints.SubPathTest_Linux" Expanded="true" />
+ <Node UniqueName="[0-1529]NUnit.Framework.Constraints.SubPathTest_Windows" Expanded="true" />
+ <Node UniqueName="[0-1728]NUnit.Framework.Constraints.SubstringTest" Expanded="true" />
+ <Node UniqueName="[0-1748]NUnit.Framework.Constraints.SubstringTestIgnoringCase" Expanded="true" />
+ <Node UniqueName="[0-1846]NUnit.Framework.Constraints.ThrowsConstraintTest_ExactType" Expanded="true" />
+ <Node UniqueName="[0-1859]NUnit.Framework.Constraints.ThrowsConstraintTest_InstanceOfType" Expanded="true" />
+ <Node UniqueName="[0-1873]NUnit.Framework.Constraints.ThrowsConstraintTest_WithConstraint" Expanded="true" />
+ <Node UniqueName="[0-1044]NUnit.Framework.Constraints.TrueConstraintTest" Expanded="true" />
+ <Node UniqueName="[0-1711]NUnit.Framework.Constraints.XmlSerializableTest" Expanded="true" />
+ <Node UniqueName="[0-2836]NUnit.Framework.Syntax" Expanded="true" />
+ <Node UniqueName="[0-2093]NUnit.Framework.Syntax.InvalidCodeTests" Expanded="true" />
+ <Node UniqueName="[0-2837]NUnit.Framework.Tests" Expanded="true" />
+ <Node UniqueName="[0-2772]NUnit.Framework.Tests.ValuesAttributeTests" Expanded="true" />
+ <Node UniqueName="[0-3878]D:\Dev\NUnit\nunit-2.5\work\build\net\2.0\release\tests/nunit.core.tests.dll" Expanded="true" />
+ <Node UniqueName="[0-3879]NUnit" Expanded="true" />
+ <Node UniqueName="[0-3880]NUnit.Core" Expanded="true" />
+ <Node UniqueName="[0-3881]NUnit.Core.Tests" Expanded="true" />
+ <Node UniqueName="[0-2919]NUnit.Core.Tests.CategoryAttributeTests" Expanded="true" />
+ <Node UniqueName="[0-2929]NUnit.Core.Tests.CombinatorialTests" Expanded="true" />
+ <Node UniqueName="[0-2998]NUnit.Core.Tests.CultureSettingAndDetectionTests" Expanded="true" />
+ <Node UniqueName="[0-3021]NUnit.Core.Tests.EventQueueTests" Expanded="true" />
+ <Node UniqueName="[0-3882]NUnit.Core.Tests.Generic" Expanded="true" />
+ <Node UniqueName="[0-2838]NUnit.Core.Tests.Generic.DeduceTypeArgsFromArgs<T1,T2>" Expanded="true" />
+ <Node UniqueName="[0-2839]NUnit.Core.Tests.Generic.DeduceTypeArgsFromArgs<Double,Int32>(100.0d,42)" Expanded="true" />
+ <Node UniqueName="[0-2842]NUnit.Core.Tests.Generic.DeduceTypeArgsFromArgs<Int32,Double>(42,100.0d)" Expanded="true" />
+ <Node UniqueName="[0-2845]NUnit.Core.Tests.Generic.SimpleGenericFixture<TList>" Expanded="true" />
+ <Node UniqueName="[0-2850]NUnit.Core.Tests.Generic.SimpleGenericMethods" Expanded="true" />
+ <Node UniqueName="[0-2866]NUnit.Core.Tests.Generic.TypeParameterUsedWithTestMethod<T>" Expanded="true" />
+ <Node UniqueName="[0-2867]NUnit.Core.Tests.Generic.TypeParameterUsedWithTestMethod<Double>" Expanded="true" />
+ <Node UniqueName="[0-3158]NUnit.Core.Tests.PairwiseTest" Expanded="true" />
+ <Node UniqueName="[0-3169]NUnit.Core.Tests.PairwiseTest+LiveTest" Expanded="true" />
+ <Node UniqueName="[0-3178]NUnit.Core.Tests.ParameterizedTestFixture" Expanded="true" />
+ <Node UniqueName="[0-3195]NUnit.Core.Tests.ParameterizedTestFixtureWithDataSources" Expanded="true" />
+ <Node UniqueName="[0-3196]NUnit.Core.Tests.ParameterizedTestFixtureWithDataSources(42)" Expanded="true" />
+ <Node UniqueName="[0-3188]NUnit.Core.Tests.ParameterizedTestFixtureWithNullArguments" Expanded="true" />
+ <Node UniqueName="[0-3297]NUnit.Core.Tests.RuntimeFrameworkTests" Expanded="true" />
+ <Node UniqueName="[0-3466]NUnit.Core.Tests.TestCaseAttributeTests" Expanded="true" />
+ <Node UniqueName="[0-3536]NUnit.Core.Tests.TestCaseSourceTests" Expanded="true" />
+ <Node UniqueName="[0-3753]NUnit.Core.Tests.TheoryTests" Expanded="true" />
+ <Node UniqueName="[0-3775]NUnit.Core.Tests.TheoryTests+SqrtTests_DisplayResults" Expanded="true" />
+ <Node UniqueName="[0-3817]NUnit.Core.Tests.TypeHelperTests" Expanded="true" />
+ <Node UniqueName="[0-3844]NUnit.Core.Tests.ValueSourceTests" Expanded="true" />
+ <Node UniqueName="[0-4250]D:\Dev\NUnit\nunit-2.5\work\build\net\2.0\release\tests/nunit.util.tests.dll" Expanded="true" />
+ <Node UniqueName="[0-4251]NUnit" Expanded="true" />
+ <Node UniqueName="[0-4252]NUnit.Util" Expanded="true" />
+ <Node UniqueName="[0-4134]NUnit.Util.Tests.ServiceManagerSetUpFixture" Expanded="true" />
+ <Node UniqueName="[0-4110]NUnit.Util.Tests.RuntimeFrameworkSelectorTests" Expanded="true" />
+ <Node UniqueName="[0-4302]D:\Dev\NUnit\nunit-2.5\work\build\net\2.0\release\tests/nunit.mocks.tests.dll" Expanded="true" />
+ <Node UniqueName="[0-4303]NUnit" Expanded="true" />
+ <Node UniqueName="[0-4304]NUnit.Mocks" Expanded="true" />
+ <Node UniqueName="[0-4305]NUnit.Mocks.Tests" Expanded="true" />
+ <Node UniqueName="[0-4361]D:\Dev\NUnit\nunit-2.5\work\build\net\2.0\release\tests/nunit-console.tests.dll" Expanded="true" />
+ <Node UniqueName="[0-4362]NUnit" Expanded="true" />
+ <Node UniqueName="[0-4363]NUnit.ConsoleRunner" Expanded="true" />
+ <Node UniqueName="[0-4364]NUnit.ConsoleRunner.Tests" Expanded="true" />
+ <Node UniqueName="[0-4345]NUnit.ConsoleRunner.Tests.TestNameParserTests" Expanded="true" />
+ <Node UniqueName="[0-4604]D:\Dev\NUnit\nunit-2.5\work\build\net\2.0\release\tests/nunit.uiexception.tests.dll" Expanded="true" />
+ <Node UniqueName="[0-4605]NUnit" Expanded="true" />
+ <Node UniqueName="[0-4606]NUnit.UiException" Expanded="true" />
+ <Node UniqueName="[0-4607]NUnit.UiException.Tests" Expanded="true" />
+ <Node UniqueName="[0-4608]NUnit.UiException.Tests.CodeFormatters" Expanded="true" />
+ <Node UniqueName="[0-4609]NUnit.UiException.Tests.Controls" Expanded="true" />
+ <Node UniqueName="[0-4610]NUnit.UiException.Tests.StackTraceAnalyzers" Expanded="true" />
+ <Node UniqueName="[0-4665]D:\Dev\NUnit\nunit-2.5\work\build\net\2.0\release\tests/nunit.uikit.tests.dll" Expanded="true" />
+ <Node UniqueName="[0-4666]NUnit" Expanded="true" />
+ <Node UniqueName="[0-4667]NUnit.UiKit" Expanded="true" />
+ <Node UniqueName="[0-4668]NUnit.UiKit.Tests" Expanded="true" />
+ <Node UniqueName="[0-4687]D:\Dev\NUnit\nunit-2.5\work\build\net\2.0\release\tests/nunit-gui.tests.dll" Expanded="true" />
+ <Node UniqueName="[0-4688]NUnit" Expanded="true" />
+ <Node UniqueName="[0-4689]NUnit.Gui" Expanded="true" />
+ <Node UniqueName="[0-4690]NUnit.Gui.Tests" Expanded="true" />
+ <Node UniqueName="[0-4699]D:\Dev\NUnit\nunit-2.5\work\build\net\2.0\release\tests/nunit.fixtures.tests.dll" Expanded="true" />
+ <Node UniqueName="[0-4700]NUnit" Expanded="true" />
+ <Node UniqueName="[0-4701]NUnit.Fixtures" Expanded="true" />
+ <Node UniqueName="[0-4702]NUnit.Fixtures.Tests" Expanded="true" />
+ </Nodes>
+</VisualState>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+<!--
+ This is the configuration file for the NUnitTests.nunit test project. You may
+ need to create a similar configuration file for your own test project.
+ -->
+
+<!--
+ The <NUnit> section is only needed if you want to use a non-default value
+ for any of the settings. It is commented out below. If you are going to use
+ it, you must deifne the NUnit section group and the sections you need.
+
+ The syntax shown here works for most runtimes. If NUnit fails at startup, you
+ can try specifying the name of the assembly containing the NameValueSectionHandler:
+
+ <section name="TestCaseBuilder" type="System.Configuration.NameValueSectionHandler, System" />
+
+ If that fails, try the fully qualified name of the assembly:
+
+ <section name="TestCaseBuilder" type="System.Configuration.NameValueSectionHandler, System,
+ Version=2.0.50727.832, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+
+ Unfortunately, this last approach makes your config file non-portable across runtimes.
+ -->
+
+<!--
+ <configSections>
+ <sectionGroup name="NUnit">
+ <section name="TestCaseBuilder" type="System.Configuration.NameValueSectionHandler"/>
+ <section name="TestRunner" type="System.Configuration.NameValueSectionHandler"/>
+ </sectionGroup>
+ </configSections>
+ -->
+
+ <appSettings>
+ <!-- User application and configured property settings go here.-->
+ <!-- Example: <add key="settingName" value="settingValue"/> -->
+ <add key="test.setting" value="54321" />
+ </appSettings>
+
+<!-- Sample NUnit section group showing all default values -->
+<!--
+ <NUnit>
+ <TestCaseBuilder>
+ <add key="OldStyleTestCases" value="false" />
+ </TestCaseBuilder>
+ <TestRunner>
+ <add key="ApartmentState" value="MTA" />
+ <add key="ThreadPriority" value="Normal" />
+ <add key="DefaultLogThreshold" value="Info" />
+ </TestRunner>
+ </NUnit>
+-->
+
+ <!--
+ The following <runtime> section allows running nunit tests under
+ .NET 1.0 by redirecting assemblies. The appliesTo attribute
+ causes the section to be ignored except under .NET 1.0.
+ -->
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"
+ appliesTo="v1.0.3705">
+ <dependentAssembly>
+ <assemblyIdentity name="System" publicKeyToken="b77a5c561934e089" culture="" />
+ <bindingRedirect oldVersion="1.0.5000.0" newVersion="1.0.3300.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Data" publicKeyToken="b77a5c561934e089" culture="" />
+ <bindingRedirect oldVersion="1.0.5000.0" newVersion="1.0.3300.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Drawing" publicKeyToken="b03f5f7f11d50a3a" culture="" />
+ <bindingRedirect oldVersion="1.0.5000.0" newVersion="1.0.3300.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Windows.Forms" publicKeyToken="b77a5c561934e089" culture="" />
+ <bindingRedirect oldVersion="1.0.5000.0" newVersion="1.0.3300.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Xml" publicKeyToken="b77a5c561934e089" culture="" />
+ <bindingRedirect oldVersion="1.0.5000.0" newVersion="1.0.3300.0" />
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+</configuration>
--- /dev/null
+<NUnitProject>
+ <Settings appbase="."/>
+ <Config name="Default" binpath="lib;tests;framework" runtimeFramework="v2.0">
+ <assembly path="tests/nunit.framework.tests.dll" />
+ <assembly path="tests/nunit.core.tests.dll" />
+ <assembly path="tests/nunit.util.tests.dll" />
+ <assembly path="tests/nunit.mocks.tests.dll" />
+ <assembly path="tests/nunit-console.tests.dll" />
+ <assembly path="tests/nunit.uiexception.tests.dll" />
+ <assembly path="tests/nunit.uikit.tests.dll" />
+ <assembly path="tests/nunit-gui.tests.dll" />
+ <assembly path="tests/nunit.fixtures.tests.dll" />
+ </Config>
+</NUnitProject>
--- /dev/null
+<AgentConfig>
+ <Port>8080</Port>
+ <PathToAssemblies>.</PathToAssemblies>
+</AgentConfig>
\ No newline at end of file
--- /dev/null
+<log4net>
+ <!-- A1 is set to be a ConsoleAppender -->
+ <appender name="A1" type="log4net.Appender.ConsoleAppender">
+
+ <!-- A1 uses PatternLayout -->
+ <layout type="log4net.Layout.PatternLayout">
+ <!-- Print the date in ISO 8601 format -->
+ <conversionPattern value="%-5level %logger - %message%newline" />
+ </layout>
+ </appender>
+
+ <!-- Set root logger level to DEBUG and its only appender to A1 -->
+ <root>
+ <level value="DEBUG" />
+ <appender-ref ref="A1" />
+ </root>
+
+</log4net>
--- /dev/null
+<log4net>
+ <!-- A1 is set to be a ConsoleAppender -->
+ <appender name="A1" type="log4net.Appender.ConsoleAppender">
+
+ <!-- A1 uses PatternLayout -->
+ <layout type="log4net.Layout.PatternLayout">
+ <!-- Print the date in ISO 8601 format -->
+ <conversionPattern value="%-5level %logger - %message%newline" />
+ </layout>
+ </appender>
+
+ <!-- Set root logger level to DEBUG and its only appender to A1 -->
+ <root>
+ <level value="DEBUG" />
+ <appender-ref ref="A1" />
+ </root>
+
+</log4net>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+
+ <runtime>
+ <!-- We need this so test exceptions don't crash NUnit -->
+ <legacyUnhandledExceptionPolicy enabled="1" />
+
+ <!-- Look for addins in the addins directory for now -->
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <probing privatePath="lib;addins"/>
+ </assemblyBinding>
+
+ <!--
+ The following <assemblyBinding> section allows running nunit under
+ .NET 1.0 by redirecting assemblies. The appliesTo attribute
+ causes the section to be ignored except under .NET 1.0
+ on a machine with only the .NET version 1.0 runtime installed.
+ If application and its tests were built for .NET 1.1 you will
+ also need to redirect system assemblies in the test config file,
+ which controls loading of the tests.
+ -->
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"
+ appliesTo="v1.0.3705">
+
+ <dependentAssembly>
+ <assemblyIdentity name="System"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Data"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Drawing"
+ publicKeyToken="b03f5f7f11d50a3a"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Windows.Forms"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Xml"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ </assemblyBinding>
+
+ </runtime>
+
+</configuration>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+
+ <runtime>
+ <!-- We need this so test exceptions don't crash NUnit -->
+ <legacyUnhandledExceptionPolicy enabled="1" />
+
+ <!-- Look for addins in the addins directory for now -->
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <probing privatePath="lib;addins"/>
+ </assemblyBinding>
+
+ <!--
+ The following <assemblyBinding> section allows running nunit under
+ .NET 1.0 by redirecting assemblies. The appliesTo attribute
+ causes the section to be ignored except under .NET 1.0
+ on a machine with only the .NET version 1.0 runtime installed.
+ If application and its tests were built for .NET 1.1 you will
+ also need to redirect system assemblies in the test config file,
+ which controls loading of the tests.
+ -->
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"
+ appliesTo="v1.0.3705">
+
+ <dependentAssembly>
+ <assemblyIdentity name="System"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Data"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Drawing"
+ publicKeyToken="b03f5f7f11d50a3a"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Windows.Forms"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Xml"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ </assemblyBinding>
+
+ </runtime>
+
+</configuration>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+
+ <runtime>
+ <!-- We need this so test exceptions don't crash NUnit -->
+ <legacyUnhandledExceptionPolicy enabled="1" />
+
+ <!-- Look for addins in the addins directory for now -->
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <probing privatePath="lib;addins"/>
+ </assemblyBinding>
+
+ <!--
+ The following <assemblyBinding> section allows running nunit under
+ .NET 1.0 by redirecting assemblies. The appliesTo attribute
+ causes the section to be ignored except under .NET 1.0
+ on a machine with only the .NET version 1.0 runtime installed.
+ If application and its tests were built for .NET 1.1 you will
+ also need to redirect system assemblies in the test config file,
+ which controls loading of the tests.
+ -->
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"
+ appliesTo="v1.0.3705">
+
+ <dependentAssembly>
+ <assemblyIdentity name="System"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Data"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Drawing"
+ publicKeyToken="b03f5f7f11d50a3a"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Windows.Forms"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Xml"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ </assemblyBinding>
+
+ </runtime>
+
+</configuration>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+
+ <runtime>
+ <!-- We need this so test exceptions don't crash NUnit -->
+ <legacyUnhandledExceptionPolicy enabled="1" />
+
+ <!-- Look for addins in the addins directory for now -->
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <probing privatePath="lib;addins"/>
+ </assemblyBinding>
+
+ <!--
+ The following <assemblyBinding> section allows running nunit under
+ .NET 1.0 by redirecting assemblies. The appliesTo attribute
+ causes the section to be ignored except under .NET 1.0
+ on a machine with only the .NET version 1.0 runtime installed.
+ If application and its tests were built for .NET 1.1 you will
+ also need to redirect system assemblies in the test config file,
+ which controls loading of the tests.
+ -->
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"
+ appliesTo="v1.0.3705">
+
+ <dependentAssembly>
+ <assemblyIdentity name="System"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Data"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Drawing"
+ publicKeyToken="b03f5f7f11d50a3a"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Windows.Forms"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Xml"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ </assemblyBinding>
+
+ </runtime>
+
+</configuration>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <!--
+ Application settings for NUnit-gui.exe. Do NOT put settings
+ for use by your tests here.
+ -->
+ <appSettings>
+ <!--
+ Uncomment to specify the url to be used for help. If not used, the
+ default value is something like
+ file://localhost/C:/Program Files/NUnit 2.2/doc/index.html
+ This setting is provided in case your default browser doesn't
+ support this format.
+ -->
+ <!-- <add key="helpUrl" value="http://www.nunit.org" /> -->
+ </appSettings>
+
+ <runtime>
+ <!-- We need this so test exceptions don't crash NUnit -->
+ <legacyUnhandledExceptionPolicy enabled="1" />
+
+ <!-- Look for addins in the addins directory for now -->
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <probing privatePath="lib;addins" />
+ </assemblyBinding>
+
+ <!--
+ The following <assemblyBinding> section allows running nunit under
+ .NET 1.0 by redirecting assemblies. The appliesTo attribute
+ causes the section to be ignored except under .NET 1.0
+ on a machine with only the .NET version 1.0 runtime installed.
+ If application and its tests were built for .NET 1.1 you will
+ also need to redirect system assemblies in the test config file,
+ which controls loading of the tests.
+ -->
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"
+ appliesTo="v1.0.3705">
+
+ <dependentAssembly>
+ <assemblyIdentity name="System"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Data"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Drawing"
+ publicKeyToken="b03f5f7f11d50a3a"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Windows.Forms"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Xml"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ </assemblyBinding>
+
+ </runtime>
+
+</configuration>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <!--
+ Application settings for NUnit-gui.exe. Do NOT put settings
+ for use by your tests here.
+ -->
+ <appSettings>
+ <!--
+ Uncomment to specify the url to be used for help. If not used, the
+ default value is something like
+ file://localhost/C:/Program Files/NUnit 2.2/doc/index.html
+ This setting is provided in case your default browser doesn't
+ support this format.
+ -->
+ <!-- <add key="helpUrl" value="http://www.nunit.org" /> -->
+ </appSettings>
+
+ <runtime>
+ <!-- We need this so test exceptions don't crash NUnit -->
+ <legacyUnhandledExceptionPolicy enabled="1" />
+
+ <!-- Look for addins in the addins directory for now -->
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <probing privatePath="lib;addins" />
+ </assemblyBinding>
+
+ <!--
+ The following <assemblyBinding> section allows running nunit under
+ .NET 1.0 by redirecting assemblies. The appliesTo attribute
+ causes the section to be ignored except under .NET 1.0
+ on a machine with only the .NET version 1.0 runtime installed.
+ If application and its tests were built for .NET 1.1 you will
+ also need to redirect system assemblies in the test config file,
+ which controls loading of the tests.
+ -->
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"
+ appliesTo="v1.0.3705">
+
+ <dependentAssembly>
+ <assemblyIdentity name="System"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Data"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Drawing"
+ publicKeyToken="b03f5f7f11d50a3a"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Windows.Forms"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Xml"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ </assemblyBinding>
+
+ </runtime>
+
+</configuration>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="Windows-1252"?>
+<configuration>
+
+ <!-- Set the level for tracing NUnit itself -->
+ <!-- 0=Off 1=Error 2=Warning 3=Info 4=Debug -->
+ <system.diagnostics>
+ <switches>
+ <add name="NTrace" value="0" />
+ </switches>
+ </system.diagnostics>
+
+ <runtime>
+ <!-- We need this so test exceptions don't crash NUnit -->
+ <legacyUnhandledExceptionPolicy enabled="1" />
+
+ <!-- Look for addins in the addins directory for now -->
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <probing privatePath="framework;lib;addins"/>
+ </assemblyBinding>
+
+ <!--
+ The following <assemblyBinding> section allows running nunit under
+ .NET 1.0 by redirecting assemblies. The appliesTo attribute
+ causes the section to be ignored except under .NET 1.0
+ on a machine with only the .NET version 1.0 runtime installed.
+ If application and its tests were built for .NET 1.1 you will
+ also need to redirect system assemblies in the test config file,
+ which controls loading of the tests.
+ -->
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"
+ appliesTo="v1.0.3705">
+
+ <dependentAssembly>
+ <assemblyIdentity name="System"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Data"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Drawing"
+ publicKeyToken="b03f5f7f11d50a3a"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Windows.Forms"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Xml"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ </assemblyBinding>
+
+ </runtime>
+
+</configuration>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="Windows-1252"?>
+<configuration>
+
+ <!-- Set the level for tracing NUnit itself -->
+ <!-- 0=Off 1=Error 2=Warning 3=Info 4=Debug -->
+ <system.diagnostics>
+ <switches>
+ <add name="NTrace" value="0" />
+ </switches>
+ </system.diagnostics>
+
+ <runtime>
+ <!-- We need this so test exceptions don't crash NUnit -->
+ <legacyUnhandledExceptionPolicy enabled="1" />
+
+ <!-- Look for addins in the addins directory for now -->
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <probing privatePath="framework;lib;addins"/>
+ </assemblyBinding>
+
+ <!--
+ The following <assemblyBinding> section allows running nunit under
+ .NET 1.0 by redirecting assemblies. The appliesTo attribute
+ causes the section to be ignored except under .NET 1.0
+ on a machine with only the .NET version 1.0 runtime installed.
+ If application and its tests were built for .NET 1.1 you will
+ also need to redirect system assemblies in the test config file,
+ which controls loading of the tests.
+ -->
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"
+ appliesTo="v1.0.3705">
+
+ <dependentAssembly>
+ <assemblyIdentity name="System"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Data"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Drawing"
+ publicKeyToken="b03f5f7f11d50a3a"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Windows.Forms"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ <dependentAssembly>
+ <assemblyIdentity name="System.Xml"
+ publicKeyToken="b77a5c561934e089"
+ culture="neutral"/>
+ <bindingRedirect oldVersion="1.0.5000.0"
+ newVersion="1.0.3300.0"/>
+ </dependentAssembly>
+
+ </assemblyBinding>
+
+ </runtime>
+
+</configuration>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+ <startup>
+ <supportedRuntime version="v2.0.50727" />
+ <supportedRuntime version="v2.0.50215" />
+ <supportedRuntime version="v2.0.40607" />
+ <supportedRuntime version="v1.1.4322" />
+ <supportedRuntime version="v1.0.3705" />
+
+ <requiredRuntime version="v1.0.3705" />
+ </startup>
+
+<!--
+ The following <runtime> section allows running nunit tests under
+ .NET 1.0 by redirecting assemblies. The appliesTo attribute
+ causes the section to be ignored except under .NET 1.0.
+ -->
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"
+ appliesTo="v1.0.3705">
+ <dependentAssembly>
+ <assemblyIdentity name="System" publicKeyToken="b77a5c561934e089" culture="" />
+ <bindingRedirect oldVersion="1.0.5000.0" newVersion="1.0.3300.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Data" publicKeyToken="b77a5c561934e089" culture="" />
+ <bindingRedirect oldVersion="1.0.5000.0" newVersion="1.0.3300.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Drawing" publicKeyToken="b03f5f7f11d50a3a" culture="" />
+ <bindingRedirect oldVersion="1.0.5000.0" newVersion="1.0.3300.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Windows.Forms" publicKeyToken="b77a5c561934e089" culture="" />
+ <bindingRedirect oldVersion="1.0.5000.0" newVersion="1.0.3300.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Xml" publicKeyToken="b77a5c561934e089" culture="" />
+ <bindingRedirect oldVersion="1.0.5000.0" newVersion="1.0.3300.0" />
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+</configuration>
--- /dev/null
+start pnunit-agent agent.conf
+pnunit-launcher test.conf
\ No newline at end of file
--- /dev/null
+<TestGroup>
+ <ParallelTests>
+
+ <ParallelTest>
+ <Name>Testing</Name>
+ <Tests>
+ <TestConf>
+ <Name>Testing</Name>
+ <Assembly>pnunit.tests.dll</Assembly>
+ <TestToRun>TestLibraries.Testing.EqualTo19</TestToRun>
+ <Machine>localhost:8080</Machine>
+ <TestParams>
+ <string>..\server</string> <!-- server dir -->
+ <string></string> <!-- database server -->
+ <string></string><!-- conn string -->
+ </TestParams>
+ </TestConf>
+
+ </Tests>
+ </ParallelTest>
+
+
+ </ParallelTests>
+</TestGroup>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<repositories>
+ <repository path="..\net35\ICSharpCode.SharpZipLib.Silverlight.Tests\packages.config" />
+</repositories>
\ No newline at end of file