├── .gitignore
├── .nuget
├── NuGet.Config
├── NuGet.exe
└── NuGet.targets
├── Blazer.Benchmark
├── Blazer.Benchmark.csproj
├── MessagesDto
│ └── LogMessage.cs
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
├── QuickLZ
│ └── QuickLZ.cs
└── packages.config
├── Blazer.Core.sln
├── Blazer.Exe
├── Blazer.Exe.csproj
├── CommandLine
│ ├── BlazerCommandLineOptions.cs
│ ├── CommandLineDescriptionAttribute.cs
│ ├── CommandLineOptionAttribute.cs
│ └── CommandLineParser.cs
├── FileNameHelper.cs
├── NullStream.cs
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
└── StatStream.cs
├── Blazer.Native.Build
├── Blazer.Native.x64.dll
└── Blazer.Native.x86.dll
├── Blazer.Native
├── .gitignore
├── Blazer.Native.vcxproj
├── Blazer.Native.vcxproj.filters
├── Blazer.cpp
├── Blazer.rc
├── BlazerBlock.cpp
├── BlazerStream.cpp
├── build.cmd
├── crc32c.cpp
├── dllmain.cpp
├── resource.h
├── stdafx.cpp
├── stdafx.h
└── targetver.h
├── Blazer.Net.Tests
├── BigDataTests.cs
├── Blazer.Net.Tests.csproj
├── Blazer.Net.Tests.xproj
├── Crc32Tests.cs
├── DataArrayTests.cs
├── EncryptionTests.cs
├── IntegrityHelper.cs
├── IntegrityTests.cs
├── MultipleFilesTests.cs
├── NativeCheckTests.cs
├── OptionsTests.cs
├── PatternedCompressionTests.cs
├── Properties
│ └── AssemblyInfo.cs
├── StreamEncoderTests.cs
├── StreamHandlingTests.cs
├── TcpClientExtensions.cs
├── TcpStreamTests.cs
├── packages.config
├── project.json
└── project.lock.json
├── Blazer.Net
├── .gitignore
├── Algorithms
│ ├── BlockDecoder.cs
│ ├── BlockDecoderNative.cs
│ ├── BlockEncoder.cs
│ ├── BlockEncoderNative.cs
│ ├── BufferInfo.cs
│ ├── Crc32C
│ │ ├── Crc32C.cs
│ │ ├── Crc32CHardware.cs
│ │ ├── Crc32CSoftware.cs
│ │ └── ICrc32CCalculator.cs
│ ├── EncoderDecoderFactory.cs
│ ├── IDecoder.cs
│ ├── IEncoder.cs
│ ├── NoCompressionDecoder.cs
│ ├── NoCompressionEncoder.cs
│ ├── Patterned
│ │ ├── BasePatternedCompressor.cs
│ │ ├── BlockPatternedCompressor.cs
│ │ ├── IPatternedCompressor.cs
│ │ ├── StreamHighPatternedCompressor.cs
│ │ └── StreamPatternedCompressor.cs
│ ├── StreamDecoder.cs
│ ├── StreamDecoderNative.cs
│ ├── StreamEncoder.cs
│ ├── StreamEncoderHigh.cs
│ └── StreamEncoderNative.cs
├── Blazer.Net.csproj
├── Blazer.Net.nuspec
├── Blazer.Net.xproj
├── BlazerAlgorithm.cs
├── BlazerBlockType.cs
├── BlazerCompressionOptions.cs
├── BlazerDecompressionOptions.cs
├── BlazerFileInfo.cs
├── BlazerFlags.cs
├── BlazerFlushMode.cs
├── BlazerInputStream.cs
├── BlazerOutputStream.cs
├── BlazerPatternedHelper.cs
├── Encyption
│ ├── DecryptHelper.cs
│ ├── EncryptHelper.cs
│ └── Iso10126TransformEmulator.cs
├── Helpers
│ ├── BlazerFileHelper.cs
│ ├── DataArrayCompressorHelper.cs
│ └── FileHeaderHelper.cs
├── Native
│ └── NativeHelper.cs
├── Properties
│ └── AssemblyInfo.cs
├── pack.cmd
├── project.json
└── project.lock.json
├── Blazer.sln
├── Doc
├── Images
│ ├── chart_blocksize1.png
│ ├── chart_comprrate1.png
│ ├── chart_comprrate2.png
│ └── chart_pattern1.png
└── PatternedCompression.md
├── LICENSE
├── README.md
├── blazer-nuget-ico.png
├── global.json
└── public.snk
/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | obj
3 | *.user
4 | *.suo
5 | packages
6 | .tools
7 | private.snk
8 | sign.cmd
9 | _releases
10 |
11 | # todo: check this folders
12 | ipch
13 | Win32
14 | *.sdf
15 | *.opensdf
16 |
17 | .idea
--------------------------------------------------------------------------------
/.nuget/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.nuget/NuGet.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/force-net/blazer/5520e017a2f5d1b55f5ab978036b138faa765e38/.nuget/NuGet.exe
--------------------------------------------------------------------------------
/.nuget/NuGet.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(MSBuildProjectDirectory)\..\
5 |
6 |
7 | false
8 |
9 |
10 | false
11 |
12 |
13 | true
14 |
15 |
16 | false
17 |
18 |
19 |
20 |
21 |
22 |
26 |
27 |
28 |
29 |
30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget"))
31 |
32 |
33 |
34 |
35 | $(SolutionDir).nuget
36 |
37 |
38 |
39 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName.Replace(' ', '_')).config
40 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName).config
41 |
42 |
43 |
44 | $(MSBuildProjectDirectory)\packages.config
45 | $(PackagesProjectConfig)
46 |
47 |
48 |
49 |
50 | $(NuGetToolsPath)\NuGet.exe
51 | @(PackageSource)
52 |
53 | "$(NuGetExePath)"
54 | mono --runtime=v4.0.30319 "$(NuGetExePath)"
55 |
56 | $(TargetDir.Trim('\\'))
57 |
58 | -RequireConsent
59 | -NonInteractive
60 |
61 | "$(SolutionDir) "
62 | "$(SolutionDir)"
63 |
64 |
65 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir)
66 | $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols
67 |
68 |
69 |
70 | RestorePackages;
71 | $(BuildDependsOn);
72 |
73 |
74 |
75 |
76 | $(BuildDependsOn);
77 | BuildPackage;
78 |
79 |
80 |
81 |
82 |
83 |
84 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
99 |
100 |
103 |
104 |
105 |
106 |
108 |
109 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
141 |
142 |
143 |
144 |
145 |
--------------------------------------------------------------------------------
/Blazer.Benchmark/Blazer.Benchmark.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {C3B4452D-103F-4191-A3FC-7188D7F9D082}
8 | Exe
9 | Properties
10 | Force.Blazer.Benchmark
11 | Blazer.Benchmark
12 | v4.0
13 | 512
14 | ..\
15 | true
16 |
17 |
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 | false
34 |
35 |
36 |
37 |
38 |
39 |
40 | ..\packages\Crc32C.NET.1.0.5.0\lib\net20\Crc32C.NET.dll
41 |
42 |
43 | True
44 | ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll
45 |
46 |
47 | ..\packages\lz4net.1.0.10.93\lib\net4-client\LZ4.dll
48 |
49 |
50 | ..\packages\Snappy.NET.1.1.1.8\lib\net20\Snappy.NET.dll
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | {026EE2B9-3367-480A-8B46-118F4037C827}
69 | Blazer.Net
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
80 |
81 |
82 |
83 |
90 |
--------------------------------------------------------------------------------
/Blazer.Benchmark/MessagesDto/LogMessage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Xml.Serialization;
6 |
7 | namespace Force.Blazer.Benchmark.MessagesDto
8 | {
9 | public class LogMessage
10 | {
11 | public DateTime EventDate { get; set; }
12 |
13 | public string Level { get; set; }
14 |
15 | public string UserName { get; set; }
16 |
17 | public int ProcessingTime { get; set; }
18 |
19 | public string Message { get; set; }
20 |
21 | public LogMessage()
22 | {
23 | }
24 |
25 | public LogMessage(Random r)
26 | {
27 | EventDate = new DateTime(2016, 1, 1).AddSeconds(r.Next(60 * 60 * 24 * 365));
28 | Level = new[] { "DEBUG", "INFO", "WARN", "ERROR", "FATAL" }[r.Next(5)];
29 | if (r.Next(2) == 0) UserName = "System";
30 | else UserName = _words[r.Next(_words.Length)];
31 | ProcessingTime = r.Next(1000);
32 | Message = string.Join(" ", Enumerable.Range(0, r.Next(10) + 3).Select(x => _words[r.Next(_words.Length)]));
33 | }
34 |
35 | private static readonly string[] _words;
36 |
37 | static LogMessage()
38 | {
39 | var r = new Random(124);
40 | _words =
41 | Enumerable.Range(0, 1000)
42 | .Select(_ => new string(Enumerable.Range(0, r.Next(6) + 1).Select(x => (char)(r.Next(26) + 'a')).ToArray())).ToArray();
43 | }
44 |
45 | public static byte[][] Generate(int count)
46 | {
47 | // fixed seed
48 | var r = new Random(124);
49 | var l = new List();
50 | for (var i = 0; i < count; i++)
51 | l.Add(new LogMessage(r));
52 |
53 | var l2 = new List();
54 | var s = new XmlSerializer(typeof(LogMessage));
55 | for (var i = 0; i < count; i++)
56 | {
57 | var ms = new MemoryStream();
58 | s.Serialize(ms, l[i]);
59 | l2.Add(ms.ToArray());
60 | }
61 |
62 | return l2.ToArray();
63 | }
64 |
65 | public static byte[] GenerateBestPattern()
66 | {
67 | var m = new LogMessage
68 | {
69 | EventDate = new DateTime(2016, 1, 1),
70 | Level = "DEBUGINFOWARNERRORFATAL",
71 | UserName = "System",
72 | Message = string.Join(string.Empty, _words)
73 | };
74 |
75 | var s = new XmlSerializer(typeof(LogMessage));
76 | var ms = new MemoryStream();
77 | s.Serialize(ms, m);
78 | return ms.ToArray();
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Blazer.Benchmark/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Blazer.Benchmark")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Blazer.Benchmark")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("e9830f12-fe45-48a2-80e5-a09b7ddef86b")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Blazer.Benchmark/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Blazer.Core.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2012
4 | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Blazer.Net", "Blazer.Net\Blazer.Net.xproj", "{1697F214-4621-4366-8313-CF729755BBDF}"
5 | EndProject
6 | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Blazer.Net.Tests", "Blazer.Net.Tests\Blazer.Net.Tests.xproj", "{C4BF2879-8EF2-49E5-B168-4C45BA895EEE}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {1697F214-4621-4366-8313-CF729755BBDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {1697F214-4621-4366-8313-CF729755BBDF}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {1697F214-4621-4366-8313-CF729755BBDF}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {1697F214-4621-4366-8313-CF729755BBDF}.Release|Any CPU.Build.0 = Release|Any CPU
18 | {C4BF2879-8EF2-49E5-B168-4C45BA895EEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {C4BF2879-8EF2-49E5-B168-4C45BA895EEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {C4BF2879-8EF2-49E5-B168-4C45BA895EEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {C4BF2879-8EF2-49E5-B168-4C45BA895EEE}.Release|Any CPU.Build.0 = Release|Any CPU
22 | EndGlobalSection
23 | EndGlobal
24 |
--------------------------------------------------------------------------------
/Blazer.Exe/Blazer.Exe.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {D1BE8FC3-7D77-4C08-A0D8-D2399A8D903F}
8 | Exe
9 | Properties
10 | Force.Blazer.Exe
11 | Blazer
12 | v4.0
13 | 512
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 | false
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 | false
35 |
36 |
37 | true
38 |
39 |
40 | ..\public.snk
41 |
42 |
43 | true
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | Resources\Blazer.Net.dll
68 |
69 |
70 |
71 |
72 | {026EE2B9-3367-480A-8B46-118F4037C827}
73 | Blazer.Net
74 |
75 |
76 |
77 |
78 | public.snk
79 |
80 |
81 |
82 |
83 | echo del /q $(TargetDir)Blazer.Net.*
84 | cmd /c if exist "$(ProjectDir)sign.cmd" "$(ProjectDir)sign.cmd" "$(TargetPath)" "$(SolutionDir)private.snk"
85 |
86 |
93 |
--------------------------------------------------------------------------------
/Blazer.Exe/CommandLine/BlazerCommandLineOptions.cs:
--------------------------------------------------------------------------------
1 | namespace Force.Blazer.Exe.CommandLine
2 | {
3 | [CommandLineDescription("Usage: Blazer.exe [options] [archiveName.blz] sourceFile|@fileList")]
4 | public class BlazerCommandLineOptions
5 | {
6 | [CommandLineOption('h', "help", "Display this help")]
7 | public bool Help { get; set; }
8 |
9 | [CommandLineOption('d', "decompress", "Decompress archive")]
10 | public bool Decompress { get; set; }
11 |
12 | [CommandLineOption('l', "list", "List content of archive")]
13 | public bool List { get; set; }
14 |
15 | [CommandLineOption('t', "test", "Test archive")]
16 | public bool Test { get; set; }
17 |
18 | [CommandLineOption('f', "force", "Overwrite target files without confirmation")]
19 | public bool Force { get; set; }
20 |
21 | [CommandLineOption("stdin", "Read data from stdin")]
22 | public bool Stdin { get; set; }
23 |
24 | [CommandLineOption("stdout", "Write data to stdout")]
25 | public bool Stdout { get; set; }
26 |
27 | [CommandLineOption('p', "password", "Archive password")]
28 | public string Password { get; set; }
29 |
30 | [CommandLineOption("encyptfull", "Encrypt archive fully (this key required on decompress)")]
31 | public bool EncryptFull { get; set; }
32 |
33 | [CommandLineOption("nofilename", "Do not (re)store file name")]
34 | public bool NoFileName { get; set; }
35 |
36 | [CommandLineOption("nopathname", "Do not (re)store information about paths")]
37 | public bool NoPathName { get; set; }
38 |
39 | [CommandLineOption("mode", "Compression mode: none, block (default), stream, streamhigh")]
40 | public string Mode { get; set; }
41 |
42 | [CommandLineOption("maxblocksize", "Specifies maximum size of data chunk")]
43 | public string MaxBlockSize { get; set; }
44 |
45 | [CommandLineOption("dataarray", "Compress to solid array with 4-bytes length prefix")]
46 | public bool DataArray { get; set; }
47 |
48 | [CommandLineOption("comment", "Add comment to archive")]
49 | public string Comment { get; set; }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Blazer.Exe/CommandLine/CommandLineDescriptionAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Force.Blazer.Exe.CommandLine
4 | {
5 | [AttributeUsage(AttributeTargets.Class)]
6 | public class CommandLineDescriptionAttribute : Attribute
7 | {
8 | public string Description { get; set; }
9 |
10 | public CommandLineDescriptionAttribute(string description)
11 | {
12 | Description = description;
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Blazer.Exe/CommandLine/CommandLineOptionAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Force.Blazer.Exe.CommandLine
4 | {
5 | [AttributeUsage(AttributeTargets.Property)]
6 | public class CommandLineOptionAttribute : Attribute
7 | {
8 | public char ShortKey { get; set; }
9 |
10 | public string LongKey { get; set; }
11 |
12 | public string Description { get; set; }
13 |
14 | public CommandLineOptionAttribute(char shortKey, string longKey, string description)
15 | {
16 | ShortKey = shortKey;
17 | LongKey = longKey;
18 | Description = description;
19 | }
20 |
21 | public CommandLineOptionAttribute(string longKey, string description)
22 | {
23 | LongKey = longKey;
24 | Description = description;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Blazer.Exe/CommandLine/CommandLineParser.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Globalization;
5 | using System.Linq;
6 | using System.Reflection;
7 | using System.Text;
8 |
9 | namespace Force.Blazer.Exe.CommandLine
10 | {
11 | public class CommandLineParser where T : new()
12 | {
13 | private T _options;
14 |
15 | private List _nonKeyOptions;
16 |
17 | private bool _hasAnyOptions;
18 |
19 | public CommandLineParser(string[] args)
20 | {
21 | ParseArgumentsInternal(args);
22 | }
23 |
24 | private void ParseArgumentsInternal(string[] args)
25 | {
26 | var t = new T();
27 |
28 | _hasAnyOptions = args.Length > 0;
29 |
30 | var knownOptions =
31 | typeof(T).GetProperties()
32 | .Select(x => new Tuple(x, (CommandLineOptionAttribute)x.GetCustomAttributes(typeof(CommandLineOptionAttribute), true).FirstOrDefault()))
33 | .Where(x => x.Item2 != null)
34 | .ToArray();
35 |
36 | var boolOptions =
37 | knownOptions.Where(x => x.Item1.PropertyType == typeof(bool) || x.Item1.PropertyType == typeof(bool?)).ToArray();
38 |
39 | Action throwError = e => { throw new InvalidOperationException("Invalid commandline argument " + e); };
40 | var dict = new Dictionary();
41 | var list = new List();
42 | string key = null;
43 | foreach (var arg in args)
44 | {
45 | if (arg.Length > 0)
46 | {
47 | if (arg[0] == '-')
48 | {
49 | if (arg.Length == 1) throwError(arg);
50 | if (arg[1] == '-')
51 | {
52 | if (arg[1] == '-' && arg.Length <= 3) throwError(arg);
53 | if (key != null) dict[key] = string.Empty;
54 | key = arg.Remove(0, 2);
55 | }
56 | else
57 | {
58 | key = arg.Remove(0, 1);
59 | }
60 |
61 | dict[key] = string.Empty;
62 | }
63 | else
64 | {
65 | if (boolOptions.Any(x => x.Item2.ShortKey.ToString(CultureInfo.InvariantCulture) == key || x.Item2.LongKey == key)) key = null;
66 | if (key == null)
67 | {
68 | list.Add(arg);
69 | }
70 | else
71 | {
72 | dict[key] = arg;
73 | key = null;
74 | }
75 | }
76 | }
77 | }
78 |
79 | _nonKeyOptions = list;
80 |
81 | foreach (var v in dict)
82 | {
83 | var option = knownOptions.FirstOrDefault(
84 | x => x.Item2.ShortKey.ToString(CultureInfo.InvariantCulture) == v.Key || x.Item2.LongKey == v.Key);
85 | if (option != null)
86 | {
87 | if (boolOptions.Contains(option))
88 | {
89 | option.Item1.SetValue(t, true, null);
90 | }
91 | else
92 | {
93 | var converted = new TypeConverter().ConvertTo(v.Value, option.Item1.PropertyType);
94 | option.Item1.SetValue(t, converted, null);
95 | }
96 | }
97 | }
98 |
99 | _options = t;
100 | }
101 |
102 | public T Get()
103 | {
104 | return _options;
105 | }
106 |
107 | public string[] GetNonParamOptions()
108 | {
109 | return _nonKeyOptions.ToArray();
110 | }
111 |
112 | public string GetNonParamOptions(int idx)
113 | {
114 | if (_nonKeyOptions.Count <= idx) return null;
115 | return _nonKeyOptions[idx];
116 | }
117 |
118 | public string GenerateHelp()
119 | {
120 | var headerAttribute = (CommandLineDescriptionAttribute)typeof(T).GetCustomAttributes(typeof(CommandLineDescriptionAttribute), true).FirstOrDefault();
121 |
122 | var options = typeof(T).GetProperties()
123 | .Select(x => (CommandLineOptionAttribute)x.GetCustomAttributes(typeof(CommandLineOptionAttribute), true).FirstOrDefault())
124 | .Where(x => x != null)
125 | .ToArray();
126 |
127 | var maxParamLen = 0;
128 |
129 | foreach (var option in options)
130 | {
131 | var cnt = 0;
132 | if (option.ShortKey != default(char) && option.LongKey != null) cnt = 6 + option.LongKey.Length;
133 | else if (option.ShortKey != default(char)) cnt = 2;
134 | else cnt = 2 + option.LongKey.Length;
135 | maxParamLen = Math.Max(maxParamLen, cnt);
136 | }
137 |
138 | var b = new StringBuilder();
139 |
140 | if (headerAttribute != null) b.Append(headerAttribute.Description).AppendLine();
141 |
142 | foreach (var option in options)
143 | {
144 | b.Append("\t");
145 | string str;
146 | if (option.ShortKey != default(char) && option.LongKey != null)
147 | {
148 | str = string.Format("-{0}, --{1}", option.ShortKey, option.LongKey);
149 | }
150 | else if (option.ShortKey != default(char))
151 | {
152 | str = string.Format("-{0}", option.ShortKey);
153 | }
154 | else
155 | {
156 | str = string.Format("--{0}", option.LongKey);
157 | }
158 |
159 | b.Append(str);
160 | b.Append(new string(' ', maxParamLen - str.Length));
161 | b.Append("\t");
162 | b.Append(option.Description);
163 | b.AppendLine();
164 | }
165 |
166 | return b.ToString();
167 | }
168 |
169 | public string GenerateHeader(string additionalVersion)
170 | {
171 | var title = (AssemblyTitleAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), true).First();
172 | var copy = (AssemblyCopyrightAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), true).First();
173 | var version = (AssemblyFileVersionAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyFileVersionAttribute), true).First();
174 |
175 | return string.Format("{0} {2} ({3}) {1}", title.Title, copy.Copyright, version.Version, additionalVersion);
176 | }
177 |
178 | public bool HasAnyOptions()
179 | {
180 | return _hasAnyOptions;
181 | }
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/Blazer.Exe/FileNameHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 |
6 | using Force.Blazer.Exe.CommandLine;
7 |
8 | namespace Force.Blazer.Exe
9 | {
10 | public class FileNameHelper
11 | {
12 | public class FileOptions
13 | {
14 | public string ArchiveName { get; set; }
15 |
16 | public string[] SourceFiles { get; set; }
17 | }
18 |
19 | public static FileOptions ParseCompressOptions(CommandLineParser options)
20 | {
21 | var opt = options.Get();
22 | var nonParamOptions = options.GetNonParamOptions();
23 | if (nonParamOptions.Length == 0 && !opt.Stdout)
24 | {
25 | Console.WriteLine(options.GenerateHelp());
26 | return null;
27 | }
28 |
29 | var listFile = options.GetNonParamOptions().FirstOrDefault(x => x[0] == '@');
30 | if (listFile != null && nonParamOptions.Length != 2 - (opt.Stdout ? 1 : 0))
31 | {
32 | Console.Error.WriteLine("When list file is provided, only archive name is allowed");
33 | return null;
34 | }
35 |
36 | if (listFile != null && opt.Stdin)
37 | {
38 | Console.Error.WriteLine("Stdin is not compatible with list file");
39 | return null;
40 | }
41 |
42 | if (opt.Stdin && nonParamOptions.Length > 1)
43 | {
44 | Console.Error.WriteLine("Stdin is not compatible with multiple files");
45 | return null;
46 | }
47 |
48 | var archiveName = opt.Stdout ? null : nonParamOptions[0];
49 | string[] filesToCompress;
50 |
51 | if (listFile != null)
52 | {
53 | listFile = listFile.Remove(0, 1);
54 | if (!File.Exists(listFile))
55 | {
56 | Console.Error.WriteLine("Invalid list file");
57 | return null;
58 | }
59 |
60 | filesToCompress =
61 | File.ReadAllLines(listFile).Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => x.Trim()).ToArray();
62 | }
63 | else
64 | {
65 | filesToCompress = opt.Stdin ? new string[0] : nonParamOptions.Skip(1).ToArray();
66 |
67 | if (filesToCompress.Length == 0 && archiveName != null && !opt.Stdin) filesToCompress = new[] { archiveName };
68 | if (!opt.Stdin)
69 | {
70 | /*if (filesToCompress.Length == 1 && Directory.Exists(filesToCompress[0]))
71 | filesToCompress = Directory.GetFiles(filesToCompress[0], "*", SearchOption.AllDirectories);
72 | else*/
73 | filesToCompress = filesToCompress.SelectMany(x => Directory.Exists(x) ? Directory.GetFiles(x, "*", SearchOption.AllDirectories) : new[] { x }).ToArray();
74 | }
75 | }
76 |
77 | bool hasMissingFiles;
78 | filesToCompress = ExpandFilesInList(filesToCompress, out hasMissingFiles);
79 |
80 | if (hasMissingFiles)
81 | {
82 | Console.Error.WriteLine("One or more of files to compress does not exist");
83 | return null;
84 | }
85 |
86 | if (archiveName != null && !archiveName.EndsWith(".blz")) archiveName += ".blz";
87 |
88 | return new FileOptions
89 | {
90 | ArchiveName = archiveName,
91 | SourceFiles = filesToCompress
92 | };
93 | }
94 |
95 | public static FileOptions ParseDecompressOptions(CommandLineParser options)
96 | {
97 | var opt = options.Get();
98 |
99 | var nonParamOptions = options.GetNonParamOptions();
100 |
101 | if (!opt.Stdin && nonParamOptions.Length == 0)
102 | {
103 | Console.Error.WriteLine("Archive name was not specified");
104 | return null;
105 | }
106 |
107 | var archiveName = opt.Stdin ? null : nonParamOptions[0];
108 |
109 | if (archiveName != null && !File.Exists(archiveName))
110 | {
111 | Console.Error.WriteLine("Archive file " + archiveName + " does not exist");
112 | return null;
113 | }
114 |
115 | var listFile = options.GetNonParamOptions().FirstOrDefault(x => x[0] == '@');
116 | if (listFile != null && nonParamOptions.Length != 2 - (opt.Stdin ? 1 : 0))
117 | {
118 | Console.Error.WriteLine("When list file is provided, only archive name is allowed");
119 | return null;
120 | }
121 |
122 | string[] customOutFileNames = null;
123 |
124 | if (listFile != null)
125 | {
126 | listFile = listFile.Remove(0, 1);
127 | if (!File.Exists(listFile))
128 | {
129 | Console.Error.WriteLine("Invalid list file");
130 | return null;
131 | }
132 |
133 | customOutFileNames = File.ReadAllLines(listFile).Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => x.Trim()).ToArray();
134 | }
135 | else
136 | {
137 | customOutFileNames = nonParamOptions.Skip(opt.Stdin ? 0 : 1).ToArray();
138 | }
139 |
140 | return new FileOptions
141 | {
142 | ArchiveName = archiveName,
143 | SourceFiles = customOutFileNames
144 | };
145 | }
146 |
147 | private static string[] ExpandFilesInList(string[] initialFiles, out bool hasMissingFiles)
148 | {
149 | hasMissingFiles = false;
150 | var l = new List();
151 | // todo: better search + unit tests
152 | foreach (var s in initialFiles)
153 | {
154 | if (File.Exists(s))
155 | l.Add(s);
156 | else if (Directory.Exists(s)) l.Add(s);
157 | else
158 | {
159 | var asteriskIdx = s.IndexOf("*", StringComparison.InvariantCulture);
160 | if (asteriskIdx < 0) hasMissingFiles = true;
161 | else
162 | {
163 | var slashIdx = asteriskIdx > 0 ? s.LastIndexOfAny(
164 | new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }, asteriskIdx - 1, asteriskIdx - 1) : -1;
165 | var dirToSearch = ".";
166 | if (slashIdx >= 0) dirToSearch = s.Substring(0, slashIdx);
167 | l.AddRange(Directory.GetFiles(dirToSearch, s.Remove(0, slashIdx + 1), SearchOption.AllDirectories));
168 | }
169 | }
170 | }
171 |
172 | return l.ToArray();
173 | }
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/Blazer.Exe/NullStream.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace Force.Blazer.Exe
4 | {
5 | public class NullStream : Stream
6 | {
7 | public override void Flush()
8 | {
9 | }
10 |
11 | public override long Seek(long offset, SeekOrigin origin)
12 | {
13 | return -1;
14 | }
15 |
16 | public override void SetLength(long value)
17 | {
18 | }
19 |
20 | public override int Read(byte[] buffer, int offset, int count)
21 | {
22 | return 0;
23 | }
24 |
25 | public override void Write(byte[] buffer, int offset, int count)
26 | {
27 | }
28 |
29 | public override bool CanRead
30 | {
31 | get
32 | {
33 | return true;
34 | }
35 | }
36 |
37 | public override bool CanSeek
38 | {
39 | get
40 | {
41 | return true;
42 | }
43 | }
44 |
45 | public override bool CanWrite
46 | {
47 | get
48 | {
49 | return true;
50 | }
51 | }
52 |
53 | public override long Length
54 | {
55 | get
56 | {
57 | return -1;
58 | }
59 | }
60 |
61 | public override long Position
62 | {
63 | get
64 | {
65 | return -1;
66 | }
67 |
68 | set
69 | {
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Blazer.Exe/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // General Information about an assembly is controlled through the following
5 | // set of attributes. Change these attribute values to modify the information
6 | // associated with an assembly.
7 | [assembly: AssemblyTitle("Blazer")]
8 | [assembly: AssemblyDescription("Blazer archiver")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("Force")]
11 | [assembly: AssemblyProduct("Blazer Archiver")]
12 | [assembly: AssemblyCopyright("Copyright by Force 2016-2017")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // Setting ComVisible to false makes the types in this assembly not visible
17 | // to COM components. If you need to access a type in this assembly from
18 | // COM, set the ComVisible attribute to true on that type.
19 | [assembly: ComVisible(false)]
20 |
21 | // The following GUID is for the ID of the typelib if this project is exposed to COM
22 | [assembly: Guid("a1bb1e2e-ec84-48dd-88b0-ff82b75417cd")]
23 |
24 | // Version information for an assembly consists of the following four values:
25 | //
26 | // Major Version
27 | // Minor Version
28 | // Build Number
29 | // Revision
30 | //
31 | // You can specify all the values or you can default the Build and Revision Numbers
32 | // by using the '*' as shown below:
33 | // [assembly: AssemblyVersion("1.0.*")]
34 | [assembly: AssemblyVersion("0.10.0.0")]
35 | [assembly: AssemblyFileVersion("0.10.0.13")]
36 |
--------------------------------------------------------------------------------
/Blazer.Exe/StatStream.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 |
5 | namespace Force.Blazer.Exe
6 | {
7 | public class StatStream : Stream
8 | {
9 | private readonly Stream _baseStream;
10 |
11 | private long _totalHandled;
12 |
13 | private readonly bool _doStats;
14 |
15 | private readonly long _totalLength;
16 |
17 | private int prevPcnt = -1;
18 |
19 | private readonly Stopwatch _sw = new Stopwatch();
20 |
21 | public string Prefix { get; set; }
22 |
23 | public StatStream(Stream baseStream, bool doStats = false)
24 | {
25 | _baseStream = baseStream;
26 | _doStats = doStats;
27 | if (doStats)
28 | {
29 | _totalLength = baseStream.CanSeek ? baseStream.Length : -1;
30 | _sw.Start();
31 | }
32 | }
33 |
34 | public override void Close()
35 | {
36 | _baseStream.Close();
37 | if (_doStats)
38 | {
39 | DoStats();
40 | if (_sw.ElapsedMilliseconds > 0)
41 | Console.WriteLine();
42 | }
43 | }
44 |
45 | public override void Flush()
46 | {
47 | _baseStream.Flush();
48 | }
49 |
50 | public override long Seek(long offset, SeekOrigin origin)
51 | {
52 | return _baseStream.Seek(offset, origin);
53 | }
54 |
55 | public override void SetLength(long value)
56 | {
57 | _baseStream.SetLength(value);
58 | }
59 |
60 | public override int Read(byte[] buffer, int offset, int count)
61 | {
62 | var readed = _baseStream.Read(buffer, offset, count);
63 | _totalHandled += readed;
64 | if (_doStats)
65 | {
66 | DoStats();
67 | }
68 |
69 | return readed;
70 | }
71 |
72 | private void DoStats()
73 | {
74 | var elapsed = _sw.ElapsedMilliseconds;
75 | if (elapsed == 0)
76 | return;
77 | if (_totalLength > 0)
78 | {
79 | var pcnt = 10000 * _totalHandled / _totalLength;
80 | var pcntAdj = (int)(pcnt / 100);
81 | if (pcntAdj != prevPcnt && pcnt > 0)
82 | {
83 | var eta = (10000 * elapsed / pcnt) - elapsed;
84 | Console.Write(
85 | "\r{3}{0,3}% ETA: {1} {2}MB/s ",
86 | pcntAdj,
87 | TimeSpan.FromMilliseconds(eta).ToString(@"hh\:mm\:ss"),
88 | _totalHandled / 1048 / elapsed,
89 | Prefix);
90 | prevPcnt = pcntAdj;
91 | }
92 | }
93 | else
94 | {
95 | Console.Write("\r{2}Processed {0,3}MB {1}MB/s ", _totalHandled / 1048576, _totalHandled / 1048 / elapsed, Prefix);
96 | }
97 | }
98 |
99 | public override void Write(byte[] buffer, int offset, int count)
100 | {
101 | _baseStream.Write(buffer, offset, count);
102 | _totalHandled += count;
103 | if (_doStats)
104 | {
105 | DoStats();
106 | }
107 | }
108 |
109 | public override bool CanRead
110 | {
111 | get
112 | {
113 | return _baseStream.CanRead;
114 | }
115 | }
116 |
117 | public override bool CanSeek
118 | {
119 | get
120 | {
121 | return _baseStream.CanSeek;
122 | }
123 | }
124 |
125 | public override bool CanWrite
126 | {
127 | get
128 | {
129 | return _baseStream.CanWrite;
130 | }
131 | }
132 |
133 | public override long Length
134 | {
135 | get
136 | {
137 | return _baseStream.Length;
138 | }
139 | }
140 |
141 | public override long Position
142 | {
143 | get
144 | {
145 | return _baseStream.Position;
146 | }
147 |
148 | set
149 | {
150 | _baseStream.Position = value;
151 | }
152 | }
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/Blazer.Native.Build/Blazer.Native.x64.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/force-net/blazer/5520e017a2f5d1b55f5ab978036b138faa765e38/Blazer.Native.Build/Blazer.Native.x64.dll
--------------------------------------------------------------------------------
/Blazer.Native.Build/Blazer.Native.x86.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/force-net/blazer/5520e017a2f5d1b55f5ab978036b138faa765e38/Blazer.Native.Build/Blazer.Native.x86.dll
--------------------------------------------------------------------------------
/Blazer.Native/.gitignore:
--------------------------------------------------------------------------------
1 | # todo remove this folders from config
2 | Debug
3 | Release
4 | Win32
5 | Win32Debug
6 | x64
--------------------------------------------------------------------------------
/Blazer.Native/Blazer.Native.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Header Files
20 |
21 |
22 | Header Files
23 |
24 |
25 | Header Files
26 |
27 |
28 |
29 |
30 | Source Files
31 |
32 |
33 | Source Files
34 |
35 |
36 | Source Files
37 |
38 |
39 | Source Files
40 |
41 |
42 | Source Files
43 |
44 |
45 | Source Files
46 |
47 |
48 |
49 |
50 | Resource Files
51 |
52 |
53 |
--------------------------------------------------------------------------------
/Blazer.Native/Blazer.cpp:
--------------------------------------------------------------------------------
1 | // Blazer.cpp : Defines the exported functions for the DLL application.
2 | //
3 |
4 | #include "stdafx.h"
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Blazer.Native/Blazer.rc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/force-net/blazer/5520e017a2f5d1b55f5ab978036b138faa765e38/Blazer.Native/Blazer.rc
--------------------------------------------------------------------------------
/Blazer.Native/build.cmd:
--------------------------------------------------------------------------------
1 | C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe /t:Rebuild /p:Configuration=Release /p:Platform=x64 "/p:VCTargetsPath=C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V110\"
2 | C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe /t:Rebuild /p:Configuration=Release /p:Platform=Win32 "/p:VCTargetsPath=C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V110\"
3 | xcopy /y Release\Blazer.Native.x86.dll ..\Blazer.Native.Build\
4 | xcopy /y Release\Blazer.Native.x64.dll ..\Blazer.Native.Build\
5 |
6 | del /s /q %temp%\Blazer.Net.0.8.2.8
--------------------------------------------------------------------------------
/Blazer.Native/dllmain.cpp:
--------------------------------------------------------------------------------
1 | // dllmain.cpp : Defines the entry point for the DLL application.
2 | #include "stdafx.h"
3 |
4 | static char* _dummy = "Blazer archiver by Force";
5 |
6 | void _crc32c_init();
7 |
8 | BOOL APIENTRY DllMain(HMODULE hModule,
9 | DWORD ul_reason_for_call,
10 | LPVOID lpReserved
11 | )
12 | {
13 | _crc32c_init();
14 | if (_dummy == 0)
15 | return FALSE;
16 | /*switch (ul_reason_for_call)
17 | {
18 | case DLL_PROCESS_ATTACH:
19 | case DLL_THREAD_ATTACH:
20 | case DLL_THREAD_DETACH:
21 | case DLL_PROCESS_DETACH:
22 | break;
23 | }*/
24 | return TRUE;
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/Blazer.Native/resource.h:
--------------------------------------------------------------------------------
1 | //{{NO_DEPENDENCIES}}
2 | // Microsoft Visual C++ generated include file.
3 | // Used by Blazer.rc
4 |
5 | // Next default values for new objects
6 | //
7 | #ifdef APSTUDIO_INVOKED
8 | #ifndef APSTUDIO_READONLY_SYMBOLS
9 | #define _APS_NEXT_RESOURCE_VALUE 101
10 | #define _APS_NEXT_COMMAND_VALUE 40001
11 | #define _APS_NEXT_CONTROL_VALUE 1001
12 | #define _APS_NEXT_SYMED_VALUE 101
13 | #endif
14 | #endif
15 |
--------------------------------------------------------------------------------
/Blazer.Native/stdafx.cpp:
--------------------------------------------------------------------------------
1 | // stdafx.cpp : source file that includes just the standard includes
2 | // Blazer.pch will be the pre-compiled header
3 | // stdafx.obj will contain the pre-compiled type information
4 |
5 | #include "stdafx.h"
6 |
7 | // TODO: reference any additional headers you need in STDAFX.H
8 | // and not in this file
9 |
--------------------------------------------------------------------------------
/Blazer.Native/stdafx.h:
--------------------------------------------------------------------------------
1 | // stdafx.h : include file for standard system include files,
2 | // or project specific include files that are used frequently, but
3 | // are changed infrequently
4 | //
5 |
6 | #pragma once
7 |
8 | #include "targetver.h"
9 |
10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
11 | // Windows Header Files:
12 | #include
13 |
14 |
15 |
16 | // TODO: reference additional headers your program requires here
17 |
--------------------------------------------------------------------------------
/Blazer.Native/targetver.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Including SDKDDKVer.h defines the highest available Windows platform.
4 |
5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
7 |
8 | #include
9 |
--------------------------------------------------------------------------------
/Blazer.Net.Tests/BigDataTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 |
5 | using Force.Blazer;
6 |
7 | using NUnit.Framework;
8 |
9 | namespace Blazer.Net.Tests
10 | {
11 | [TestFixture]
12 | public class BigDataTests
13 | {
14 | [Test]
15 | [Ignore("Slow for usual run")]
16 | public void Large_Data_Should_Be_Compressed()
17 | {
18 | var outs = new MemoryStream();
19 | // stream algorithm is affected to big data (requires backref shift)
20 | var blazerCompressionOptions = BlazerCompressionOptions.CreateStream();
21 | blazerCompressionOptions.LeaveStreamOpen = true;
22 | var comp = new BlazerInputStream(outs, blazerCompressionOptions);
23 | const int BufSize = 200000;
24 | var buf = new byte[BufSize];
25 | long totalSize = 1L << 32; // 4Gb
26 | var iterations = totalSize / buf.Length;
27 | totalSize = iterations * buf.Length;
28 | for (var i = 0; i < iterations; i++)
29 | {
30 | var v = i % 256;
31 | for (var k = 0; k < buf.Length; k++) buf[k] = (byte)v;
32 | comp.Write(buf, 0, buf.Length);
33 | }
34 |
35 | comp.Close();
36 |
37 | Debug.WriteLine("Compressed. " + outs.Length);
38 |
39 | outs.Seek(0, SeekOrigin.Begin);
40 | var decomp = new BlazerOutputStream(outs);
41 | long totalPos = 0;
42 | while (true)
43 | {
44 | var readed = decomp.Read(buf, 0, buf.Length);
45 | if (readed == 0) break;
46 | for (var i = 0; i < readed; i++)
47 | {
48 | long v = (totalPos / BufSize) % 256;
49 | if (buf[i] != v)
50 | throw new ArgumentException("Invalid data at " + totalPos + ". Expected: " + v + ", but was: " + buf[i]);
51 | totalPos++;
52 | }
53 | }
54 |
55 | Assert.That(totalPos, Is.EqualTo(totalSize));
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Blazer.Net.Tests/Blazer.Net.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {7C1D5EDB-476B-453F-A7EE-E4E8CB8AB2CF}
8 | Library
9 | Properties
10 | Blazer.Net.Tests
11 | Blazer.Net.Tests
12 | v4.0
13 | 512
14 | ..\
15 | true
16 |
17 |
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 | ..\packages\Crc32.NET.1.1.0\lib\net20\Crc32.NET.dll
37 | True
38 |
39 |
40 | ..\packages\Crc32C.NET.1.0.5.0\lib\net20\Crc32C.NET.dll
41 |
42 |
43 | ..\packages\NUnit.3.4.0\lib\net40\nunit.framework.dll
44 | True
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | {026EE2B9-3367-480A-8B46-118F4037C827}
75 | Blazer.Net
76 |
77 |
78 |
79 |
80 |
81 |
82 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
83 |
84 |
85 |
86 |
93 |
--------------------------------------------------------------------------------
/Blazer.Net.Tests/Blazer.Net.Tests.xproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 14.0
5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0
6 |
7 |
8 |
9 |
10 | {C4BF2879-8EF2-49E5-B168-4C45BA895EEE}
11 | Blazer.Net.Tests
12 | .\obj
13 | .\bin\
14 | v4.6.1
15 |
16 |
17 |
18 | 2.0
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Blazer.Net.Tests/Crc32Tests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Text;
4 |
5 | using Force.Crc32;
6 | using NUnit.Framework;
7 |
8 | using E = Force.Blazer.Algorithms.Crc32C.Crc32C;
9 |
10 | namespace Blazer.Net.Tests
11 | {
12 | [TestFixture]
13 | public class Crc32Tests
14 | {
15 | [TestCase("Hello", 3)]
16 | [TestCase("Nazdar", 0)]
17 | [TestCase("Ahoj", 1)]
18 | [TestCase("Very long text.Very long text.Very long text.Very long text.Very long text.Very long text.Very long text", 0)]
19 | [TestCase("Very long text.Very long text.Very long text.Very long text.Very long text.Very long text.Very long text", 3)]
20 | public void ResultConsistency(string text, int offset)
21 | {
22 | var bytes = Encoding.ASCII.GetBytes(text);
23 |
24 | var crc1 = E.Calculate(bytes.Skip(offset).ToArray());
25 | var crc2 = Crc32CAlgorithm.Append(0, bytes, offset, bytes.Length - offset);
26 | Assert.That(crc2, Is.EqualTo(crc1));
27 | }
28 |
29 | [Test]
30 | public void ResultConsistencyLong()
31 | {
32 | var bytes = new byte[30000];
33 | new Random().NextBytes(bytes);
34 | var crc1 = E.Calculate(bytes, 0, bytes.Length);
35 | var crc2 = Crc32CAlgorithm.Append(0, bytes, 0, bytes.Length);
36 | Assert.That(crc2, Is.EqualTo(crc1));
37 | }
38 |
39 | [Test]
40 | public void ResultConsistency2()
41 | {
42 | Assert.That(E.Calculate(new byte[] { 1 }), Is.EqualTo(Crc32CAlgorithm.Compute(new byte[] { 1 })));
43 | Assert.That(E.Calculate(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }), Is.EqualTo(Crc32CAlgorithm.Compute(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 })));
44 | }
45 |
46 | [Test]
47 | public void PartIsWhole()
48 | {
49 | var bytes = new byte[30000];
50 | new Random().NextBytes(bytes);
51 | var r1 = E.Calculate(0, bytes, 0, 15000);
52 | var r2 = E.Calculate(r1, bytes, 15000, 15000);
53 | var r3 = E.Calculate(0, bytes, 0, 30000);
54 | Assert.That(r2, Is.EqualTo(r3));
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Blazer.Net.Tests/DataArrayTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 |
4 | using Force.Blazer;
5 | using Force.Blazer.Algorithms;
6 | using Force.Blazer.Helpers;
7 | using Force.Blazer.Native;
8 |
9 | using NUnit.Framework;
10 |
11 | namespace Blazer.Net.Tests
12 | {
13 | [TestFixture]
14 | public class DataArrayTests
15 | {
16 | [Test]
17 | public void Stream_Encode_Decode_Should_Not_Resize_Array()
18 | {
19 | var bufferIn = new byte[] { 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4 };
20 | var compr = StreamEncoder.CompressData(bufferIn);
21 | var bufferOut = new byte[bufferIn.Length];
22 | var cnt = StreamDecoder.DecompressBlockExternal(compr, 0, compr.Length, ref bufferOut, 0, bufferOut.Length, false);
23 | Assert.That(cnt, Is.EqualTo(bufferIn.Length));
24 | CollectionAssert.AreEqual(bufferIn, bufferOut);
25 | }
26 |
27 | [Test]
28 | [TestCase(typeof(BlockEncoder), typeof(BlockDecoder))]
29 | [TestCase(typeof(BlockEncoderNative), typeof(BlockDecoderNative))]
30 | public void Block_Encode_Decode_Should_Not_Resize_Array(Type encoderType, Type decoderType)
31 | {
32 | // ensuring native is inited
33 | NativeHelper.SetNativeImplementation(true);
34 | var bufferIn = new byte[] { 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4 };
35 | var encoder = (BlockEncoder)Activator.CreateInstance(encoderType);
36 | encoder.Init(bufferIn.Length);
37 | var compr = new byte[bufferIn.Length];
38 | var comprCnt = encoder.CompressBlock(bufferIn, 0, bufferIn.Length, compr, 0, true);
39 | Console.WriteLine(comprCnt);
40 |
41 | var bufferOut = new byte[bufferIn.Length];
42 | var decoder = (BlockDecoder)Activator.CreateInstance(decoderType);
43 | decoder.Init(bufferIn.Length);
44 | var cnt = decoder.DecompressBlock(compr, 0, comprCnt, bufferOut, 0, bufferOut.Length, true);
45 | Assert.That(cnt, Is.EqualTo(bufferIn.Length));
46 | CollectionAssert.AreEqual(bufferIn, bufferOut);
47 | }
48 |
49 | [Test]
50 | [TestCase(typeof(StreamEncoder), typeof(StreamDecoder))]
51 | [TestCase(typeof(StreamEncoderNative), typeof(StreamDecoderNative))]
52 | [TestCase(typeof(StreamEncoderHigh), typeof(StreamDecoder))]
53 | public void Stream_Encode_Decode_Should_Not_Resize_Array(Type encoderType, Type decoderType)
54 | {
55 | // ensuring native is inited
56 | NativeHelper.SetNativeImplementation(true);
57 | var bufferIn = new byte[] { 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4 };
58 | var encoder = (StreamEncoder)Activator.CreateInstance(encoderType);
59 | encoder.Init(bufferIn.Length);
60 | var compr = new byte[bufferIn.Length];
61 | var comprCnt = encoder.CompressBlock(bufferIn, 0, bufferIn.Length, 0, compr, 0);
62 | Console.WriteLine(comprCnt);
63 |
64 | var bufferOut = new byte[bufferIn.Length];
65 | var decoder = (StreamDecoder)Activator.CreateInstance(decoderType);
66 | decoder.Init(bufferIn.Length);
67 | var cnt = decoder.DecompressBlock(compr, 0, comprCnt, bufferOut, 0, bufferOut.Length);
68 | Assert.That(cnt, Is.EqualTo(bufferIn.Length));
69 | CollectionAssert.AreEqual(bufferIn, bufferOut);
70 | }
71 |
72 | [Test]
73 | [TestCase(BlazerAlgorithm.NoCompress)]
74 | [TestCase(BlazerAlgorithm.Block)]
75 | [TestCase(BlazerAlgorithm.Stream)]
76 | public void DataArrayCompressionHelper_Should_Encode_Decode(BlazerAlgorithm algorithm)
77 | {
78 | var bufferIn = new byte[] { 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4 };
79 | var arr = DataArrayCompressorHelper.CompressDataToArray(bufferIn, EncoderDecoderFactory.GetEncoder(algorithm));
80 | var bufferOut = DataArrayCompressorHelper.DecompressDataArray(arr, EncoderDecoderFactory.GetDecoder(algorithm));
81 | CollectionAssert.AreEqual(bufferIn, bufferOut);
82 | }
83 |
84 | [Test]
85 | [TestCase(BlazerAlgorithm.NoCompress)]
86 | [TestCase(BlazerAlgorithm.Block)]
87 | [TestCase(BlazerAlgorithm.Stream)]
88 | public void DataArrayCompressionHelper_Should_Encode_Decode_With_Offset(BlazerAlgorithm algorithm)
89 | {
90 | var bufferIn = new byte[] { 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4 };
91 | var arr = DataArrayCompressorHelper.CompressDataToArray(bufferIn, 1, bufferIn.Length - 2, EncoderDecoderFactory.GetEncoder(algorithm));
92 | var dupArray = new byte[arr.Length + 10];
93 | Buffer.BlockCopy(arr, 0, dupArray, 2, arr.Length);
94 | var bufferOut = DataArrayCompressorHelper.DecompressDataArray(dupArray, 2, arr.Length, EncoderDecoderFactory.GetDecoder(algorithm));
95 | CollectionAssert.AreEqual(bufferIn.Skip(1).Take(bufferIn.Length - 2).ToArray(), bufferOut);
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Blazer.Net.Tests/IntegrityHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | using Force.Blazer;
5 | using Force.Blazer.Algorithms;
6 |
7 | using NUnit.Framework;
8 |
9 | namespace Blazer.Net.Tests
10 | {
11 | public static class IntegrityHelper
12 | {
13 | public static int CheckCompressDecompress(byte[] inData, BlazerCompressionOptions options, Func decoderCreator = null, int bufferSize = 81920)
14 | {
15 | var compressed = CompressData(inData, options, bufferSize);
16 | var decompressed = DecompressData(compressed, decoderCreator, bufferSize);
17 |
18 | CollectionAssert.AreEqual(inData, decompressed);
19 | return compressed.Length;
20 | }
21 |
22 | public static byte[] CompressData(byte[] inData, BlazerCompressionOptions options, int bufferSize = 81920)
23 | {
24 | var ms1 = new MemoryStream();
25 | var input = new BlazerInputStream(ms1, options);
26 |
27 | new MemoryStream(inData).CopyTo(input, bufferSize);
28 | input.Close();
29 | return ms1.ToArray();
30 | }
31 |
32 | public static byte[] DecompressData(byte[] inData, Func decoderCreator = null, int bufferSize = 81920)
33 | {
34 | var ms3 = new MemoryStream(inData);
35 | var output = decoderCreator != null ? decoderCreator(ms3) : new BlazerOutputStream(ms3);
36 | var ms2 = new MemoryStream();
37 | output.CopyTo(ms2, bufferSize);
38 | output.Close();
39 | return ms2.ToArray();
40 | }
41 |
42 | public static int StreamEncoderCheckCompressDecompress(byte[] inData)
43 | {
44 | var compressed = StreamEncoder.CompressData(inData);
45 | var decompressed = StreamDecoder.DecompressData(compressed);
46 | CollectionAssert.AreEqual(inData, decompressed);
47 | return compressed.Length;
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Blazer.Net.Tests/IntegrityTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Security.Cryptography;
4 | using System.Text;
5 |
6 | using Force.Blazer;
7 |
8 | using NUnit.Framework;
9 |
10 | namespace Blazer.Net.Tests
11 | {
12 | [TestFixture]
13 | public class IntegrityTests
14 | {
15 | [Test]
16 | [TestCase(BlazerAlgorithm.NoCompress)]
17 | [TestCase(BlazerAlgorithm.Stream)]
18 | [TestCase(BlazerAlgorithm.Block)]
19 | public void Simple_Data_Should_Be_Encoded_Decoded(BlazerAlgorithm algorithm)
20 | {
21 | var data = Encoding.UTF8.GetBytes("some compressible not very long string. some some some.");
22 | var blazerCompressionOptions = BlazerCompressionOptions.CreateStream();
23 | blazerCompressionOptions.SetEncoderByAlgorithm(algorithm);
24 | IntegrityHelper.CheckCompressDecompress(data, blazerCompressionOptions);
25 | }
26 |
27 | [Test]
28 | [TestCase(BlazerAlgorithm.NoCompress)]
29 | [TestCase(BlazerAlgorithm.Stream)]
30 | [TestCase(BlazerAlgorithm.Block)]
31 | public void HighCompressible_Data_Should_Be_Encoded_Decoded(BlazerAlgorithm algorithm)
32 | {
33 | var data = new byte[10 * 1048576];
34 | var blazerCompressionOptions = BlazerCompressionOptions.CreateStream();
35 | blazerCompressionOptions.SetEncoderByAlgorithm(algorithm);
36 | IntegrityHelper.CheckCompressDecompress(data, blazerCompressionOptions);
37 | }
38 |
39 | [Test]
40 | [TestCase(BlazerAlgorithm.NoCompress)]
41 | [TestCase(BlazerAlgorithm.Stream)]
42 | [TestCase(BlazerAlgorithm.Block)]
43 | public void NonCompressible_Data_Should_Be_Encoded_Decoded(BlazerAlgorithm algorithm)
44 | {
45 | var data = new byte[1234];
46 | RandomNumberGenerator.Create().GetBytes(data);
47 | var blazerCompressionOptions = BlazerCompressionOptions.CreateStream();
48 | blazerCompressionOptions.SetEncoderByAlgorithm(algorithm);
49 | IntegrityHelper.CheckCompressDecompress(data, blazerCompressionOptions);
50 | }
51 |
52 | [Test]
53 | public void Invalid_Header_Should_Throw_Errors()
54 | {
55 | var data1 = new byte[12];
56 | var compressed = IntegrityHelper.CompressData(data1, BlazerCompressionOptions.CreateStream());
57 | // not blazer archiver
58 | compressed[0]++;
59 | Assert.That(Assert.Throws(() => IntegrityHelper.DecompressData(compressed)).Message, Is.EqualTo("This is not Blazer archive"));
60 | compressed[0]--;
61 |
62 | // invalid version
63 | compressed[3]++;
64 | Assert.That(Assert.Throws(() => IntegrityHelper.DecompressData(compressed)).Message, Is.EqualTo("Stream was created in newer version of Blazer library"));
65 | compressed[3]--;
66 |
67 | // invalid flags
68 | compressed[6] = 0xff;
69 | Assert.That(Assert.Throws(() => IntegrityHelper.DecompressData(compressed)).Message, Is.EqualTo("Invalid flag combination. Try to use newer version of Blazer"));
70 | // compressed[6]--;
71 | }
72 |
73 | [Test]
74 | [TestCase(1, BlazerAlgorithm.NoCompress)]
75 | [TestCase(1, BlazerAlgorithm.Stream)]
76 | [TestCase(1, BlazerAlgorithm.Block)]
77 | [TestCase(2, BlazerAlgorithm.NoCompress)]
78 | [TestCase(2, BlazerAlgorithm.Stream)]
79 | [TestCase(2, BlazerAlgorithm.Block)]
80 | [TestCase(3, BlazerAlgorithm.NoCompress)]
81 | [TestCase(3, BlazerAlgorithm.Stream)]
82 | [TestCase(3, BlazerAlgorithm.Block)]
83 | [TestCase(4, BlazerAlgorithm.NoCompress)]
84 | [TestCase(4, BlazerAlgorithm.Stream)]
85 | [TestCase(4, BlazerAlgorithm.Block)]
86 | public void Small_Block_Sizes_ShouldBe_Handled_WithoutFlush(int blockSize, BlazerAlgorithm algorithm)
87 | {
88 | var data = new byte[blockSize];
89 | data[0] = (byte)blockSize;
90 | var blazerCompressionOptions = BlazerCompressionOptions.CreateStream();
91 | blazerCompressionOptions.SetEncoderByAlgorithm(algorithm);
92 |
93 | var memoryStream = new MemoryStream();
94 | const int Count = 10;
95 | using (var stream = new BlazerInputStream(memoryStream, blazerCompressionOptions))
96 | {
97 | for (var i = 0; i < Count; i++)
98 | stream.Write(data, 0, data.Length);
99 | }
100 |
101 | var compressed = memoryStream.ToArray();
102 | var decompressed = IntegrityHelper.DecompressData(compressed);
103 | Assert.That(decompressed.Length, Is.EqualTo(Count * data.Length));
104 | }
105 |
106 | [Test]
107 | [TestCase(1, BlazerAlgorithm.NoCompress)]
108 | [TestCase(1, BlazerAlgorithm.Stream)]
109 | [TestCase(1, BlazerAlgorithm.Block)]
110 | [TestCase(2, BlazerAlgorithm.NoCompress)]
111 | [TestCase(2, BlazerAlgorithm.Stream)]
112 | [TestCase(2, BlazerAlgorithm.Block)]
113 | [TestCase(3, BlazerAlgorithm.NoCompress)]
114 | [TestCase(3, BlazerAlgorithm.Stream)]
115 | [TestCase(3, BlazerAlgorithm.Block)]
116 | [TestCase(4, BlazerAlgorithm.NoCompress)]
117 | [TestCase(4, BlazerAlgorithm.Stream)]
118 | [TestCase(4, BlazerAlgorithm.Block)]
119 | public void Small_Block_Sizes_ShouldBe_Handled_WithFlush(int blockSize, BlazerAlgorithm algorithm)
120 | {
121 | var data = new byte[blockSize];
122 | data[0] = (byte)blockSize;
123 | var blazerCompressionOptions = BlazerCompressionOptions.CreateStream();
124 | blazerCompressionOptions.SetEncoderByAlgorithm(algorithm);
125 | blazerCompressionOptions.FlushMode = BlazerFlushMode.RespectFlush;
126 |
127 | var memoryStream = new MemoryStream();
128 | const int Count = 10;
129 | using (var stream = new BlazerInputStream(memoryStream, blazerCompressionOptions))
130 | {
131 | for (var i = 0; i < Count; i++)
132 | {
133 | stream.Write(data, 0, data.Length);
134 | stream.Flush();
135 | }
136 | }
137 |
138 | var compressed = memoryStream.ToArray();
139 | var decompressed = IntegrityHelper.DecompressData(compressed);
140 | Assert.That(decompressed.Length, Is.EqualTo(Count * data.Length));
141 | Assert.That(decompressed[blockSize], Is.EqualTo(blockSize));
142 | }
143 |
144 | [Test]
145 | [TestCase(BlazerAlgorithm.NoCompress)]
146 | [TestCase(BlazerAlgorithm.Stream)]
147 | [TestCase(BlazerAlgorithm.Block)]
148 | public void Zero_Block_Sizes_Should_Not_Cause_Error(BlazerAlgorithm algorithm)
149 | {
150 | var data = new byte[0];
151 | var blazerCompressionOptions = BlazerCompressionOptions.CreateStream();
152 | blazerCompressionOptions.SetEncoderByAlgorithm(algorithm);
153 |
154 | var memoryStream = new MemoryStream();
155 | const int Count = 10;
156 | using (var stream = new BlazerInputStream(memoryStream, blazerCompressionOptions))
157 | {
158 | for (var i = 0; i < Count; i++)
159 | {
160 | stream.Write(data, 0, data.Length);
161 | stream.Flush();
162 | }
163 | }
164 |
165 | var compressed = memoryStream.ToArray();
166 | var decompressed = IntegrityHelper.DecompressData(compressed);
167 | Assert.That(decompressed.Length, Is.EqualTo(0));
168 | }
169 |
170 | [Test]
171 | public void FailData_Should_Not_Cause_StackOverflow()
172 | {
173 | var ss = new MemoryStream();
174 | var blazerCompressionOptions = BlazerCompressionOptions.CreateStream();
175 | blazerCompressionOptions.IncludeFooter = false;
176 | var os = new BlazerInputStream(ss, blazerCompressionOptions);
177 | os.WriteControlData(new byte[0], 0, 0);
178 |
179 | new BlazerOutputStream(new MemoryStream(ss.ToArray()), new BlazerDecompressionOptions { NoSeek = true }).Read(new byte[100], 0, 100);
180 | }
181 |
182 | [Test]
183 | public void MissingFooter_With_No_Seec_Should_Cause_Error()
184 | {
185 | var ss = new MemoryStream();
186 | var blazerCompressionOptions = BlazerCompressionOptions.CreateStream();
187 | var os = new BlazerInputStream(ss, blazerCompressionOptions);
188 | os.WriteControlData(new byte[0], 0, 0);
189 |
190 | var ex = Assert.Throws(() => new BlazerOutputStream(new MemoryStream(ss.ToArray()), new BlazerDecompressionOptions { NoSeek = true }).Read(new byte[100], 0, 100));
191 | Assert.That(ex.Message, Is.EqualTo("Stream was finished, but footer is missing. It seems, stream is incomplete"));
192 | }
193 |
194 | [Test]
195 | public void After_Footer_Read_Should_Be_Zero()
196 | {
197 | var ss = new MemoryStream();
198 | var blazerCompressionOptions = BlazerCompressionOptions.CreateStream();
199 | blazerCompressionOptions.LeaveStreamOpen = true;
200 | var os = new BlazerInputStream(ss, blazerCompressionOptions);
201 | os.Write(new byte[100], 0, 100);
202 | os.Close();
203 | ss.Write(new byte[] { 1, 2, 3, 4 }, 0, 4);
204 | ss.Close();
205 |
206 | var oos = new BlazerOutputStream(new MemoryStream(ss.ToArray()), new BlazerDecompressionOptions { NoSeek = true });
207 | var read = oos.Read(new byte[100], 0, 100);
208 | Assert.That(read, Is.EqualTo(100));
209 | Assert.That(oos.Read(new byte[100], 0, 100), Is.EqualTo(0));
210 | Assert.That(oos.Read(new byte[100], 0, 100), Is.EqualTo(0));
211 | }
212 |
213 | // checking strange MemoryStream logic
214 | /*[Test]
215 | public void Test()
216 | {
217 | var stream = new MemoryStream(new byte[1000], 10, 100);
218 |
219 | Assert.That(stream.Position, Is.EqualTo(stream.Seek(0, SeekOrigin.Current)));
220 | }*/
221 | }
222 | }
223 |
--------------------------------------------------------------------------------
/Blazer.Net.Tests/MultipleFilesTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 |
5 | using Force.Blazer;
6 |
7 | using NUnit.Framework;
8 |
9 | namespace Blazer.Net.Tests
10 | {
11 | [TestFixture]
12 | public class MultipleFilesTests
13 | {
14 | [Test]
15 | public void Cannot_Set_One_File_And_Multiple_Files()
16 | {
17 | var options = new BlazerCompressionOptions();
18 | options.FileInfo = new BlazerFileInfo();
19 | Assert.Throws(() => options.MultipleFiles = true);
20 |
21 | options = new BlazerCompressionOptions();
22 | options.MultipleFiles = true;
23 | Assert.Throws(() => options.FileInfo = new BlazerFileInfo());
24 | }
25 |
26 | [Test]
27 | public void EmptyFileInfo_Should_Not_Cause_An_Error()
28 | {
29 | var data = new byte[123];
30 | var blazerCompressionOptions = BlazerCompressionOptions.CreateStream();
31 | blazerCompressionOptions.FileInfo = new BlazerFileInfo();
32 | var compressed = IntegrityHelper.CompressData(data, blazerCompressionOptions);
33 | var os = new BlazerOutputStream(new MemoryStream(compressed));
34 | Assert.That(os.FileInfo, Is.Not.Null);
35 | Assert.That(os.FileInfo.FileName, Is.EqualTo(string.Empty));
36 | }
37 |
38 | [Test]
39 | public void FirstChunk_For_MultipleFiles_Should_Be_FileInfo()
40 | {
41 | var data = new byte[123];
42 | var blazerCompressionOptions = BlazerCompressionOptions.CreateStream();
43 | blazerCompressionOptions.MultipleFiles = true;
44 | var stream = new BlazerInputStream(new MemoryStream(), blazerCompressionOptions);
45 | Assert.Throws(() => stream.Write(data, 0, data.Length));
46 |
47 | // does not throw
48 | stream = new BlazerInputStream(new MemoryStream(), blazerCompressionOptions);
49 | stream.WriteFileInfo(new BlazerFileInfo());
50 | stream.Write(data, 0, data.Length);
51 | }
52 |
53 | [Test]
54 | public void Two_Files_Should_Be_Compressed()
55 | {
56 | var data = new byte[123];
57 | var blazerCompressionOptions = BlazerCompressionOptions.CreateStream();
58 | blazerCompressionOptions.MultipleFiles = true;
59 | var memoryStream = new MemoryStream();
60 | var stream = new BlazerInputStream(memoryStream, blazerCompressionOptions);
61 | stream.WriteFileInfo(new BlazerFileInfo { FileName = "t1" });
62 | stream.Write(data, 0, data.Length);
63 | stream.WriteFileInfo(new BlazerFileInfo { FileName = "t2" });
64 | stream.Write(data, 0, data.Length);
65 | stream.Close();
66 | var res = memoryStream.ToArray();
67 | var decOptions = new BlazerDecompressionOptions();
68 | var q = new Queue(new[] { "t1", "t2" });
69 | decOptions.FileInfoCallback = f => Assert.That(f.FileName, Is.EqualTo(q.Dequeue()));
70 | new BlazerOutputStream(new MemoryStream(res), decOptions).CopyTo(new MemoryStream());
71 | Assert.That(q.Count, Is.EqualTo(0));
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/Blazer.Net.Tests/NativeCheckTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Text;
6 | using Force.Blazer.Native;
7 | using Force.Crc32;
8 | using NUnit.Framework;
9 |
10 | using E = Force.Blazer.Algorithms.Crc32C.Crc32C;
11 |
12 | namespace Blazer.Net.Tests
13 | {
14 | [TestFixture]
15 | public class NativeCheckTests
16 | {
17 | [Test]
18 | public void ResultConsistency()
19 | {
20 | // checking that native implementation is available. it works only on windows, but tests on windows now
21 |
22 | // removing old data
23 | var architectureSuffix = IntPtr.Size == 8 ? "x64" : "x86";
24 | var dllPath = Path.Combine(Path.GetTempPath(), "Blazer.Net.0.8.3.9", architectureSuffix);
25 | var fileName = Path.Combine(dllPath, "Blazer.Native.dll");
26 | if (File.Exists(fileName))
27 | {
28 | try
29 | {
30 | File.Delete(fileName);
31 | }
32 | catch (Exception e)
33 | {
34 | File.Move(fileName, fileName + ".old");
35 | throw;
36 | }
37 | }
38 |
39 | var result = (bool) typeof(NativeHelper).GetMethod("Init", BindingFlags.Static | BindingFlags.NonPublic)
40 | .Invoke(null, new object[0]);
41 |
42 | Assert.That(result, Is.True);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Blazer.Net.Tests/PatternedCompressionTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 |
4 | using Force.Blazer.Algorithms;
5 | using Force.Blazer.Algorithms.Patterned;
6 |
7 | using NUnit.Framework;
8 |
9 | namespace Blazer.Net.Tests
10 | {
11 | [TestFixture(1)]
12 | [TestFixture(2)]
13 | [TestFixture(3)]
14 | public class PatternedCompressionTests
15 | {
16 | private readonly Type _compressorType;
17 |
18 | private BasePatternedCompressor GetCompressor()
19 | {
20 | return (BasePatternedCompressor)Activator.CreateInstance(_compressorType);
21 | }
22 |
23 | public PatternedCompressionTests(int type)
24 | {
25 | if (type == 1) _compressorType = typeof(StreamPatternedCompressor);
26 | else if (type == 2) _compressorType = typeof(StreamHighPatternedCompressor);
27 | else if (type == 3) _compressorType = typeof(BlockPatternedCompressor);
28 | else throw new NotImplementedException();
29 | }
30 |
31 | [Test]
32 | public void DataWithPattern_Should_Be_Correctly_Encoded_Decoded()
33 | {
34 | var ssed = GetCompressor();
35 | var pattern = new byte[100];
36 | pattern[1] = 42;
37 | ssed.PreparePattern(pattern, 0, pattern.Length);
38 |
39 | var data1 = new byte[10];
40 | data1[0] = 42;
41 |
42 | var data2 = new byte[10];
43 | data2[0] = 12;
44 |
45 | var tmpOut = new byte[ssed.CalculateMaxCompressedBufferLength(10)];
46 | var tmpOut2 = new byte[ssed.CalculateMaxCompressedBufferLength(10)];
47 |
48 | var cntPatterned = ssed.EncodeWithPattern(data1, 0, data1.Length, tmpOut, 0);
49 | var cntUnpatterned = StreamEncoder.CompressData(data1);
50 | // TODO: uncomment
51 | Assert.That(cntPatterned, Is.LessThan(cntUnpatterned.Length));
52 | var cntPatternUnpacked = ssed.DecodeWithPattern(tmpOut, 0, cntPatterned, tmpOut2, 0);
53 | Assert.That(cntPatternUnpacked, Is.EqualTo(10));
54 | CollectionAssert.AreEqual(data1, tmpOut2.Take(cntPatternUnpacked));
55 |
56 | // checking that we can repeat without failure
57 | cntPatterned = ssed.EncodeWithPattern(data2, 0, data2.Length, tmpOut, 0);
58 | cntPatternUnpacked = ssed.DecodeWithPattern(tmpOut, 0, cntPatterned, tmpOut2, 0);
59 | Assert.That(cntPatternUnpacked, Is.EqualTo(10));
60 | CollectionAssert.AreEqual(data2, tmpOut2.Take(cntPatternUnpacked));
61 | }
62 |
63 | [Test]
64 | public void DataWithPattern_Should_Be_Correctly_Encoded_Decoded_With_Offsets()
65 | {
66 | var ssed = GetCompressor();
67 | var pattern = new byte[100];
68 | pattern[1] = 42;
69 | ssed.PreparePattern(pattern, 1, pattern.Length - 1);
70 |
71 | var data1 = new byte[10];
72 | data1[1] = 42;
73 |
74 | var data2 = new byte[9];
75 | data1[0] = 42;
76 |
77 | var tmpOut = new byte[ssed.CalculateMaxCompressedBufferLength(10)];
78 | var tmpOut2 = new byte[ssed.CalculateMaxCompressedBufferLength(10)];
79 |
80 | var cntPatterned1 = ssed.EncodeWithPattern(data1, 1, data1.Length - 1, tmpOut, 1);
81 | var cntPatterned2 = ssed.EncodeWithPattern(data2, 0, data2.Length, tmpOut2, 0);
82 | Assert.That(cntPatterned1, Is.EqualTo(cntPatterned2));
83 | var cntPatternedUnpacked = ssed.DecodeWithPattern(tmpOut, 1, cntPatterned1, tmpOut2, 1);
84 | Assert.That(cntPatternedUnpacked, Is.EqualTo(9));
85 | CollectionAssert.AreEqual(data1.Skip(1), tmpOut2.Skip(1).Take(cntPatternedUnpacked));
86 | }
87 |
88 | [Test]
89 | public void DataWithPattern_Should_Be_Correctly_Encoded_Decoded_With_Simple_Interface()
90 | {
91 | var ssed = GetCompressor();
92 | var pattern = new byte[100];
93 | pattern[1] = 42;
94 | ssed.PreparePattern(pattern, 1, pattern.Length - 1);
95 |
96 | var data1 = new byte[10];
97 | data1[1] = 42;
98 |
99 | var patterned = ssed.EncodeWithPattern(data1);
100 | var patternedUnpacked = ssed.DecodeWithPattern(patterned);
101 |
102 | CollectionAssert.AreEqual(data1, patternedUnpacked);
103 | }
104 |
105 | [Test]
106 | public void Zero_Length_Should_not_Cause_Error()
107 | {
108 | var ssed = GetCompressor();
109 | var pattern = new byte[100];
110 | pattern[1] = 42;
111 | ssed.PreparePattern(pattern, 1, pattern.Length - 1);
112 |
113 | var data1 = new byte[0];
114 |
115 | var patterned = ssed.EncodeWithPattern(data1);
116 | Assert.That(patterned.Length, Is.EqualTo(1));
117 | var patternUnpacked = ssed.DecodeWithPattern(patterned);
118 |
119 | CollectionAssert.AreEqual(data1, patternUnpacked);
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/Blazer.Net.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Blazer.Net.Tests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Blazer.Net.Tests")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("23d2154d-816c-47aa-b67c-6690949c054e")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Blazer.Net.Tests/StreamEncoderTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Text;
4 |
5 | using NUnit.Framework;
6 |
7 | namespace Blazer.Net.Tests
8 | {
9 | [TestFixture]
10 | public class StreamEncoderTests
11 | {
12 | [OneTimeSetUp]
13 | public void OneTimeSetUp()
14 | {
15 | #if NETCORE
16 | Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
17 | #endif
18 | }
19 |
20 | [Test]
21 | public void Test_AAAAAAAA()
22 | {
23 | var buf = new byte[] { 1, 1, 1, 1, 1, 1, 1, 1 };
24 | var len = IntegrityHelper.StreamEncoderCheckCompressDecompress(buf);
25 | // 1 times 1, then 7 times ref -1
26 | Assert.That(len, Is.EqualTo(3));
27 | }
28 |
29 | [Test]
30 | public void Test_AAAAAAAABBBBBBBB()
31 | {
32 | var buf = new byte[] { 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2 };
33 | var len = IntegrityHelper.StreamEncoderCheckCompressDecompress(buf);
34 | Assert.That(len, Is.LessThanOrEqualTo(16));
35 | }
36 |
37 | [Test]
38 | public void Test_1000A()
39 | {
40 | // byte 0: short backref, 1 lit, 15 repetitions
41 | // byte 1: backref 0 + 1
42 | // byte 2: 254 repetitions + 2 byte
43 | // byte 3-4: 1d7 repetitions. 471 + 256 + 253 + 15 + 4 = 999
44 | // 1F-00-FE-01-D7-01 (6)
45 | var buf = Enumerable.Range(0, 1000).Select(x => (byte)1).ToArray();
46 | var len = IntegrityHelper.StreamEncoderCheckCompressDecompress(buf);
47 | // 1 times 1, then 7 times ref -1
48 | Assert.That(len, Is.EqualTo(6));
49 | }
50 |
51 | [Test]
52 | public void Test_ByteBorder_Repetitions()
53 | {
54 | for (var i = 250; i < 300; i++)
55 | {
56 | var buf = Enumerable.Range(0, i).Select(x => (byte)1).ToArray();
57 | IntegrityHelper.StreamEncoderCheckCompressDecompress(buf);
58 | }
59 |
60 | for (var i = 65700; i < 65800; i++)
61 | {
62 | var buf = Enumerable.Range(0, i).Select(x => (byte)1).ToArray();
63 | IntegrityHelper.StreamEncoderCheckCompressDecompress(buf);
64 | }
65 | }
66 |
67 | [Test]
68 | public void Test_HabaxHabax()
69 | {
70 | var buf = new byte[] { 2, 1, 3, 1, 4, 2, 1, 3, 1, 4 };
71 | var len = IntegrityHelper.StreamEncoderCheckCompressDecompress(buf);
72 | Assert.That(len, Is.LessThan(8));
73 | }
74 |
75 | [Test]
76 | public void Test_Cycle_20000_SemiRandom()
77 | {
78 | var r = new Random(12346);
79 | var buf = Enumerable.Range(0, 20000).Select(x => (byte)r.Next(2)).ToArray();
80 | var len = IntegrityHelper.StreamEncoderCheckCompressDecompress(buf);
81 | // 1 times 1, then 7 times ref -1
82 | Assert.That(len, Is.LessThan(20000));
83 | }
84 |
85 | [Test]
86 | public void Test_Cycle_120000_SemiRandom()
87 | {
88 | var r = new Random(12346);
89 | var buf = Enumerable.Range(0, 120000).Select(x => (byte)r.Next(2)).ToArray();
90 | var len = IntegrityHelper.StreamEncoderCheckCompressDecompress(buf);
91 | // 1 times 1, then 7 times ref -1
92 | Assert.That(len, Is.LessThan(120000));
93 | }
94 |
95 | [Test]
96 | public void Test_Text()
97 | {
98 | var buf = Encoding.GetEncoding(1251).GetBytes(@"
99 | Когда то давно Московское метро замышлялось как гигантское бомбоубежище, способное спасти десятки тысяч жизней. Мир стоял на пороге гибели, но тогда ее удалось отсрочить. Дорога, по которой идет человечество, вьется, как спираль, и однажды оно снова окажется на краю пропасти. Когда мир будет рушиться, метро окажется последним пристанищем человека перед тем, как он канет в ничто.
100 | — Кто это там? Эй, Артем! Глянь ка!
101 | Артем нехотя поднялся со своего места у костра и, перетягивая со спины на грудь автомат, двинулся во тьму. Стоя на самом краю освещенного пространства, он демонстративно, как можно громче и внушительней, щелкнул затвором и хрипло крикнул: — Стоять! Пароль!");
102 | IntegrityHelper.StreamEncoderCheckCompressDecompress(buf);
103 | }
104 |
105 | [Test]
106 | public void Test_Zero_Bytes()
107 | {
108 | var len = IntegrityHelper.StreamEncoderCheckCompressDecompress(new byte[0]);
109 | Assert.That(len, Is.EqualTo(0));
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/Blazer.Net.Tests/StreamHandlingTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | using Force.Blazer;
5 |
6 | using NUnit.Framework;
7 |
8 | namespace Blazer.Net.Tests
9 | {
10 | [TestFixture]
11 | public class StreamHandlingTests
12 | {
13 | [Test]
14 | public void Memory_Stream_With_Offset_Should_Be_Handled()
15 | {
16 | var memoryStream = new MemoryStream();
17 | var blzStream = new BlazerInputStream(memoryStream, BlazerCompressionOptions.CreateStream());
18 | var streamWriter = new StreamWriter(blzStream);
19 | streamWriter.Write("123");
20 | streamWriter.Flush();
21 | blzStream.Dispose();
22 |
23 | var dstArr = new byte[1000];
24 | var comprData = memoryStream.ToArray();
25 | Buffer.BlockCopy(comprData, 0, dstArr, 1, comprData.Length);
26 |
27 | // such usage of MemoryStream causes Seek and Position return invalid values. As result, decompress can cause an error
28 | // we're checking that we work correctly
29 | var r = new StreamReader(new BlazerOutputStream(new MemoryStream(dstArr, 1, comprData.Length))).ReadToEnd();
30 | Assert.That(r, Is.EqualTo("123"));
31 |
32 | Buffer.BlockCopy(comprData, 0, dstArr, 23, comprData.Length);
33 | r = new StreamReader(new BlazerOutputStream(new MemoryStream(dstArr, 23, comprData.Length))).ReadToEnd();
34 | Assert.That(r, Is.EqualTo("123"));
35 | }
36 |
37 | [Test]
38 | public void Two_Joined_Streams_Should_Be_Handled()
39 | {
40 | var memoryStream = new MemoryStream();
41 | var options = BlazerCompressionOptions.CreateStream();
42 | options.LeaveStreamOpen = true;
43 | var blzStream = new BlazerInputStream(memoryStream, options);
44 | var streamWriter = new StreamWriter(blzStream);
45 | streamWriter.Write("111111111111111111111");
46 | streamWriter.Flush();
47 | blzStream.Dispose();
48 |
49 | blzStream = new BlazerInputStream(memoryStream, options);
50 | streamWriter = new StreamWriter(blzStream);
51 | streamWriter.Write("22222222222222222");
52 | streamWriter.Flush();
53 | blzStream.Dispose();
54 |
55 |
56 | var comprData = memoryStream.ToArray();
57 | var readMs = new MemoryStream(comprData);
58 |
59 | // such usage of MemoryStream causes Seek and Position return invalid values. As result, decompress can cause an error
60 | // we're checking that we work correctly
61 | var r = new StreamReader(new BlazerOutputStream(readMs, new BlazerDecompressionOptions { LeaveStreamOpen = true })).ReadToEnd();
62 | Assert.That(r, Is.EqualTo("111111111111111111111"));
63 |
64 | r = new StreamReader(new BlazerOutputStream(readMs, new BlazerDecompressionOptions { LeaveStreamOpen = true })).ReadToEnd();
65 | Assert.That(r, Is.EqualTo("22222222222222222"));
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Blazer.Net.Tests/TcpClientExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Net;
3 | using System.Net.Sockets;
4 |
5 | namespace Blazer.Net.Tests
6 | {
7 | public static class TcpClientExtensions
8 | {
9 | #if NETCORE
10 | public static TcpClient AcceptTcpClient(this TcpListener listener)
11 | {
12 | return listener.AcceptTcpClientAsync().Result;
13 | }
14 |
15 | public static void Connect(this TcpClient client, IPEndPoint endpoint)
16 | {
17 | client.ConnectAsync(endpoint.Address, endpoint.Port).Wait();
18 | }
19 |
20 | public static void Close(this TcpClient client)
21 | {
22 | client.Dispose();
23 | }
24 |
25 | public static void Close(this Stream stream)
26 | {
27 | stream.Dispose();
28 | }
29 | #endif
30 | }
31 | }
--------------------------------------------------------------------------------
/Blazer.Net.Tests/TcpStreamTests.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using System.Net.Sockets;
3 | using System.Threading.Tasks;
4 |
5 | using Force.Blazer;
6 |
7 | using NUnit.Framework;
8 |
9 | namespace Blazer.Net.Tests
10 | {
11 | // in these test we ensure that all data is correctly processed with live network streams
12 | [TestFixture]
13 | public class TcpStreamTests
14 | {
15 | [Test]
16 | public void EnsureUsualStreamWriteFull()
17 | {
18 | var l = new TcpListener(new IPEndPoint(IPAddress.Loopback, 9990));
19 | l.Start();
20 | try
21 | {
22 | Task.Factory.StartNew(
23 | () =>
24 | {
25 | var cl = l.AcceptTcpClient();
26 | cl.GetStream().Write(new byte[] { 0x1, 0x2, 0x3 }, 0, 3);
27 | cl.Close();
28 | });
29 |
30 | var c = new TcpClient();
31 | c.Connect(new IPEndPoint(IPAddress.Loopback, 9990));
32 | var stream = c.GetStream();
33 | var buf = new byte[100];
34 | Assert.That(stream.Read(buf, 0, buf.Length), Is.EqualTo(3));
35 | Assert.That(buf[1], Is.EqualTo(2));
36 | }
37 | finally
38 | {
39 | l.Stop();
40 | }
41 | }
42 |
43 | [Test]
44 | public void EnsureBlazerStreamWriteFull()
45 | {
46 | var l = new TcpListener(new IPEndPoint(IPAddress.Loopback, 9990));
47 | l.Start();
48 | try
49 | {
50 | Task.Factory.StartNew(
51 | () =>
52 | {
53 | var cl = l.AcceptTcpClient();
54 | var networkStream = new BlazerInputStream(cl.GetStream(), BlazerCompressionOptions.CreateStream());
55 | networkStream.Write(new byte[] { 0x1, 0x2, 0x3 }, 0, 3);
56 | networkStream.Close();
57 | cl.Close();
58 | });
59 |
60 | var c = new TcpClient();
61 | c.Connect(new IPEndPoint(IPAddress.Loopback, 9990));
62 | var stream = new BlazerOutputStream(c.GetStream());
63 | var buf = new byte[100];
64 | Assert.That(stream.Read(buf, 0, buf.Length), Is.EqualTo(3));
65 | Assert.That(buf[1], Is.EqualTo(2));
66 | }
67 | finally
68 | {
69 | l.Stop();
70 | }
71 | }
72 |
73 | [Test]
74 | public void EnsureBlazerStreamWriteFull_ControlBlock()
75 | {
76 | var l = new TcpListener(new IPEndPoint(IPAddress.Loopback, 9990));
77 | l.Start();
78 | try
79 | {
80 | Task.Factory.StartNew(
81 | () =>
82 | {
83 | var cl = l.AcceptTcpClient();
84 | var str = cl.GetStream();
85 | var networkStream = new BlazerInputStream(str, BlazerCompressionOptions.CreateStream());
86 | var b = new byte[80];
87 | b[1] = 0x2;
88 | networkStream.WriteControlData(b, 0, b.Length);
89 | networkStream.Flush();
90 | networkStream.Close();
91 | cl.Close();
92 | });
93 |
94 | var c = new TcpClient();
95 | c.Connect(new IPEndPoint(IPAddress.Loopback, 9990));
96 | var readedCnt = 0;
97 | var stream = new BlazerOutputStream(c.GetStream(), new BlazerDecompressionOptions() { ControlDataCallback = (bytes, i, arg3) => readedCnt = arg3 });
98 | var buf = new byte[100];
99 | Assert.That(stream.Read(buf, 0, buf.Length), Is.EqualTo(0));
100 | Assert.That(readedCnt, Is.EqualTo(80));
101 | }
102 | finally
103 | {
104 | l.Stop();
105 | }
106 | }
107 |
108 | [Test]
109 | public void EnsureBlazerStreamWriteFull_EncryptFull()
110 | {
111 | var l = new TcpListener(new IPEndPoint(IPAddress.Loopback, 9990));
112 | l.Start();
113 | try
114 | {
115 | Task.Factory.StartNew(
116 | () =>
117 | {
118 | var cl = l.AcceptTcpClient();
119 | var opt = BlazerCompressionOptions.CreateStream();
120 | opt.Comment = "test";
121 | var networkStream = new BlazerInputStream(cl.GetStream(), opt);
122 | networkStream.WriteControlData(new byte[0], 0, 0);
123 | networkStream.Close();
124 | cl.Close();
125 | });
126 |
127 | var c = new TcpClient();
128 | c.Connect(new IPEndPoint(IPAddress.Loopback, 9990));
129 | var stream = new BlazerOutputStream(c.GetStream(), new BlazerDecompressionOptions());
130 | var buf = new byte[100];
131 | Assert.That(stream.Read(buf, 0, buf.Length), Is.EqualTo(0));
132 | Assert.That(stream.Comment, Is.EqualTo("test"));
133 | }
134 | finally
135 | {
136 | l.Stop();
137 | }
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/Blazer.Net.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Blazer.Net.Tests/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.0.0-*",
3 | "buildOptions": {
4 | "debugType": "portable",
5 | "allowUnsafe": true
6 | },
7 | "dependencies": {
8 | "Blazer.Net": "0.10.0-*",
9 | "Crc32.NET": "1.1.0",
10 | "NUnit": "3.6.0"
11 | },
12 |
13 | "testRunner": "nunit",
14 |
15 | "frameworks": {
16 | "net461": {
17 | "dependencies": {
18 | }
19 | },
20 | "netcoreapp1.0": {
21 | "imports": "portable-net45+win8",
22 | "buildOptions": {
23 | "define": ["NETCORE"]
24 | },
25 | "dependencies": {
26 | "System.Text.Encoding.CodePages": "4.3.0",
27 | "NETStandard.Library": "1.6.1",
28 | "dotnet-test-nunit": "3.4.0-beta-3",
29 | "Microsoft.NETCore.App": {
30 | "version": "1.1.0-*",
31 | "type": "platform"
32 | }
33 | }
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/Blazer.Net/.gitignore:
--------------------------------------------------------------------------------
1 | _releases
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/BlockDecoder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics.CodeAnalysis;
3 |
4 | namespace Force.Blazer.Algorithms
5 | {
6 | ///
7 | /// Decoder of block version of Blazer algorithm
8 | ///
9 | /// This version provides relative good and fast compression but decompression rate is same as compression
10 | public class BlockDecoder : IDecoder
11 | {
12 | // should be equal with BlockEncoder
13 | private const int HASH_TABLE_BITS = 16;
14 |
15 | ///
16 | /// Length of hashtable - 1
17 | ///
18 | protected const int HASH_TABLE_LEN = (1 << HASH_TABLE_BITS) - 1;
19 | private const int MIN_SEQ_LEN = 4;
20 | // carefully selected random number
21 | private const uint Mul = 1527631329;
22 |
23 | private byte[] _innerBuffer;
24 |
25 | private int _maxUncompressedBlockSize;
26 |
27 | ///
28 | /// Hash array to store dictionary between iterations
29 | ///
30 | [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1304:NonPrivateReadonlyFieldsMustBeginWithUpperCaseLetter", Justification = "Reviewed. Suppression is OK here.")]
31 | protected readonly int[] _hashArr = new int[HASH_TABLE_LEN + 1];
32 |
33 | ///
34 | /// Returns internal hash array
35 | ///
36 | public int[] HashArr
37 | {
38 | get
39 | {
40 | return _hashArr;
41 | }
42 | }
43 |
44 | ///
45 | /// Decodes given buffer
46 | ///
47 | public BufferInfo Decode(byte[] buffer, int offset, int length, bool isCompressed)
48 | {
49 | if (!isCompressed)
50 | return new BufferInfo(buffer, offset, length);
51 |
52 | var outLen = DecompressBlock(buffer, offset, length, _innerBuffer, 0, _maxUncompressedBlockSize, true);
53 | return new BufferInfo(_innerBuffer, 0, outLen);
54 | }
55 |
56 | ///
57 | /// Initializes decoder with information about maximum uncompressed block size
58 | ///
59 | public virtual void Init(int maxUncompressedBlockSize)
60 | {
61 | _innerBuffer = new byte[maxUncompressedBlockSize];
62 | _maxUncompressedBlockSize = maxUncompressedBlockSize;
63 | }
64 |
65 | ///
66 | /// Returns algorithm id
67 | ///
68 | public BlazerAlgorithm GetAlgorithmId()
69 | {
70 | return BlazerAlgorithm.Block;
71 | }
72 |
73 | ///
74 | /// Decompresses block of data
75 | ///
76 | public virtual int DecompressBlock(
77 | byte[] bufferIn, int bufferInOffset, int bufferInLength, byte[] bufferOut, int bufferOutOffset, int bufferOutLength, bool doCleanup)
78 | {
79 | var cnt = DecompressBlockExternal(bufferIn, bufferInOffset, bufferInLength, bufferOut, bufferOutOffset, bufferOutLength, _hashArr);
80 | if (doCleanup)
81 | Array.Clear(_hashArr, 0, HASH_TABLE_LEN + 1);
82 |
83 | return cnt;
84 | }
85 |
86 | ///
87 | /// Decompresses block of data, can be used independently for byte arrays
88 | ///
89 | /// In buffer
90 | /// In buffer offset
91 | /// In buffer right offset (offset + count)
92 | /// Out buffer, should be enough size
93 | /// Out buffer offset
94 | /// Out buffer maximum right offset (offset + count)
95 | /// Hash array. Can be null.
96 | /// Bytes count of decompressed data
97 | public static int DecompressBlockExternal(byte[] bufferIn, int bufferInOffset, int bufferInLength, byte[] bufferOut, int bufferOutOffset, int bufferOutLength, int[] hashArr)
98 | {
99 | hashArr = hashArr ?? new int[HASH_TABLE_LEN + 1];
100 | var idxIn = bufferInOffset;
101 | var idxOut = bufferOutOffset;
102 | uint mulEl = 0;
103 |
104 | while (idxIn < bufferInLength)
105 | {
106 | var elem = bufferIn[idxIn++];
107 |
108 | var seqCntFirst = elem & 0xf;
109 | var litCntFirst = (elem >> 4) & 7;
110 |
111 | var litCnt = litCntFirst;
112 | int seqCnt;
113 | var backRef = 0;
114 | var hashIdx = -1;
115 |
116 | if (elem >= 128)
117 | {
118 | hashIdx = bufferIn[idxIn++] | (bufferIn[idxIn++] << 8);
119 | seqCnt = seqCntFirst + MIN_SEQ_LEN/* + 1*/;
120 | if (hashIdx == 0xffff)
121 | {
122 | seqCnt = 0;
123 | seqCntFirst = 0;
124 | litCnt = elem - 128;
125 | litCntFirst = litCnt == 127 ? 7 : 0;
126 | }
127 | }
128 | else
129 | {
130 | backRef = bufferIn[idxIn++] + 1;
131 | seqCnt = seqCntFirst + MIN_SEQ_LEN;
132 | }
133 |
134 | if (litCntFirst == 7)
135 | {
136 | var litCntR = bufferIn[idxIn++];
137 | if (litCntR < 253) litCnt += litCntR;
138 | else if (litCntR == 253)
139 | litCnt += 253 + bufferIn[idxIn++];
140 | else if (litCntR == 254)
141 | litCnt += 253 + 256 + bufferIn[idxIn++] + (bufferIn[idxIn++] << 8);
142 | else
143 | litCnt += 253 + (256 * 256) + bufferIn[idxIn++] + (bufferIn[idxIn++] << 8) + (bufferIn[idxIn++] << 16) + (bufferIn[idxIn++] << 24);
144 | }
145 |
146 | if (seqCntFirst == 15)
147 | {
148 | var seqCntR = bufferIn[idxIn++];
149 | if (seqCntR < 253) seqCnt += seqCntR;
150 | else if (seqCntR == 253)
151 | seqCnt += 253 + bufferIn[idxIn++];
152 | else if (seqCntR == 254)
153 | seqCnt += 253 + 256 + bufferIn[idxIn++] + (bufferIn[idxIn++] << 8);
154 | else
155 | seqCnt += 253 + (256 * 256) + bufferIn[idxIn++] + (bufferIn[idxIn++] << 8) + (bufferIn[idxIn++] << 16) + (bufferIn[idxIn++] << 24);
156 | }
157 |
158 | var maxOutLength = idxOut + litCnt + seqCnt;
159 | if (maxOutLength > bufferOutLength)
160 | {
161 | throw new InvalidOperationException("Very small inner buffer. Invalid configuration or stream.");
162 | }
163 |
164 | while (--litCnt >= 0)
165 | {
166 | var v = bufferIn[idxIn++];
167 | mulEl = (mulEl << 8) | v;
168 | var hashKey = (mulEl * Mul) >> (32 - HASH_TABLE_BITS);
169 | hashArr[hashKey] = idxOut;
170 | bufferOut[idxOut++] = v;
171 | }
172 |
173 | var inRepIdx = hashIdx >= 0 ? hashArr[hashIdx] - 3 : idxOut - backRef;
174 |
175 | while (--seqCnt >= 0)
176 | {
177 | var v = bufferOut[inRepIdx++];
178 | mulEl = (mulEl << 8) | v;
179 |
180 | hashArr[(mulEl * Mul) >> (32 - HASH_TABLE_BITS)] = idxOut;
181 |
182 | bufferOut[idxOut++] = v;
183 | }
184 | }
185 |
186 | return idxOut;
187 | }
188 |
189 | ///
190 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
191 | ///
192 | /// 2
193 | public virtual void Dispose()
194 | {
195 | }
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/BlockDecoderNative.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace Force.Blazer.Algorithms
5 | {
6 | ///
7 | /// Native implementation of decoder of block version of Blazer algorithm
8 | ///
9 | /// This version provides relative good and fast compression but decompression rate is same as compression
10 | public class BlockDecoderNative : BlockDecoder
11 | {
12 | [DllImport(@"Blazer.Native.dll", CallingConvention = CallingConvention.Cdecl)]
13 | private static extern int blazer_block_decompress_block(
14 | byte[] bufferIn, int bufferInOffset, int bufferInLength, byte[] bufferOut, int bufferOutOffset, int bufferOutLength, int[] hashArr);
15 |
16 | ///
17 | /// Initializes encoder with information about maximum uncompressed block size
18 | ///
19 | public override void Init(int maxInBlockSize)
20 | {
21 | base.Init(maxInBlockSize);
22 | }
23 |
24 | ///
25 | /// Decompresses block of data
26 | ///
27 | public override int DecompressBlock(
28 | byte[] bufferIn, int bufferInOffset, int bufferInLength, byte[] bufferOut, int idxOut, int bufferOutLength, bool doCleanup)
29 | {
30 | var res = blazer_block_decompress_block(bufferIn, bufferInOffset, bufferInLength, bufferOut, idxOut, bufferOutLength, _hashArr);
31 | if (doCleanup)
32 | Array.Clear(_hashArr, 0, HASH_TABLE_LEN + 1);
33 |
34 | if (res < 0)
35 | throw new InvalidOperationException("Invalid compressed data");
36 | return res;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/BlockEncoderNative.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace Force.Blazer.Algorithms
5 | {
6 | ///
7 | /// Native implementation of encoder of block version of Blazer algorithm
8 | ///
9 | /// This version provides relative good and fast compression but decompression rate is same as compression
10 | public class BlockEncoderNative : BlockEncoder
11 | {
12 | [DllImport(@"Blazer.Native.dll", CallingConvention = CallingConvention.Cdecl)]
13 | private static extern int blazer_block_compress_block(
14 | byte[] bufferIn, int bufferInOffset, int bufferInLength, byte[] bufferOut, int bufferOutOffset, int[] hashArr);
15 |
16 | ///
17 | /// Compresses block of data
18 | ///
19 | public override int CompressBlock(
20 | byte[] bufferIn,
21 | int bufferInOffset,
22 | int bufferInCount,
23 | byte[] bufferOut,
24 | int bufferOutOffset,
25 | bool doCleanup)
26 | {
27 | var cnt = blazer_block_compress_block(
28 | bufferIn,
29 | bufferInOffset,
30 | bufferInCount,
31 | bufferOut,
32 | bufferOutOffset,
33 | _hashArr);
34 |
35 | if (doCleanup)
36 | Array.Clear(_hashArr, 0, HASH_TABLE_LEN + 1);
37 |
38 | return cnt;
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/BufferInfo.cs:
--------------------------------------------------------------------------------
1 | namespace Force.Blazer.Algorithms
2 | {
3 | ///
4 | /// Information about data buffer
5 | ///
6 | public struct BufferInfo
7 | {
8 | ///
9 | /// Data buffer
10 | ///
11 | public byte[] Buffer;
12 |
13 | ///
14 | /// Buffer offset
15 | ///
16 | public int Offset;
17 |
18 | ///
19 | /// Buffer data length (Offset + Count, right position of valid data in buffer)
20 | ///
21 | public int Length;
22 |
23 | ///
24 | /// Count of valid data in buffer)
25 | ///
26 | public int Count
27 | {
28 | get
29 | {
30 | return Length - Offset;
31 | }
32 | }
33 |
34 | ///
35 | /// BufferInfo constructor
36 | ///
37 | public BufferInfo(byte[] buffer, int offset, int length)
38 | {
39 | Buffer = buffer;
40 | Offset = offset;
41 | Length = length;
42 | }
43 |
44 | ///
45 | /// Extracts body to separate byte array
46 | ///
47 | /// new array
48 | public byte[] ExtractToSeparateArray()
49 | {
50 | return ExtractToSeparateArray(0);
51 | }
52 |
53 | ///
54 | /// Extracts body to separate byte array
55 | ///
56 | /// additional offset for new array
57 | /// new array
58 | public byte[] ExtractToSeparateArray(int offset)
59 | {
60 | var res = new byte[Count + offset];
61 | System.Buffer.BlockCopy(Buffer, Offset, res, offset, Count);
62 | return res;
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/Crc32C/Crc32C.cs:
--------------------------------------------------------------------------------
1 | using Force.Blazer.Native;
2 |
3 | namespace Force.Blazer.Algorithms.Crc32C
4 | {
5 | ///
6 | /// Crc32C (Castagnoli) checksum implementation
7 | ///
8 | public static class Crc32C
9 | {
10 | private static readonly ICrc32CCalculator _calculator;
11 |
12 | static Crc32C()
13 | {
14 | _calculator = NativeHelper.IsNativeAvailable ? (ICrc32CCalculator)new Crc32CHardware() : new Crc32CSoftware();
15 | }
16 |
17 | ///
18 | /// Calculates Crc32C data of given buffer
19 | ///
20 | public static uint Calculate(byte[] buffer, int offset, int count)
21 | {
22 | return Calculate(0, buffer, offset, count);
23 | }
24 |
25 | ///
26 | /// Calculates Crc32C data of given buffer, updates existing crc
27 | ///
28 | public static uint Calculate(uint currentCrc, byte[] buffer)
29 | {
30 | return Calculate(currentCrc, buffer, 0, buffer.Length);
31 | }
32 |
33 | ///
34 | /// Calculates Crc32C data of given buffer, updates existing crc
35 | ///
36 | public static uint Calculate(uint currentCrc, byte[] buffer, int offset, int count)
37 | {
38 | return _calculator.Calculate(currentCrc, buffer, offset, count);
39 | }
40 |
41 | ///
42 | /// Calculates Crc32C data of given buffer
43 | ///
44 | public static uint Calculate(byte[] buffer)
45 | {
46 | return Calculate(0, buffer, 0, buffer.Length);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/Crc32C/Crc32CHardware.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | using Force.Blazer.Native;
5 |
6 | namespace Force.Blazer.Algorithms.Crc32C
7 | {
8 | ///
9 | /// Native (hardware if available) Crc32C calculator. Do not use it directly, instead of use class
10 | ///
11 | public class Crc32CHardware : ICrc32CCalculator
12 | {
13 | [DllImport(@"Blazer.Native.dll", CallingConvention = CallingConvention.Cdecl)]
14 | private static extern uint crc32c_append(uint crc, IntPtr buffer, int length);
15 |
16 | ///
17 | /// Constructor, will throw exception if it impossible to use hardware implementation
18 | ///
19 | public Crc32CHardware()
20 | {
21 | if (!NativeHelper.IsNativeAvailable)
22 | throw new InvalidOperationException("You have no right for hardware implementation");
23 | }
24 |
25 | uint ICrc32CCalculator.Calculate(uint crc, byte[] buffer, int offset, int count)
26 | {
27 | var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
28 | var res = crc32c_append(crc, handle.AddrOfPinnedObject() + offset, count);
29 | handle.Free();
30 | return res;
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/Crc32C/Crc32CSoftware.cs:
--------------------------------------------------------------------------------
1 | namespace Force.Blazer.Algorithms.Crc32C
2 | {
3 | ///
4 | /// Software managed Crc32C calculator
5 | ///
6 | public class Crc32CSoftware : ICrc32CCalculator
7 | {
8 | private static readonly uint[] _table = new uint[16 * 256];
9 |
10 | static Crc32CSoftware()
11 | {
12 | const uint Poly = 0x82f63b78;
13 | for (uint i = 0; i < 256; i++)
14 | {
15 | uint res = i;
16 | for (int t = 0; t < 16; t++)
17 | {
18 | for (int k = 0; k < 8; k++) res = (res & 1) == 1 ? Poly ^ (res >> 1) : (res >> 1);
19 | _table[(t * 256) + i] = res;
20 | }
21 | }
22 | }
23 |
24 | uint ICrc32CCalculator.Calculate(uint crc, byte[] input, int offset, int length)
25 | {
26 | uint crcLocal = uint.MaxValue ^ crc;
27 |
28 | uint[] table = _table;
29 | while (length >= 16)
30 | {
31 | var a = table[(3 * 256) + input[offset + 12]]
32 | ^ table[(2 * 256) + input[offset + 13]]
33 | ^ table[(1 * 256) + input[offset + 14]]
34 | ^ table[(0 * 256) + input[offset + 15]];
35 |
36 | var b = table[(7 * 256) + input[offset + 8]]
37 | ^ table[(6 * 256) + input[offset + 9]]
38 | ^ table[(5 * 256) + input[offset + 10]]
39 | ^ table[(4 * 256) + input[offset + 11]];
40 |
41 | var c = table[(11 * 256) + input[offset + 4]]
42 | ^ table[(10 * 256) + input[offset + 5]]
43 | ^ table[(9 * 256) + input[offset + 6]]
44 | ^ table[(8 * 256) + input[offset + 7]];
45 |
46 | var d = table[(15 * 256) + ((crcLocal ^ input[offset]) & 0xff)]
47 | ^ table[(14 * 256) + (((crcLocal >> 8) ^ input[offset + 1]) & 0xff)]
48 | ^ table[(13 * 256) + (((crcLocal >> 16) ^ input[offset + 2]) & 0xff)]
49 | ^ table[(12 * 256) + (((crcLocal >> 24) ^ input[offset + 3]) & 0xff)];
50 |
51 | crcLocal = d ^ c ^ b ^ a;
52 | offset += 16;
53 | length -= 16;
54 | }
55 |
56 | while (--length >= 0)
57 | crcLocal = table[(crcLocal ^ input[offset++]) & 0xff] ^ crcLocal >> 8;
58 |
59 | return crcLocal ^ uint.MaxValue;
60 |
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/Crc32C/ICrc32CCalculator.cs:
--------------------------------------------------------------------------------
1 | namespace Force.Blazer.Algorithms.Crc32C
2 | {
3 | ///
4 | /// Interface for Crc32 calculators
5 | ///
6 | public interface ICrc32CCalculator
7 | {
8 | ///
9 | /// Calculates Crc32C data for buffer
10 | ///
11 | uint Calculate(uint crc, byte[] buffer, int offset, int count);
12 | }
13 | }
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/EncoderDecoderFactory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | using Force.Blazer.Native;
4 |
5 | namespace Force.Blazer.Algorithms
6 | {
7 | ///
8 | /// Factory for creating default encoders and decoders for Blazer algorithmns
9 | ///
10 | public class EncoderDecoderFactory
11 | {
12 | ///
13 | /// Returns decoder for algorithm
14 | ///
15 | public static IDecoder GetDecoder(BlazerAlgorithm algorithm)
16 | {
17 | switch (algorithm)
18 | {
19 | case BlazerAlgorithm.NoCompress: return new NoCompressionDecoder();
20 | case BlazerAlgorithm.Stream: return NativeHelper.IsNativeAvailable ? new StreamDecoderNative() : new StreamDecoder();
21 | case BlazerAlgorithm.Block: return NativeHelper.IsNativeAvailable ? new BlockDecoderNative() : new BlockDecoder();
22 | default: throw new NotImplementedException("Not supported algorithm: " + algorithm);
23 | }
24 | }
25 |
26 | ///
27 | /// Returns encoder for algorithm
28 | ///
29 | public static IEncoder GetEncoder(BlazerAlgorithm algorithm)
30 | {
31 | switch (algorithm)
32 | {
33 | case BlazerAlgorithm.NoCompress: return new NoCompressionEncoder();
34 | case BlazerAlgorithm.Stream: return NativeHelper.IsNativeAvailable ? new StreamEncoderNative() : new StreamEncoder();
35 | case BlazerAlgorithm.Block: return NativeHelper.IsNativeAvailable ? new BlockEncoderNative() : new BlockEncoder();
36 | default: throw new NotImplementedException("Not supported algorithm: " + algorithm);
37 | }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/IDecoder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Force.Blazer.Algorithms
4 | {
5 | ///
6 | /// Inteface for implementing decoders for Blazer algoritms
7 | ///
8 | public interface IDecoder : IDisposable
9 | {
10 | ///
11 | /// Decodes given buffer
12 | ///
13 | BufferInfo Decode(byte[] buffer, int offset, int length, bool isCompressed);
14 |
15 | ///
16 | /// Initializes decoder with information about maximum uncompressed block size
17 | ///
18 | void Init(int maxUncompressedBlockSize);
19 |
20 | ///
21 | /// Returns algorithm id
22 | ///
23 | BlazerAlgorithm GetAlgorithmId();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/IEncoder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Force.Blazer.Algorithms
4 | {
5 | ///
6 | /// Inteface for implementing encoders for Blazer algoritms
7 | ///
8 | public interface IEncoder : IDisposable
9 | {
10 | ///
11 | /// Encodes given buffer
12 | ///
13 | BufferInfo Encode(byte[] buffer, int offset, int length);
14 |
15 | ///
16 | /// Initializes encoder with information about maximum uncompressed block size
17 | ///
18 | void Init(int maxInBlockSize);
19 |
20 | ///
21 | /// Returns algorithm id
22 | ///
23 | BlazerAlgorithm GetAlgorithmId();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/NoCompressionDecoder.cs:
--------------------------------------------------------------------------------
1 | namespace Force.Blazer.Algorithms
2 | {
3 | ///
4 | /// Decoder of no compression version of Blazer algorithm
5 | ///
6 | /// This is dummy decoder can be used for testing or storing data with Blazer structure
7 | public class NoCompressionDecoder : IDecoder
8 | {
9 | ///
10 | /// Decodes given buffer
11 | ///
12 | public BufferInfo Decode(byte[] buffer, int offset, int length, bool isCompressed)
13 | {
14 | return new BufferInfo(buffer, offset, length);
15 | }
16 |
17 | ///
18 | /// Initializes decoder with information about maximum uncompressed block size
19 | ///
20 | public void Init(int maxUncompressedBlockSize)
21 | {
22 | }
23 |
24 | ///
25 | /// Returns algorithm id
26 | ///
27 | public BlazerAlgorithm GetAlgorithmId()
28 | {
29 | return BlazerAlgorithm.NoCompress;
30 | }
31 |
32 | ///
33 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
34 | ///
35 | /// 2
36 | public void Dispose()
37 | {
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/NoCompressionEncoder.cs:
--------------------------------------------------------------------------------
1 | namespace Force.Blazer.Algorithms
2 | {
3 | ///
4 | /// Encoder of no compression version of Blazer algorithm
5 | ///
6 | /// This is dummy decoder can be used for testing or storing data with Blazer structure
7 | public class NoCompressionEncoder : IEncoder
8 | {
9 | ///
10 | /// Encodes given buffer
11 | ///
12 | public BufferInfo Encode(byte[] buffer, int offset, int length)
13 | {
14 | return new BufferInfo(buffer, offset, length);
15 | }
16 |
17 | ///
18 | /// Initializes encoder with information about maximum uncompressed block size
19 | ///
20 | public void Init(int maxInBlockSize)
21 | {
22 | }
23 |
24 | ///
25 | /// Returns algorithm id
26 | ///
27 | public BlazerAlgorithm GetAlgorithmId()
28 | {
29 | return BlazerAlgorithm.NoCompress;
30 | }
31 |
32 | ///
33 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
34 | ///
35 | /// 2
36 | public void Dispose()
37 | {
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/Patterned/BasePatternedCompressor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics.CodeAnalysis;
3 | using System.Threading;
4 |
5 | namespace Force.Blazer.Algorithms.Patterned
6 | {
7 | ///
8 | /// Base implementation of Patterned Compressor/Decompressor
9 | ///
10 | public abstract class BasePatternedCompressor : IPatternedCompressor
11 | {
12 | ///
13 | /// Calculates max compressed buffer size for specified uncompressed data length
14 | ///
15 | public abstract int CalculateMaxCompressedBufferLength(int uncompressedLength);
16 |
17 | ///
18 | /// Initializes internal hash array
19 | ///
20 | protected abstract void InitHashArray();
21 |
22 | ///
23 | /// Restores internal hash array
24 | ///
25 | protected abstract void RestoreHashArray();
26 |
27 | ///
28 | /// Returns algorithm id
29 | ///
30 | protected abstract byte GetAlgorithmId();
31 |
32 | ///
33 | /// Inner buffer
34 | ///
35 | [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:FieldsMustBePrivate", Justification = "Reviewed. Suppression is OK here.")]
36 | protected byte[] _innerBuffer;
37 |
38 | ///
39 | /// Length of pattern
40 | ///
41 | [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:FieldsMustBePrivate", Justification = "Reviewed. Suppression is OK here.")]
42 | protected int _patternLength;
43 |
44 | ///
45 | /// Compress block of data
46 | ///
47 | protected abstract int CompressBlock(int countIn, byte[] bufferOut, int offsetOut);
48 |
49 | ///
50 | /// Prepares pattern. Should be called only once for one pattern
51 | ///
52 | public void PreparePattern(byte[] pattern, int offset, int count)
53 | {
54 | if (count <= 0)
55 | throw new InvalidOperationException("Invalid pattern length");
56 | var patternLength = count;
57 | _innerBuffer = new byte[patternLength * 2];
58 | var outerBuffer = new byte[CalculateMaxCompressedBufferLength(patternLength) + 1];
59 |
60 | Buffer.BlockCopy(pattern, offset, _innerBuffer, 0, patternLength);
61 | CompressBlock(patternLength, outerBuffer, 0);
62 | _patternLength = patternLength;
63 | InitHashArray();
64 | }
65 |
66 | ///
67 | /// Prepares pattern. Should be called only once for one pattern
68 | ///
69 | public void PreparePattern(byte[] pattern)
70 | {
71 | PreparePattern(pattern, 0, pattern.Length);
72 | }
73 |
74 | private int _isWorking;
75 |
76 | ///
77 | /// Encodes data with prepared pattern
78 | ///
79 | public int EncodeWithPattern(byte[] bufferIn, int offsetIn, int countIn, byte[] bufferOut, int offsetOut)
80 | {
81 | if (Interlocked.CompareExchange(ref _isWorking, 1, 0) != 0)
82 | throw new InvalidOperationException("Method is not thread safe ");
83 |
84 | try
85 | {
86 | var totalInLength = countIn + _patternLength;
87 | if (totalInLength > _innerBuffer.Length)
88 | {
89 | var oldInnerBuffer = _innerBuffer;
90 | _innerBuffer = new byte[totalInLength + 128];
91 | Buffer.BlockCopy(oldInnerBuffer, 0, _innerBuffer, 0, _patternLength);
92 | }
93 |
94 | Buffer.BlockCopy(bufferIn, offsetIn, _innerBuffer, _patternLength, countIn);
95 |
96 | if (bufferOut.Length - offsetOut < CalculateMaxCompressedBufferLength(countIn))
97 | throw new InvalidOperationException("Out buffer too small");
98 |
99 | var len = CompressBlock(countIn, bufferOut, offsetOut);
100 | var writtenCnt = len - offsetOut - 1;
101 | writtenCnt >>= 16;
102 | var lenCnt = 0;
103 | while (writtenCnt > 0)
104 | {
105 | lenCnt++;
106 | writtenCnt >>= 1;
107 | }
108 |
109 | // writing some metainfo to out buffer, to allow decode and validate data
110 | bufferOut[offsetOut] = (byte)(lenCnt | (GetAlgorithmId() << 4));
111 |
112 | RestoreHashArray();
113 | return len - offsetOut;
114 | }
115 | finally
116 | {
117 | Interlocked.Exchange(ref _isWorking, 0);
118 | }
119 | }
120 |
121 | ///
122 | /// Decompress block of data
123 | ///
124 | protected abstract int DecompressBlock(byte[] bufferIn, int offsetIn, int countIn);
125 |
126 | ///
127 | /// Decodes data with prepared pattern
128 | ///
129 | public int DecodeWithPattern(byte[] bufferIn, int offsetIn, int countIn, byte[] bufferOut, int offsetOut)
130 | {
131 | if (Interlocked.CompareExchange(ref _isWorking, 1, 0) != 0)
132 | throw new InvalidOperationException("Method is not thread safe ");
133 |
134 | try
135 | {
136 | var algFlag = bufferIn[offsetIn];
137 | var algorithm = algFlag >> 4;
138 | if (algorithm != GetAlgorithmId())
139 | throw new InvalidOperationException("Encoded data is not patterned data");
140 | var maxOutLength = ((algFlag + 1) & 0xf) << 16;
141 |
142 | var totalOutLength = _patternLength + maxOutLength;
143 | if (totalOutLength > _innerBuffer.Length)
144 | {
145 | var oldInnerBuffer = _innerBuffer;
146 | _innerBuffer = new byte[totalOutLength + 128];
147 | Buffer.BlockCopy(oldInnerBuffer, 0, _innerBuffer, 0, _patternLength);
148 | }
149 |
150 | var res = DecompressBlock(bufferIn, offsetIn, countIn);
151 | if (offsetOut + res - _patternLength > bufferOut.Length)
152 | throw new InvalidOperationException("Out buffer too small");
153 | Buffer.BlockCopy(_innerBuffer, _patternLength, bufferOut, offsetOut, res - _patternLength);
154 | return res - _patternLength;
155 | }
156 | finally
157 | {
158 | Interlocked.Exchange(ref _isWorking, 0);
159 | }
160 | }
161 |
162 | ///
163 | /// Encodes data with prepared pattern
164 | ///
165 | public byte[] EncodeWithPattern(byte[] buffer, int offset, int count)
166 | {
167 | var bufferOut = new byte[CalculateMaxCompressedBufferLength(count)];
168 | var cnt = EncodeWithPattern(buffer, offset, count, bufferOut, 0);
169 | Array.Resize(ref bufferOut, cnt);
170 | return bufferOut;
171 | }
172 |
173 | ///
174 | /// Encodes data with prepared pattern
175 | ///
176 | public byte[] EncodeWithPattern(byte[] buffer)
177 | {
178 | return EncodeWithPattern(buffer, 0, buffer.Length);
179 | }
180 |
181 | ///
182 | /// Decodes data with prepared pattern
183 | ///
184 | public byte[] DecodeWithPattern(byte[] buffer, int offset, int count)
185 | {
186 | var algFlag = buffer[offset];
187 | var maxOutLength = ((algFlag + 1) & 0xf) << 16;
188 |
189 | var bufferOut = new byte[maxOutLength];
190 | var cnt = DecodeWithPattern(buffer, offset, count, bufferOut, 0);
191 | Array.Resize(ref bufferOut, cnt);
192 | return bufferOut;
193 | }
194 |
195 | ///
196 | /// Decodes data with prepared pattern
197 | ///
198 | public byte[] DecodeWithPattern(byte[] buffer)
199 | {
200 | return DecodeWithPattern(buffer, 0, buffer.Length);
201 | }
202 | }
203 | }
204 |
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/Patterned/BlockPatternedCompressor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Force.Blazer.Algorithms.Patterned
4 | {
5 | ///
6 | /// Patterned Compressor/Decompressor for Blazer Block algorithm
7 | ///
8 | public class BlockPatternedCompressor : BasePatternedCompressor
9 | {
10 | private readonly BlockEncoder _encoder;
11 |
12 | private readonly BlockDecoder _decoder;
13 |
14 | private int[] _hashArrClone;
15 |
16 | ///
17 | /// Initializes patterned compressor
18 | ///
19 | public BlockPatternedCompressor()
20 | {
21 | _encoder = (BlockEncoder)EncoderDecoderFactory.GetEncoder(BlazerAlgorithm.Block);
22 | _decoder = (BlockDecoder)EncoderDecoderFactory.GetDecoder(BlazerAlgorithm.Block);
23 | }
24 |
25 | ///
26 | /// Calculates max compressed buffer size for specified uncompressed data length
27 | ///
28 | public override int CalculateMaxCompressedBufferLength(int uncompressedLength)
29 | {
30 | return uncompressedLength + (uncompressedLength >> 8) + 3 + /*_encoder.GetAdditionalInSize()*/ + 1;
31 | }
32 |
33 | ///
34 | /// Initializes HashArray for Encoder
35 | ///
36 | protected override void InitHashArray()
37 | {
38 | _hashArrClone = new int[_encoder.HashArr.Length];
39 | Array.Copy(_encoder.HashArr, 0, _hashArrClone, 0, _hashArrClone.Length);
40 | }
41 |
42 | ///
43 | /// Restores HashArray for Encoder
44 | ///
45 | protected override void RestoreHashArray()
46 | {
47 | Array.Copy(_hashArrClone, 0, _encoder.HashArr, 0, _hashArrClone.Length);
48 | }
49 |
50 | ///
51 | /// Returns algorithm id
52 | ///
53 | protected override byte GetAlgorithmId()
54 | {
55 | return (byte)_encoder.GetAlgorithmId();
56 | }
57 |
58 | ///
59 | /// Compress block of data
60 | ///
61 | protected override int CompressBlock(int countIn, byte[] bufferOut, int offsetOut)
62 | {
63 | return _encoder.CompressBlock(_innerBuffer, _patternLength, _patternLength + countIn, bufferOut, offsetOut + 1, false);
64 | }
65 |
66 | ///
67 | /// Decompress block of data
68 | ///
69 | protected override int DecompressBlock(byte[] bufferIn, int offsetIn, int countIn)
70 | {
71 | var res = _decoder.DecompressBlock(bufferIn, offsetIn + 1, offsetIn + countIn, _innerBuffer, _patternLength, _innerBuffer.Length, false);
72 | RestoreHashArray();
73 | return res;
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/Patterned/IPatternedCompressor.cs:
--------------------------------------------------------------------------------
1 | namespace Force.Blazer.Algorithms.Patterned
2 | {
3 | ///
4 | /// Common interface for Pattened Encoder/Decoder
5 | ///
6 | public interface IPatternedCompressor
7 | {
8 | ///
9 | /// Calculates max compressed buffer size for specified uncompressed data length
10 | ///
11 | int CalculateMaxCompressedBufferLength(int uncompressedLength);
12 |
13 | ///
14 | /// Prepares pattern. Should be called only once for pattern
15 | ///
16 | void PreparePattern(byte[] pattern);
17 |
18 | ///
19 | /// Prepares pattern. Should be called only once for pattern
20 | ///
21 | void PreparePattern(byte[] pattern, int offset, int length);
22 |
23 | ///
24 | /// Encodes data with prepared pattern
25 | ///
26 | int EncodeWithPattern(byte[] bufferIn, int offsetIn, int countIn, byte[] bufferOut, int offsetOut);
27 |
28 | ///
29 | /// Decodes data with prepared pattern
30 | ///
31 | int DecodeWithPattern(byte[] bufferIn, int offsetIn, int countIn, byte[] bufferOut, int offsetOut);
32 |
33 | ///
34 | /// Encodes data with prepared pattern
35 | ///
36 | byte[] EncodeWithPattern(byte[] buffer, int offset, int count);
37 |
38 | ///
39 | /// Encodes data with prepared pattern
40 | ///
41 | byte[] EncodeWithPattern(byte[] buffer);
42 |
43 | ///
44 | /// Decodes data with prepared pattern
45 | ///
46 | byte[] DecodeWithPattern(byte[] buffer, int offset, int count);
47 |
48 | ///
49 | /// Decodes data with prepared pattern
50 | ///
51 | byte[] DecodeWithPattern(byte[] buffer);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/Patterned/StreamHighPatternedCompressor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Force.Blazer.Algorithms.Patterned
4 | {
5 | ///
6 | /// Patterned Compressor/Decompressor for Blazer Stream High algorithm
7 | ///
8 | /// Method is very slow to use in normal situations. Use only when needed in your specific case
9 | public class StreamHighPatternedCompressor : StreamPatternedCompressor
10 | {
11 | private readonly StreamEncoderHigh _encoder;
12 |
13 | ///
14 | /// Initializes patterned compressor
15 | ///
16 | public StreamHighPatternedCompressor()
17 | {
18 | _encoder = new StreamEncoderHigh();
19 | _encoder.Init(0);
20 | }
21 |
22 | private int[][] _hashArrClone;
23 |
24 | private int[] _hashArrPosClone;
25 |
26 | ///
27 | /// Initializes HashArray for Encoder
28 | ///
29 | protected override void InitHashArray()
30 | {
31 | _hashArrClone = new int[StreamEncoderHigh.HASHARR_CNT][];
32 | var e = _encoder.HashArr2;
33 | for (var i = 0; i < StreamEncoderHigh.HASHARR_CNT; i++)
34 | {
35 | _hashArrClone[i] = new int[e[i].Length];
36 | Array.Copy(e[i], 0, _hashArrClone[i], 0, e[i].Length);
37 | }
38 |
39 | _hashArrPosClone = new int[_encoder.HashArrPos.Length];
40 | Array.Copy(_encoder.HashArrPos, 0, _hashArrPosClone, 0, _hashArrPosClone.Length);
41 | }
42 |
43 | ///
44 | /// Restores HashArray for Encoder
45 | ///
46 | protected override void RestoreHashArray()
47 | {
48 | var e = _encoder.HashArr2;
49 | for (var i = 0; i < StreamEncoderHigh.HASHARR_CNT; i++)
50 | {
51 | Array.Copy(_hashArrClone[i], 0, e[i], 0, e[i].Length);
52 | }
53 |
54 | Array.Copy(_hashArrPosClone, 0, _encoder.HashArrPos, 0, _hashArrPosClone.Length);
55 | }
56 |
57 | ///
58 | /// Compress block of data
59 | ///
60 | protected override int CompressBlock(int countIn, byte[] bufferOut, int offsetOut)
61 | {
62 | return _encoder.CompressBlock(_innerBuffer, _patternLength, _patternLength + countIn, 0, bufferOut, offsetOut + 1);
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/Patterned/StreamPatternedCompressor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Force.Blazer.Algorithms.Patterned
4 | {
5 | ///
6 | /// Patterned Compressor/Decompressor for Blazer Stream algorithm
7 | ///
8 | public class StreamPatternedCompressor : BasePatternedCompressor
9 | {
10 | private readonly StreamEncoder _encoder;
11 |
12 | private readonly StreamDecoder _decoder;
13 |
14 | private int[] _hashArrClone;
15 |
16 | ///
17 | /// Initializes patterned compressor
18 | ///
19 | public StreamPatternedCompressor()
20 | {
21 | _encoder = (StreamEncoder)EncoderDecoderFactory.GetEncoder(BlazerAlgorithm.Stream);
22 | _decoder = (StreamDecoder)EncoderDecoderFactory.GetDecoder(BlazerAlgorithm.Stream);
23 | }
24 |
25 | ///
26 | /// Calculates max compressed buffer size for specified uncompressed data length
27 | ///
28 | public override int CalculateMaxCompressedBufferLength(int uncompressedLength)
29 | {
30 | return uncompressedLength + (uncompressedLength >> 8) + 3 + _encoder.GetAdditionalInSize() + 1;
31 | }
32 |
33 | ///
34 | /// Initializes HashArray for Encoder
35 | ///
36 | protected override void InitHashArray()
37 | {
38 | _hashArrClone = new int[_encoder.HashArr.Length];
39 | Array.Copy(_encoder.HashArr, 0, _hashArrClone, 0, _hashArrClone.Length);
40 | }
41 |
42 | ///
43 | /// Restores HashArray for Encoder
44 | ///
45 | protected override void RestoreHashArray()
46 | {
47 | Array.Copy(_hashArrClone, 0, _encoder.HashArr, 0, _hashArrClone.Length);
48 | }
49 |
50 | ///
51 | /// Returns algorithm id
52 | ///
53 | protected override byte GetAlgorithmId()
54 | {
55 | return (byte)_encoder.GetAlgorithmId();
56 | }
57 |
58 | ///
59 | /// Compress block of data
60 | ///
61 | protected override int CompressBlock(int countIn, byte[] bufferOut, int offsetOut)
62 | {
63 | return _encoder.CompressBlock(_innerBuffer, _patternLength, _patternLength + countIn, 0, bufferOut, offsetOut + 1);
64 | }
65 |
66 | ///
67 | /// Decompress block of data
68 | ///
69 | protected override int DecompressBlock(byte[] bufferIn, int offsetIn, int countIn)
70 | {
71 | return _decoder.DecompressBlock(bufferIn, offsetIn + 1, offsetIn + countIn, _innerBuffer, _patternLength, _innerBuffer.Length);
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/StreamDecoder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics.CodeAnalysis;
3 |
4 | namespace Force.Blazer.Algorithms
5 | {
6 | ///
7 | /// Decoder of Stream version of Blazer algorithm
8 | ///
9 | /// Stream version is good for 'live' streamss, slightly slower than Block, but support stream flushing without
10 | /// losing compression rate and has very fast decoder
11 | public class StreamDecoder : IDecoder
12 | {
13 | ///
14 | /// Inner buffer to store data between iterations
15 | ///
16 | [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:FieldsMustBePrivate", Justification = "Reviewed. Suppression is OK here.")]
17 | protected byte[] _innerBuffer;
18 |
19 | private int _innerBufferMaxLen = 0;
20 |
21 | private int _innerBufferLen = 0;
22 |
23 | ///
24 | /// Initializes decoder with information about maximum uncompressed block size
25 | ///
26 | public virtual void Init(int maxUncompressedBlockSize)
27 | {
28 | _innerBufferMaxLen = maxUncompressedBlockSize + StreamEncoder.MAX_BACK_REF + 1;
29 | _innerBuffer = new byte[_innerBufferMaxLen];
30 | }
31 |
32 | ///
33 | /// Decodes given buffer
34 | ///
35 | public BufferInfo Decode(byte[] buffer, int offset, int length, bool isCompressed)
36 | {
37 | if (_innerBufferLen > StreamEncoder.MAX_BACK_REF)
38 | {
39 | Buffer.BlockCopy(_innerBuffer, _innerBufferLen - StreamEncoder.MAX_BACK_REF, _innerBuffer, 0, StreamEncoder.MAX_BACK_REF);
40 | _innerBufferLen = StreamEncoder.MAX_BACK_REF;
41 | }
42 |
43 | var outOffset = _innerBufferLen;
44 |
45 | if (isCompressed)
46 | _innerBufferLen = DecompressBlock(buffer, offset, length, _innerBuffer, _innerBufferLen, _innerBufferMaxLen);
47 | else
48 | {
49 | Buffer.BlockCopy(buffer, offset, _innerBuffer, _innerBufferLen, length - offset);
50 | _innerBufferLen += length - offset;
51 | }
52 |
53 | return new BufferInfo(_innerBuffer, outOffset, _innerBufferLen);
54 | }
55 |
56 | ///
57 | /// Returns algorithm id
58 | ///
59 | public BlazerAlgorithm GetAlgorithmId()
60 | {
61 | return BlazerAlgorithm.Stream;
62 | }
63 |
64 | ///
65 | /// Decompresses block of data
66 | ///
67 | public virtual int DecompressBlock(
68 | byte[] bufferIn, int bufferInOffset, int bufferInLength, byte[] bufferOut, int bufferOutOffset, int bufferOutLength)
69 | {
70 | return DecompressBlockExternal(bufferIn, bufferInOffset, bufferInLength, ref bufferOut, bufferOutOffset, bufferOutLength, false);
71 | }
72 |
73 | ///
74 | /// Decompresses independent block of data
75 | ///
76 | /// In buffer
77 | /// Decompressed data
78 | public static byte[] DecompressData(
79 | byte[] bufferIn)
80 | {
81 | var outBuffer = new byte[bufferIn.Length * 2];
82 | var count = DecompressBlockExternal(bufferIn, 0, bufferIn.Length, ref outBuffer, 0, outBuffer.Length, true);
83 | Array.Resize(ref outBuffer, count);
84 | return outBuffer;
85 | }
86 |
87 | ///
88 | /// Decompresses block of data, can be used independently for byte arrays
89 | ///
90 | /// In buffer
91 | /// In buffer offset
92 | /// In buffer right offset (offset + count)
93 | /// Out buffer, should be enough size
94 | /// Out buffer offset
95 | /// Out buffer maximum right offset (offset + count)
96 | /// Resize out buffer if smaller than required
97 | /// Bytes count of decompressed data
98 | public static int DecompressBlockExternal(byte[] bufferIn, int bufferInOffset, int bufferInLength, ref byte[] bufferOut, int bufferOutOffset, int bufferOutLength, bool resizeOutBufferIfNeeded)
99 | {
100 | var idxIn = bufferInOffset;
101 | var idxOut = bufferOutOffset;
102 | while (idxIn < bufferInLength)
103 | {
104 | var elem = bufferIn[idxIn++];
105 | var seqCntFirst = elem & 0xf;
106 | var litCntFirst = (elem >> 4) & 7;
107 |
108 | var litCnt = litCntFirst;
109 | int seqCnt;
110 | int backRef;
111 |
112 | if (elem >= 128)
113 | {
114 | backRef = (bufferIn[idxIn++] | bufferIn[idxIn++] << 8) + 257;
115 | seqCnt = seqCntFirst + 4;
116 | if (backRef == 0xffff + 257)
117 | {
118 | seqCntFirst = 0;
119 | seqCnt = 0;
120 | litCnt = elem - 128;
121 | litCntFirst = litCnt == 127 ? 7 : 0;
122 | // backRef = 0;
123 | }
124 | }
125 | else
126 | {
127 | backRef = bufferIn[idxIn++] + 1;
128 | seqCnt = seqCntFirst + 4;
129 | }
130 |
131 | if (litCntFirst == 7)
132 | {
133 | var litCntR = bufferIn[idxIn++];
134 | if (litCntR < 253) litCnt += litCntR;
135 | else if (litCntR == 253)
136 | litCnt += 253 + bufferIn[idxIn++];
137 | else if (litCntR == 254)
138 | litCnt += 253 + 256 + (bufferIn[idxIn++] | bufferIn[idxIn++] << 8);
139 | else
140 | litCnt += 253 + (256 * 256) + (bufferIn[idxIn++] << 0) + (bufferIn[idxIn++] << 8) + (bufferIn[idxIn++] << 16) + (bufferIn[idxIn++] << 24);
141 | }
142 |
143 | if (seqCntFirst == 15)
144 | {
145 | var seqCntR = bufferIn[idxIn++];
146 | if (seqCntR < 253) seqCnt += seqCntR;
147 | else if (seqCntR == 253)
148 | seqCnt += 253 + bufferIn[idxIn++];
149 | else if (seqCntR == 254)
150 | seqCnt += 253 + 256 + (bufferIn[idxIn++] << 0 | bufferIn[idxIn++] << 8);
151 | else
152 | seqCnt += 253 + (256 * 256) + (bufferIn[idxIn++] << 0) + (bufferIn[idxIn++] << 8) + (bufferIn[idxIn++] << 16) + (bufferIn[idxIn++] << 24);
153 | }
154 |
155 | var maxOutLength = idxOut + litCnt + seqCnt;
156 | if (maxOutLength > bufferOutLength)
157 | {
158 | if (resizeOutBufferIfNeeded)
159 | {
160 | bufferOutLength = Math.Max(bufferOut.Length * 2, maxOutLength);
161 | Array.Resize(ref bufferOut, bufferOutLength);
162 | }
163 | else
164 | throw new IndexOutOfRangeException("Invalid stream structure");
165 | }
166 |
167 | if (litCnt >= 8)
168 | {
169 | Buffer.BlockCopy(bufferIn, idxIn, bufferOut, idxOut, litCnt);
170 | idxOut += litCnt;
171 | idxIn += litCnt;
172 | }
173 | else
174 | {
175 | while (--litCnt >= 0) bufferOut[idxOut++] = bufferIn[idxIn++];
176 | }
177 |
178 | // exception wil be thrown anyway, but this check decreases decompression speed
179 | // if (idxOut - backRef < 0)
180 | // throw new InvalidOperationException("Invalid stream structure");
181 |
182 | if (backRef >= seqCnt && seqCnt >= 8)
183 | {
184 | Buffer.BlockCopy(bufferOut, idxOut - backRef, bufferOut, idxOut, seqCnt);
185 | idxOut += seqCnt;
186 | }
187 | else
188 | {
189 | while (--seqCnt >= 0)
190 | {
191 | bufferOut[idxOut] = bufferOut[idxOut - backRef];
192 | idxOut++;
193 | }
194 | }
195 | }
196 |
197 | return idxOut;
198 | }
199 |
200 | ///
201 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
202 | ///
203 | /// 2
204 | public virtual void Dispose()
205 | {
206 | }
207 | }
208 | }
209 |
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/StreamDecoderNative.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace Force.Blazer.Algorithms
5 | {
6 | ///
7 | /// Native implementation of decoder of Stream version of Blazer algorithm
8 | ///
9 | /// Stream version is good for 'live' streamss, slightly slower than Block, but support stream flushing without
10 | /// losing compression rate and has very fast decoder
11 | public class StreamDecoderNative : StreamDecoder
12 | {
13 | [DllImport(@"Blazer.Native.dll", CallingConvention = CallingConvention.Cdecl)]
14 | private static extern int blazer_stream_decompress_block(
15 | byte[] bufferIn, int bufferInOffset, int bufferInLength, byte[] bufferOut, int bufferOutOffset, int bufferOutLength);
16 |
17 | ///
18 | /// Initializes decoder with information about maximum uncompressed block size
19 | ///
20 | public override void Init(int maxUncompressedBlockSize)
21 | {
22 | // +8 for better copying speed. allow dummy copy by 8 bytes
23 | base.Init(maxUncompressedBlockSize + 8);
24 | }
25 |
26 | ///
27 | /// Decompresses block of data
28 | ///
29 | public override int DecompressBlock(
30 | byte[] bufferIn, int bufferInOffset, int bufferInLength, byte[] bufferOut, int bufferOutOffset, int bufferOutLength)
31 | {
32 | var cnt = blazer_stream_decompress_block(
33 | bufferIn, bufferInOffset, bufferInLength, bufferOut, bufferOutOffset, bufferOutLength);
34 | if (cnt < 0)
35 | throw new InvalidOperationException("Invalid compressed data");
36 | return cnt;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Blazer.Net/Algorithms/StreamEncoderNative.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace Force.Blazer.Algorithms
4 | {
5 | ///
6 | /// Native implementation of Stream version encoder of Blazer algorithm
7 | ///
8 | /// Stream version is good for 'live' streamss, slightly slower than Block, but support stream flushing without
9 | /// losing compression rate and has very fast decoder
10 | public class StreamEncoderNative : StreamEncoder
11 | {
12 | [DllImport(@"Blazer.Native.dll", CallingConvention = CallingConvention.Cdecl)]
13 | private static extern int blazer_stream_compress_block(
14 | byte[] bufferIn, int bufferInOffset, int bufferInLength, int globalOffset, byte[] bufferOut, int bufferOutOffset, int[] hashArr);
15 |
16 | ///
17 | /// Returns additional size for inner buffers. Can be used to store some data or for optimiations
18 | ///
19 | /// Size in bytes
20 | public override int GetAdditionalInSize()
21 | {
22 | return 8;
23 | }
24 |
25 | ///
26 | /// Compresses block of data. See for details
27 | ///
28 | public override int CompressBlock(
29 | byte[] bufferIn,
30 | int bufferInOffset,
31 | int bufferInLength,
32 | int bufferInShift,
33 | byte[] bufferOut,
34 | int bufferOutOffset)
35 | {
36 | return blazer_stream_compress_block(
37 | bufferIn,
38 | bufferInOffset,
39 | bufferInLength,
40 | bufferInShift,
41 | bufferOut,
42 | bufferOutOffset,
43 | _hashArr);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Blazer.Net/Blazer.Net.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {026EE2B9-3367-480A-8B46-118F4037C827}
8 | Library
9 | Properties
10 | Force.Blazer
11 | Blazer.Net
12 | v4.0
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 | false
24 |
25 |
26 | none
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
32 | false
33 | bin\Release\Blazer.Net.xml
34 |
35 |
36 | true
37 |
38 |
39 | true
40 |
41 |
42 | ..\public.snk
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | public.snk
100 |
101 |
102 |
103 |
104 | Resources\Blazer.Native.x64.dll
105 |
106 |
107 | Resources\Blazer.Native.x86.dll
108 |
109 |
110 |
111 |
112 | cmd /c if exist "$(ProjectDir)sign.cmd" "$(ProjectDir)sign.cmd" "$(TargetPath)" "$(SolutionDir)private.snk"
113 |
114 |
121 |
--------------------------------------------------------------------------------
/Blazer.Net/Blazer.Net.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Blazer.Net
5 | Blazer.Net
6 | 0.10.1
7 | force
8 | force
9 | https://github.com/force-net/blazer/blob/develop/LICENSE
10 | https://github.com/force-net/blazer
11 | http://files.force-net.com/blazer-nuget-ico.png
12 | false
13 | Blazer is high-performance, low compression archiver.
14 |
15 | Blazer is high-performance, low compression archiver.
16 | Main usage to work with streams, but can be used as general archiver or for reducing application size by compressing it resources.
17 | Compression rate is comparable (slightly better) to LZ4 and Snappy and compression speed is really faster than GZip.
18 | Blazer contains all standard features for archives, but also it is possible to use control commands in stream, encrypt archive, use it as simple (but fast) crc32c calulator, perform patterned compresstion and many others features.
19 |
20 | See project site for detailed information.
21 |
22 |
23 | - Fixed an issue with loading of native library for dotnet core on Windows
24 | - Fixed issue with seeking of MemoryStream with offset (Position/Seek gives different results)
25 | - Improved Api for DataArrayHelper
26 |
27 | Copyright by Force 2016-2018
28 | .NET fast compression archive crc32c archiver
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Blazer.Net/Blazer.Net.xproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 14.0
5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0
6 |
7 |
8 |
9 |
10 | {1697F214-4621-4366-8313-CF729755BBDF}
11 | Blazer.Net
12 | .\obj
13 | .\bin\
14 | v4.6.1
15 |
16 |
17 |
18 | 2.0
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Blazer.Net/BlazerAlgorithm.cs:
--------------------------------------------------------------------------------
1 | namespace Force.Blazer
2 | {
3 | ///
4 | /// Blazer algorithm
5 | ///
6 | public enum BlazerAlgorithm : byte
7 | {
8 | ///
9 | /// No compression. Can be used for non-compressible data or for keeping stream stucture
10 | ///
11 | NoCompress = 0,
12 |
13 | ///
14 | /// Stream compression. Effective for 'live' streams
15 | ///
16 | Stream = 1,
17 |
18 | ///
19 | /// Block compression. Effective for compressing files
20 | ///
21 | Block = 2
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Blazer.Net/BlazerBlockType.cs:
--------------------------------------------------------------------------------
1 | namespace Force.Blazer
2 | {
3 | ///
4 | /// Block type of Blazer archive
5 | ///
6 | public enum BlazerBlockType : byte
7 | {
8 | ///
9 | /// Empty control block
10 | ///
11 | ControlDataEmpty = 0xf0,
12 |
13 | ///
14 | /// Control block
15 | ///
16 | ControlData = 0xf1,
17 |
18 | ///
19 | /// File info block
20 | ///
21 | Comment = 0xf9,
22 |
23 | // FileInfoIndex = 0xfc
24 |
25 | ///
26 | /// File info block
27 | ///
28 | FileInfo = 0xfd,
29 |
30 | // FileInfoRef = 0xfe
31 |
32 | ///
33 | /// Footer block
34 | ///
35 | Footer = 0xff
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Blazer.Net/BlazerCompressionOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | using Force.Blazer.Algorithms;
5 |
6 | namespace Force.Blazer
7 | {
8 | ///
9 | /// Options for compression
10 | ///
11 | public class BlazerCompressionOptions
12 | {
13 | ///
14 | /// Encoder (realization of compression algorithm)
15 | ///
16 | public IEncoder Encoder { get; set; }
17 |
18 | private BlazerFlags _flags { get; set; }
19 |
20 | ///
21 | /// Password for encrypting data
22 | ///
23 | public string Password
24 | {
25 | get
26 | {
27 | return PasswordRaw == null ? null : Encoding.UTF8.GetString(PasswordRaw);
28 | }
29 |
30 | set
31 | {
32 | PasswordRaw = string.IsNullOrEmpty(value) ? null : Encoding.UTF8.GetBytes(value);
33 | }
34 | }
35 |
36 | ///
37 | /// Password for encrypting data (raw binary variant)
38 | ///
39 | public byte[] PasswordRaw { get; set; }
40 |
41 | ///
42 | /// Encrypt full flag. Fully encypted streams does not reveal any information about inner data (blazer header is also encypted)
43 | ///
44 | /// Flush can be unsupported with this mode
45 | public bool EncryptFull { get; set; }
46 |
47 | ///
48 | /// Leave inner stream open after closing blazer stream
49 | ///
50 | public bool LeaveStreamOpen { get; set; }
51 |
52 | ///
53 | /// Add Crc data to stream. If data are damaged, error will occure
54 | ///
55 | /// Blazer uses Crc32C checksum algorithm
56 | public bool IncludeCrc
57 | {
58 | get
59 | {
60 | return GetFlag(BlazerFlags.IncludeCrc);
61 | }
62 |
63 | set
64 | {
65 | SetFlag(BlazerFlags.IncludeCrc, value);
66 | }
67 | }
68 |
69 | ///
70 | /// Add header to stream. Stream without header requires manual flags set on decompression
71 | ///
72 | public bool IncludeHeader
73 | {
74 | get
75 | {
76 | return GetFlag(BlazerFlags.IncludeHeader);
77 | }
78 |
79 | set
80 | {
81 | SetFlag(BlazerFlags.IncludeHeader, value);
82 | }
83 | }
84 |
85 | ///
86 | /// Add footer to stream. Footer allows to check on decompression that stream is correct
87 | ///
88 | /// If on decompression stream is not seekable, footer will be validated only after decompressing data. If stream is seekable, before it.
89 | public bool IncludeFooter
90 | {
91 | get
92 | {
93 | return GetFlag(BlazerFlags.IncludeFooter);
94 | }
95 |
96 | set
97 | {
98 | SetFlag(BlazerFlags.IncludeFooter, value);
99 | }
100 | }
101 |
102 | ///
103 | /// Respect command.
104 | ///
105 | /// If it set, every flush will compress current block of data and Flush it into inner stream. Otherwise, flush commands are ignored
106 | public BlazerFlushMode FlushMode { get; set; }
107 |
108 | ///
109 | /// Maximum block size to compress. Larger blocks require more memory, but can produce higher compression
110 | ///
111 | /// Currently, block sizes from 512 bytes to 16Mb are supported
112 | public int MaxBlockSize
113 | {
114 | get
115 | {
116 | var cnt = (int)(_flags & BlazerFlags.InBlockSize16M);
117 | return 1 << (cnt + 9);
118 | }
119 |
120 | set
121 | {
122 | if (value < 0)
123 | throw new ArgumentOutOfRangeException("value", "Block size should be positive");
124 | var v = value - 1;
125 | var cnt = 0;
126 | while (v > 0)
127 | {
128 | cnt++;
129 | v >>= 1;
130 | }
131 |
132 | cnt -= 9;
133 | if (cnt < 0) cnt = 0;
134 |
135 | if (cnt > 15) cnt = 15;
136 | _flags &= ~BlazerFlags.InBlockSize16M;
137 | _flags |= (BlazerFlags)cnt;
138 | }
139 | }
140 |
141 | ///
142 | /// Sets max block size from flags
143 | ///
144 | public void SetMaxBlockSizeFromFlags(BlazerFlags sizeFlags)
145 | {
146 | _flags &= ~BlazerFlags.InBlockSize16M;
147 | _flags |= sizeFlags & BlazerFlags.InBlockSize16M;
148 | }
149 |
150 | ///
151 | /// Gets default block size for Stream algorithm
152 | ///
153 | public static int DefaultStreamBlockSize
154 | {
155 | get
156 | {
157 | return 65536;
158 | }
159 | }
160 |
161 | ///
162 | /// Gets default block size for Block algorithm
163 | ///
164 | public static int DefaultBlockBlockSize
165 | {
166 | get
167 | {
168 | // 2Mb
169 | return 1 << 21;
170 | }
171 | }
172 |
173 | ///
174 | /// Creates default options for no compression algorithm
175 | ///
176 | public static BlazerCompressionOptions CreateNoCompression()
177 | {
178 | return new BlazerCompressionOptions
179 | {
180 | Encoder = EncoderDecoderFactory.GetEncoder(BlazerAlgorithm.NoCompress),
181 | _flags = BlazerFlags.DefaultStream
182 | };
183 | }
184 |
185 | ///
186 | /// Creates default options for Stream algorithm
187 | ///
188 | public static BlazerCompressionOptions CreateStream()
189 | {
190 | return new BlazerCompressionOptions
191 | {
192 | Encoder = EncoderDecoderFactory.GetEncoder(BlazerAlgorithm.Stream),
193 | _flags = BlazerFlags.DefaultStream,
194 | FlushMode = BlazerFlushMode.RespectFlush
195 | };
196 | }
197 |
198 | ///
199 | /// Creates default options for Stream algorithm with high compression
200 | ///
201 | public static BlazerCompressionOptions CreateStreamHigh()
202 | {
203 | return new BlazerCompressionOptions
204 | {
205 | Encoder = new StreamEncoderHigh(),
206 | _flags = BlazerFlags.DefaultStream,
207 | FlushMode = BlazerFlushMode.RespectFlush
208 | };
209 | }
210 |
211 | ///
212 | /// Creates default options for Block algorithm
213 | ///
214 | public static BlazerCompressionOptions CreateBlock()
215 | {
216 | return new BlazerCompressionOptions
217 | {
218 | Encoder = EncoderDecoderFactory.GetEncoder(BlazerAlgorithm.Block),
219 | _flags = BlazerFlags.DefaultBlock
220 | };
221 | }
222 |
223 | ///
224 | /// Returns bit flags for current settings
225 | ///
226 | public BlazerFlags GetFlags()
227 | {
228 | var flags = _flags;
229 | if (PasswordRaw != null && PasswordRaw.Length != 0)
230 | {
231 | flags |= EncryptFull ? BlazerFlags.EncryptOuter : BlazerFlags.EncryptInner;
232 | }
233 |
234 | if (FlushMode != BlazerFlushMode.IgnoreFlush)
235 | flags |= BlazerFlags.RespectFlush;
236 |
237 | return flags;
238 | }
239 |
240 | private void SetFlag(BlazerFlags flag, bool isSet)
241 | {
242 | if (isSet) _flags |= flag;
243 | else _flags &= ~flag;
244 | }
245 |
246 | private bool GetFlag(BlazerFlags flag)
247 | {
248 | return (_flags & flag) != 0;
249 | }
250 |
251 | ///
252 | /// Instantiates default encoder for specified algoritm
253 | ///
254 | public void SetEncoderByAlgorithm(BlazerAlgorithm algorithm)
255 | {
256 | Encoder = EncoderDecoderFactory.GetEncoder(algorithm);
257 | }
258 |
259 | private BlazerFileInfo _fileInfo;
260 |
261 | private byte[] _commentRaw;
262 |
263 | ///
264 | /// Gets or sets information about encoded file
265 | ///
266 | public BlazerFileInfo FileInfo
267 | {
268 | get
269 | {
270 | return _fileInfo;
271 | }
272 |
273 | set
274 | {
275 | if (GetFlag(BlazerFlags.MultipleFiles) && value != null)
276 | throw new InvalidOperationException("Do not set FileInfo in multiple files mode mode");
277 | _fileInfo = value;
278 | SetFlag(BlazerFlags.OnlyOneFile, _fileInfo != null);
279 | }
280 | }
281 |
282 | ///
283 | /// Marks, that archive can contains multiple file, pass file info through
284 | ///
285 | public bool MultipleFiles
286 | {
287 | get
288 | {
289 | return GetFlag(BlazerFlags.MultipleFiles);
290 | }
291 |
292 | set
293 | {
294 | if (GetFlag(BlazerFlags.OnlyOneFile) && value)
295 | throw new InvalidOperationException("Do not set FileInfo in this mode");
296 | SetFlag(BlazerFlags.MultipleFiles, value);
297 | }
298 | }
299 |
300 | ///
301 | /// Gets or sets archive comment
302 | ///
303 | public string Comment
304 | {
305 | get
306 | {
307 | return CommentRaw == null ? null : Encoding.UTF8.GetString(CommentRaw);
308 | }
309 |
310 | set
311 | {
312 | CommentRaw = value == null ? null : Encoding.UTF8.GetBytes(value);
313 | }
314 | }
315 |
316 | ///
317 | /// Gets or sets archive raw (binary) comment. Useful for adding some info for technical streams
318 | ///
319 | public byte[] CommentRaw
320 | {
321 | get
322 | {
323 | return _commentRaw;
324 | }
325 |
326 | set
327 | {
328 | _commentRaw = value;
329 | SetFlag(BlazerFlags.IncludeComment, value != null && value.Length > 0);
330 | }
331 | }
332 | }
333 | }
334 |
--------------------------------------------------------------------------------
/Blazer.Net/BlazerDecompressionOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | using Force.Blazer.Algorithms;
5 |
6 | namespace Force.Blazer
7 | {
8 | ///
9 | /// Options for decompression
10 | ///
11 | public class BlazerDecompressionOptions
12 | {
13 | ///
14 | /// Initialize this property for archive without header, to provide required information for decompression
15 | ///
16 | public BlazerCompressionOptions CompressionOptions { get; set; }
17 |
18 | ///
19 | /// Initialize this property for archive without header, to provide custom decoder
20 | ///
21 | public IDecoder Decoder { get; set; }
22 |
23 | ///
24 | /// Set default decoder by algorithm
25 | ///
26 | public void SetDecoderByAlgorithm(BlazerAlgorithm algorithm)
27 | {
28 | Decoder = EncoderDecoderFactory.GetDecoder(algorithm);
29 | }
30 |
31 | ///
32 | /// Leave inner stream open after closing blazer stream
33 | ///
34 | public bool LeaveStreamOpen { get; set; }
35 |
36 | ///
37 | /// Password for encrypting data
38 | ///
39 | public string Password
40 | {
41 | get
42 | {
43 | return PasswordRaw == null ? null : Encoding.UTF8.GetString(PasswordRaw);
44 | }
45 |
46 | set
47 | {
48 | PasswordRaw = string.IsNullOrEmpty(value) ? null : Encoding.UTF8.GetBytes(value);
49 | }
50 | }
51 |
52 | ///
53 | /// Password for decrypting data (raw binary variant)
54 | ///
55 | public byte[] PasswordRaw { get; set; }
56 |
57 | ///
58 | /// Encrypt full flag. Fully encypted streams does not reveal any information about inner data (blazer header is also encypted)
59 | ///
60 | public bool EncyptFull { get; set; }
61 |
62 | ///
63 | /// Disable seeking for inner stream
64 | ///
65 | /// By default, checks is stream seekable. But with this flag this check can be disabled and seek will not be performed for any stream.
66 | /// This also can be useful for muliple joined streams, when only part of real stream is a Blazer archive
67 | public bool NoSeek { get; set; }
68 |
69 | ///
70 | /// Callback on control data block. If is set, will be called for every control data
71 | ///
72 | public Action ControlDataCallback { get; set; }
73 |
74 | ///
75 | /// Callbacks on new file info
76 | ///
77 | public Action FileInfoCallback { get; set; }
78 |
79 | ///
80 | /// Skip when archive contains only one file (can be useful, when file name is analyzed manually)
81 | ///
82 | public bool DoNotFireInfoCallbackOnOneFile { get; set; }
83 |
84 | ///
85 | /// Skip real decoding. This option can be useful for 'list' or 'test' modes, when it required to get some info (e.g. files list) without real decoding
86 | ///
87 | public bool DoNotPerformDecoding { get; set; }
88 |
89 | ///
90 | /// Create default options
91 | ///
92 | public static BlazerDecompressionOptions CreateDefault()
93 | {
94 | return new BlazerDecompressionOptions();
95 | }
96 |
97 | ///
98 | /// Constructor for default options
99 | ///
100 | public BlazerDecompressionOptions()
101 | {
102 | }
103 |
104 | ///
105 | /// Constructor for default options with password
106 | ///
107 | public BlazerDecompressionOptions(string password)
108 | {
109 | Password = password;
110 | }
111 |
112 | ///
113 | /// Constructor for default options with raw password
114 | ///
115 | public BlazerDecompressionOptions(byte[] passwordRaw)
116 | {
117 | PasswordRaw = passwordRaw;
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/Blazer.Net/BlazerFileInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace Force.Blazer
5 | {
6 | ///
7 | /// Information about compressed file
8 | ///
9 | public class BlazerFileInfo
10 | {
11 | ///
12 | /// File name with path, or without it
13 | ///
14 | public string FileName { get; set; }
15 |
16 | ///
17 | /// File creation time in UTC
18 | ///
19 | public DateTime CreationTimeUtc { get; set; }
20 |
21 | ///
22 | /// Last write time in UTC
23 | ///
24 | public DateTime LastWriteTimeUtc { get; set; }
25 |
26 | ///
27 | /// File length
28 | ///
29 | /// This length is just for information. Real compressed data can have another lengh
30 | public long Length { get; set; }
31 |
32 | ///
33 | /// File attributes
34 | ///
35 | public FileAttributes Attributes { get; set; }
36 |
37 | ///
38 | /// Creates file info from with optional custom relative name
39 | ///
40 | /// If no relative name is passed, file name without path is used as file name. Otherwise, this relative name
41 | public static BlazerFileInfo FromFileInfo(FileSystemInfo info, string relativeFileName = null)
42 | {
43 | var bfi = new BlazerFileInfo();
44 | bfi.FileName = relativeFileName ?? info.Name;
45 | bfi.Attributes = info.Attributes;
46 | bfi.CreationTimeUtc = info.CreationTimeUtc;
47 | bfi.LastWriteTimeUtc = info.LastWriteTimeUtc;
48 | var fileInfo = info as FileInfo;
49 | // directory has zero size
50 | bfi.Length = fileInfo != null ? fileInfo.Length : 0;
51 | return bfi;
52 | }
53 |
54 | ///
55 | /// Creates file info from file name
56 | ///
57 | public static BlazerFileInfo FromFileName(string fileName, bool leaveFullName)
58 | {
59 | if (File.Exists(fileName))
60 | return FromFileInfo(new FileInfo(fileName), leaveFullName ? fileName : Path.GetFileName(fileName));
61 | if (Directory.Exists(fileName))
62 | return FromFileInfo(new DirectoryInfo(fileName), leaveFullName ? fileName : Path.GetFileName(fileName));
63 | throw new FileNotFoundException("File not found", fileName);
64 | }
65 |
66 | ///
67 | /// Apply this file info to real file (set attributes and time)
68 | ///
69 | public void ApplyToFile()
70 | {
71 | if (File.Exists(FileName))
72 | {
73 | File.SetAttributes(FileName, Attributes);
74 | File.SetCreationTimeUtc(FileName, CreationTimeUtc);
75 | File.SetLastWriteTimeUtc(FileName, LastWriteTimeUtc);
76 | }
77 | else if (Directory.Exists(FileName))
78 | {
79 | new DirectoryInfo(FileName).Attributes = Attributes;
80 | Directory.SetCreationTimeUtc(FileName, CreationTimeUtc);
81 | Directory.SetLastWriteTimeUtc(FileName, LastWriteTimeUtc);
82 | }
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/Blazer.Net/BlazerFlags.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Force.Blazer
4 | {
5 | ///
6 | /// Header flags for Blazer archive
7 | ///
8 | [Flags]
9 | public enum BlazerFlags : uint
10 | {
11 | ///
12 | /// No flags
13 | ///
14 | None = 0,
15 |
16 | #pragma warning disable 1591
17 | InBlockSize512 = 0,
18 | InBlockSize1K = 1,
19 | InBlockSize2K = 2,
20 | InBlockSize4K = 3,
21 | InBlockSize8K = 4,
22 | InBlockSize16K = 5,
23 | InBlockSize32K = 6,
24 | InBlockSize64K = 7,
25 | InBlockSize128K = 8,
26 | InBlockSize256K = 9,
27 | InBlockSize512K = 10,
28 | InBlockSize1M = 11,
29 | InBlockSize2M = 12,
30 | InBlockSize4M = 13,
31 | InBlockSize8M = 14,
32 | InBlockSize16M = 15,
33 |
34 | IncludeCrc = 256,
35 | IncludeHeader = 512,
36 | IncludeFooter = 1024,
37 | RespectFlush = 2048,
38 |
39 | // in theory, we can encrypt outer and inner two times, so, let's keep both flags
40 | EncryptInner = 4096,
41 | EncryptOuter = 8192,
42 | NotImplementedAddRecoveryInfo = 16384,
43 |
44 | NoFileInfo = 0,
45 | OnlyOneFile = 32768,
46 | MultipleFiles = 65536,
47 | NotImplementedMultipleIndexedFiles = OnlyOneFile | MultipleFiles,
48 | IncludeComment = 131072,
49 |
50 | Default = IncludeCrc | IncludeHeader | IncludeFooter | RespectFlush,
51 | DefaultStream = Default | InBlockSize64K,
52 | DefaultBlock = Default | InBlockSize2M,
53 |
54 | // all known flags for this time
55 | AllKnownFlags = InBlockSize16M | IncludeCrc | IncludeHeader | IncludeFooter | RespectFlush | EncryptInner | EncryptOuter | OnlyOneFile | MultipleFiles | IncludeComment | 0xf0
56 | #pragma warning restore 1591
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Blazer.Net/BlazerFlushMode.cs:
--------------------------------------------------------------------------------
1 | namespace Force.Blazer
2 | {
3 | ///
4 | /// Flush variants for stream
5 | ///
6 | public enum BlazerFlushMode
7 | {
8 | ///
9 | /// Ignore all flush requests (default variant)
10 | ///
11 | IgnoreFlush = 0,
12 |
13 | ///
14 | /// Respect flush requests
15 | ///
16 | RespectFlush = 1,
17 |
18 | ///
19 | /// Auto flush on every write
20 | ///
21 | AutoFlush = 2,
22 |
23 | ///
24 | /// Try to determine, when flush should be performed
25 | ///
26 | SmartFlush = 3
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Blazer.Net/BlazerPatternedHelper.cs:
--------------------------------------------------------------------------------
1 | using Force.Blazer.Algorithms.Patterned;
2 |
3 | namespace Force.Blazer
4 | {
5 | ///
6 | /// Helper for patterned compression
7 | ///
8 | public static class BlazerPatternedHelper
9 | {
10 | ///
11 | /// Creates Stream algorithm Patterned compressor. Good on compression, fast on decompression
12 | ///
13 | /// Do not use pattern data more than 64Kb. It is useless for this type
14 | public static IPatternedCompressor CreateStream()
15 | {
16 | return new StreamPatternedCompressor();
17 | }
18 |
19 | ///
20 | /// Creates Stream algorithm Patterned compressor with high encoding. Slow on compression, fast on decompression
21 | ///
22 | /// Compression is very slow. Use only when needed
23 | public static IPatternedCompressor CreateStreamHigh()
24 | {
25 | return new StreamHighPatternedCompressor();
26 | }
27 |
28 | ///
29 | /// Creates Block algorithm Patterned compressor. Good on compression, Good on decompression
30 | ///
31 | /// Use this algorithm whan pattern is big (greater than 64Kb)
32 | public static IPatternedCompressor CreateBlock()
33 | {
34 | return new BlockPatternedCompressor();
35 | }
36 |
37 | ///
38 | /// Creates Patterned compressor and init it with pattern. Algorithm is selected by pattern size
39 | ///
40 | public static IPatternedCompressor CreateFromPatternAuto(byte[] pattern)
41 | {
42 | return CreateFromPatternAuto(pattern, 0, pattern.Length);
43 | }
44 |
45 | ///
46 | /// Creates Patterned compressor and init it with pattern. Algorithm is selected by pattern size
47 | ///
48 | public static IPatternedCompressor CreateFromPatternAuto(byte[] pattern, int offset, int count)
49 | {
50 | IPatternedCompressor c;
51 | if (count < 65536) c = CreateStream();
52 | else c = CreateBlock();
53 |
54 | c.PreparePattern(pattern, offset, count);
55 |
56 | return c;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Blazer.Net/Encyption/DecryptHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics.CodeAnalysis;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Security.Cryptography;
6 | using System.Text;
7 |
8 | using Force.Blazer.Algorithms;
9 |
10 | namespace Force.Blazer.Encyption
11 | {
12 | internal class NullDecryptHelper
13 | {
14 | public virtual BufferInfo Decrypt(byte[] data, int offset, int length)
15 | {
16 | return new BufferInfo(data, offset, length);
17 | }
18 |
19 | public virtual int AdjustLength(int inLength)
20 | {
21 | return inLength;
22 | }
23 |
24 | public virtual int GetHeaderLength()
25 | {
26 | return 0;
27 | }
28 |
29 | public virtual void Init(byte[] header, int maxBlockSize)
30 | {
31 | }
32 | }
33 |
34 | [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass", Justification = "Reviewed. Suppression is OK here.")]
35 | internal class DecryptHelper : NullDecryptHelper
36 | {
37 | private const int PbkIterations = 20000;
38 |
39 | private Aes _aes;
40 |
41 | private byte[] _passwordRaw;
42 |
43 | private byte[] _buffer;
44 |
45 | public DecryptHelper(string password)
46 | {
47 | _passwordRaw = string.IsNullOrEmpty(password) ? null : Encoding.UTF8.GetBytes(password);
48 | }
49 |
50 | public DecryptHelper(byte[] passwordRaw)
51 | {
52 | _passwordRaw = passwordRaw;
53 | }
54 |
55 | public override int GetHeaderLength()
56 | {
57 | return 24;
58 | }
59 |
60 | private long _counter;
61 |
62 | private bool _useCounter;
63 |
64 | public override void Init(byte[] buffer, int maxBlockSize)
65 | {
66 | if (buffer.Length != GetHeaderLength())
67 | throw new InvalidOperationException("Invalid header");
68 |
69 | _buffer = new byte[AdjustLength(maxBlockSize)];
70 |
71 | var salt = new byte[8];
72 | Buffer.BlockCopy(buffer, 0, salt, 0, 8);
73 | var pass = new Rfc2898DeriveBytes(_passwordRaw, salt, PbkIterations);
74 | _passwordRaw = null;
75 | _aes = Aes.Create();
76 | _aes.Key = pass.GetBytes(32);
77 | // zero. it is ok
78 | _aes.IV = new byte[16];
79 | _aes.Mode = CipherMode.CBC;
80 | _aes.Padding = PaddingMode.Zeros;
81 |
82 | using (var encryptor = _aes.CreateEncryptor())
83 | {
84 | var toEncrypt = new byte[16];
85 | Buffer.BlockCopy(buffer, 8, toEncrypt, 0, 8);
86 | Buffer.BlockCopy(new[] { (byte)'B', (byte)'l', (byte)'a', (byte)'z', (byte)'e', (byte)'r', (byte)'!', (byte)'?' }, 0, toEncrypt, 8, 8);
87 | var encoded = encryptor.TransformFinalBlock(toEncrypt, 0, 16);
88 | if (encoded.Take(8).Where((t, i) => buffer[i + 16] != t).Any())
89 | {
90 | // trying second variant
91 | toEncrypt[15] = (byte)'!';
92 | encoded = encryptor.TransformFinalBlock(toEncrypt, 0, 16);
93 | if (encoded.Take(8).Where((t, i) => buffer[i + 16] != t).Any())
94 | {
95 | throw new InvalidOperationException("Invalid password");
96 | }
97 | else
98 | {
99 | _useCounter = false;
100 | }
101 | }
102 | else
103 | {
104 | _useCounter = true;
105 | _counter = 0;
106 | }
107 | }
108 | }
109 |
110 | public override BufferInfo Decrypt(byte[] data, int offset, int length)
111 | {
112 | using (var decryptor = _aes.CreateDecryptor())
113 | {
114 | var ob = _buffer;
115 | var cnt = decryptor.TransformBlock(data, offset, length - offset, ob, 0);
116 | if (_useCounter)
117 | {
118 | var cv = ((long)ob[0] << 0) | ((long)ob[1] << 8) | ((long)ob[2] << 16) | ((long)ob[3] << 24) | ((long)ob[4] << 32) | ((long)ob[5] << 40) | ((long)ob[6] << 48) | ((long)ob[7] << 56);
119 | if (_counter++ != cv)
120 | throw new InvalidOperationException("Invalid encrypted block. Duplicated or damaged.");
121 | }
122 |
123 | // else dummy data in header (8)
124 | return new BufferInfo(ob, 8, cnt);
125 | }
126 | }
127 |
128 | public override int AdjustLength(int inLength)
129 | {
130 | return ((inLength - 1 + 8) | 15) + 1;
131 | }
132 |
133 | public static Stream ConvertStreamToDecyptionStream(Stream inner, byte[] password)
134 | {
135 | var salt = new byte[8];
136 | // ensure read 8 bytes
137 | var cnt = 8;
138 | while (cnt > 0)
139 | {
140 | var readed = inner.Read(salt, 8 - cnt, cnt);
141 | if (readed == 0 && cnt > 0)
142 | throw new InvalidOperationException("Invalid input stream");
143 | cnt -= readed;
144 | }
145 |
146 | var pass = new Rfc2898DeriveBytes(password, salt, 4096);
147 | var aes = Aes.Create();
148 | aes.Key = pass.GetBytes(32);
149 | // zero. it is ok - we use random password (due salt), so, anyway it will be different
150 | aes.IV = new byte[16];
151 | aes.Mode = CipherMode.CBC;
152 | var cryptoTransform = aes.CreateDecryptor();
153 | #if NETCORE
154 | aes.Padding = PaddingMode.PKCS7; // here we will use such padding
155 | cryptoTransform = new Iso10126TransformEmulator(cryptoTransform);
156 | #else
157 | aes.Padding = PaddingMode.ISO10126; // here we will use such padding
158 | #endif
159 | aes.Padding = PaddingMode.PKCS7; // here we will use such padding
160 | return new CryptoStream(inner, cryptoTransform, CryptoStreamMode.Read);
161 | }
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/Blazer.Net/Encyption/EncryptHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics.CodeAnalysis;
3 | using System.IO;
4 | using System.Security.Cryptography;
5 | using System.Text;
6 |
7 | using Force.Blazer.Algorithms;
8 |
9 | namespace Force.Blazer.Encyption
10 | {
11 | internal class NullEncryptHelper
12 | {
13 | public virtual BufferInfo Encrypt(byte[] data, int offset, int length)
14 | {
15 | return new BufferInfo(data, offset, length);
16 | }
17 |
18 | public virtual byte[] AppendHeader(byte[] header)
19 | {
20 | return header;
21 | }
22 | }
23 |
24 | [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass", Justification = "Reviewed. Suppression is OK here.")]
25 | internal class EncryptHelper : NullEncryptHelper
26 | {
27 | private const int PrefixSize = 8;
28 |
29 | private const int PbkIterations = 20000;
30 |
31 | private readonly Aes _aes;
32 |
33 | private readonly byte[] _headerToWrite;
34 |
35 | private readonly RandomNumberGenerator _rng;
36 |
37 | // private readonly Random _random;
38 |
39 | private readonly byte[] _buffer;
40 |
41 | // private readonly byte[] _randomBlock8;
42 |
43 | private readonly byte[] _randomBlock16;
44 |
45 | private int AdjustLength(int inLength)
46 | {
47 | return ((inLength + PrefixSize - 1) | 15) + 1;
48 | }
49 |
50 | public EncryptHelper(string password, int maxBufferSize)
51 | : this(string.IsNullOrEmpty(password) ? null : Encoding.UTF8.GetBytes(password), maxBufferSize)
52 | {
53 | }
54 |
55 | public EncryptHelper(byte[] password, int maxBufferSize)
56 | {
57 | _buffer = new byte[AdjustLength(maxBufferSize)]; // additional 8 bytes for adding random data to every block and whole block is multiple by 16
58 | // _randomBlock8 = new byte[PrefixSize];
59 | _randomBlock16 = new byte[16];
60 |
61 | // we write to header 8 byte of salt + 8 byte of random data
62 | // after that, we encrypt 8 bytes of random data (pad with static to 16 and write first 8)
63 | // this 8 bytes will be used for checking correctness on decryption
64 | // this is fine for fast checking "is password correct", but does not
65 | // give full information about is it the required password
66 | _rng = RandomNumberGenerator.Create();
67 | // _random = new Random();
68 | var salt = new byte[8];
69 | _rng.GetBytes(salt);
70 | var pass = new Rfc2898DeriveBytes(password, salt, PbkIterations);
71 | _aes = Aes.Create();
72 | _aes.Key = pass.GetBytes(32);
73 | // zero. it is ok - we use data with salted random and do not need to use additional IV here
74 | _aes.IV = new byte[16];
75 | _aes.Mode = CipherMode.CBC;
76 | _aes.Padding = PaddingMode.None; // other padding will add additional block, we manually will add random padding
77 | _headerToWrite = new byte[24];
78 |
79 | var random = new byte[8];
80 | _rng.GetBytes(random);
81 | var toEncrypt = new byte[16];
82 |
83 | Buffer.BlockCopy(random, 0, toEncrypt, 0, 8);
84 |
85 | Buffer.BlockCopy(new[] { (byte)'B', (byte)'l', (byte)'a', (byte)'z', (byte)'e', (byte)'r', (byte)'!', (byte)'?' }, 0, toEncrypt, 8, 8);
86 |
87 | Buffer.BlockCopy(salt, 0, _headerToWrite, 0, 8);
88 | Buffer.BlockCopy(random, 0, _headerToWrite, 8, 8);
89 |
90 | // currently, we use salt for password, so every encryption has own key, as result we do not need to use other values for counter
91 | // nonce is useful when password is static
92 | // _counter = ((long)salt[0] << 0) | ((long)salt[1] << 8) | ((long)salt[2] << 16) | ((long)salt[3] << 24) | ((long)salt[4] << 32) | ((long)salt[5] << 40) | ((long)salt[6] << 48) | ((long)salt[7] << 56);
93 | _counter = 0;
94 |
95 | using (var encryptor = _aes.CreateEncryptor())
96 | {
97 | var encoded = encryptor.TransformFinalBlock(toEncrypt, 0, 16);
98 | Buffer.BlockCopy(encoded, 0, _headerToWrite, 16, 8);
99 | }
100 | }
101 |
102 | private long _counter;
103 |
104 | [SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1107:CodeMustNotContainMultipleStatementsOnOneLine", Justification = "Reviewed. Suppression is OK here.")]
105 | public override BufferInfo Encrypt(byte[] data, int offset, int length)
106 | {
107 | var count = length - offset;
108 | // we can use random iv here, but is simplier to use zero iv and write some dummy bytes
109 | // in block header. on decoding, we just skip it
110 | // this is will elimitate CBC problem with same blocks (if data is repeatable)
111 | using (var encryptor = _aes.CreateEncryptor())
112 | {
113 | // currently, we're not supporting multi-threading, so, we do not need to use Interlocked operations
114 | var c = _counter++;
115 | _buffer[0] = (byte)((c >> 00) & 0xff); _buffer[1] = (byte)((c >> 08) & 0xff); _buffer[2] = (byte)((c >> 16) & 0xff); _buffer[3] = (byte)((c >> 24) & 0xff);
116 | _buffer[4] = (byte)((c >> 32) & 0xff); _buffer[5] = (byte)((c >> 40) & 0xff); _buffer[6] = (byte)((c >> 48) & 0xff); _buffer[7] = (byte)((c >> 56) & 0xff);
117 | // _rng.GetBytes(_randomBlock8);
118 | // copying prefix
119 | // Buffer.BlockCopy(_randomBlock8, 0, _buffer, 0, PrefixSize);
120 |
121 | // copying real data
122 | Buffer.BlockCopy(data, offset, _buffer, PrefixSize, count);
123 |
124 | var addRandomCnt = 16 - ((count + PrefixSize) & 15);
125 | if (addRandomCnt < 16)
126 | {
127 | // here is no security required, but it faster
128 | _rng.GetBytes(_randomBlock16);
129 | Buffer.BlockCopy(_randomBlock16, 0, _buffer, PrefixSize + count, addRandomCnt);
130 | }
131 | else
132 | {
133 | addRandomCnt = 0;
134 | }
135 |
136 | var encLength = PrefixSize + count + addRandomCnt;
137 | encryptor.TransformBlock(_buffer, 0, encLength, _buffer, 0);
138 |
139 | return new BufferInfo(_buffer, 0, encLength);
140 | }
141 | }
142 |
143 | public override byte[] AppendHeader(byte[] header)
144 | {
145 | if (header == null) header = new byte[0];
146 | var res = new byte[header.Length + _headerToWrite.Length];
147 | Buffer.BlockCopy(header, 0, res, 0, header.Length);
148 | Buffer.BlockCopy(_headerToWrite, 0, res, header.Length, _headerToWrite.Length);
149 | return res;
150 | }
151 |
152 | public static Stream ConvertStreamToEncyptionStream(Stream inner, byte[] password)
153 | {
154 | var rng = RandomNumberGenerator.Create();
155 | var salt = new byte[8];
156 | rng.GetBytes(salt);
157 | var pass = new Rfc2898DeriveBytes(password, salt, 4096);
158 | var aes = Aes.Create();
159 | aes.Key = pass.GetBytes(32);
160 | // zero. it is ok - we use random password (due salt), so, anyway it will be different
161 | aes.IV = new byte[16];
162 | aes.Mode = CipherMode.CBC;
163 | aes.Padding = PaddingMode.PKCS7; // here we will use such padding
164 | inner.Write(salt, 0, 8);
165 | return new CryptoStream(inner, aes.CreateEncryptor(), CryptoStreamMode.Write);
166 | }
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/Blazer.Net/Encyption/Iso10126TransformEmulator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Security.Cryptography;
3 |
4 | namespace Force.Blazer.Encyption
5 | {
6 | ///
7 | /// This class emulates ISO10126 AES transform for .NET Core
8 | ///
9 | public class Iso10126TransformEmulator : ICryptoTransform
10 | {
11 | private readonly ICryptoTransform _origTransofrm;
12 |
13 | ///
14 | /// Constructor. Origignal transform should be aes with PKCS7 padding
15 | ///
16 | ///
17 | public Iso10126TransformEmulator(ICryptoTransform origTransofrm)
18 | {
19 | _origTransofrm = origTransofrm;
20 | }
21 |
22 | ///
23 | /// Dispose current transform
24 | ///
25 | public void Dispose()
26 | {
27 | _origTransofrm.Dispose();
28 | }
29 |
30 | int ICryptoTransform.TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
31 | {
32 | return _origTransofrm.TransformBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
33 | }
34 |
35 | byte[] ICryptoTransform.TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
36 | {
37 | var outBuffer = new byte[_origTransofrm.OutputBlockSize + inputCount];
38 | var dummyBuffer = new byte[_origTransofrm.InputBlockSize + inputCount];
39 | Buffer.BlockCopy(inputBuffer, inputOffset, dummyBuffer, 0, inputCount);
40 | _origTransofrm.TransformBlock(dummyBuffer, 0, dummyBuffer.Length, outBuffer, 0);
41 | Array.Resize(ref outBuffer, outBuffer.Length - outBuffer[outBuffer.Length - 1]);
42 | return outBuffer;
43 | }
44 |
45 | int ICryptoTransform.InputBlockSize
46 | {
47 | get
48 | {
49 | return _origTransofrm.InputBlockSize;
50 | }
51 | }
52 |
53 | int ICryptoTransform.OutputBlockSize
54 | {
55 | get
56 | {
57 | return _origTransofrm.OutputBlockSize;
58 | }
59 | }
60 |
61 | bool ICryptoTransform.CanTransformMultipleBlocks
62 | {
63 | get
64 | {
65 | return _origTransofrm.CanTransformMultipleBlocks;
66 | }
67 | }
68 |
69 | bool ICryptoTransform.CanReuseTransform
70 | {
71 | get
72 | {
73 | return _origTransofrm.CanReuseTransform;
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/Blazer.Net/Helpers/BlazerFileHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace Force.Blazer.Helpers
5 | {
6 | ///
7 | /// File Helper class
8 | ///
9 | public static class BlazerFileHelper
10 | {
11 | ///
12 | /// Helper method for convenient read multiple files from blazer archive and writing result to stream
13 | ///
14 | /// Out streams type
15 | /// Input blazer stream
16 | /// Callback on new directory arrival
17 | /// Callback on new file arrival, method should return stream for writing or null to skip it
18 | /// Callback on file end (called only for files, not for directories)
19 | public static void ReadFilesFromStream(
20 | BlazerOutputStream blazerStream,
21 | Action directoryCallback,
22 | Func fileStartCallback,
23 | Action fileEndCallback)
24 | where T : Stream
25 | {
26 | if (directoryCallback == null) directoryCallback = info => { };
27 | if (fileStartCallback == null) fileStartCallback = info => null;
28 | if (fileEndCallback == null) fileEndCallback = (info, arg2) => { };
29 |
30 | // we've missed original event, so, emulate it for client manually
31 | if (!blazerStream.HaveMultipleFiles)
32 | {
33 | if ((blazerStream.FileInfo.Attributes & FileAttributes.Directory) != 0)
34 | directoryCallback(blazerStream.FileInfo);
35 | else
36 | {
37 | var s = fileStartCallback(blazerStream.FileInfo);
38 | if (s != null)
39 | blazerStream.CopyTo(s);
40 | fileEndCallback(blazerStream.FileInfo, s);
41 | }
42 |
43 | return;
44 | }
45 |
46 | T[] outFile = new T[1];
47 | BlazerFileInfo prevFile = null;
48 |
49 | blazerStream.FileInfoCallback = fInfo =>
50 | {
51 | if (prevFile != null)
52 | {
53 | if (fileEndCallback != null) fileEndCallback(prevFile, outFile[0]);
54 | prevFile = null;
55 | }
56 |
57 | prevFile = fInfo;
58 | if ((fInfo.Attributes & FileAttributes.Directory) != 0)
59 | {
60 | directoryCallback(fInfo);
61 | }
62 | else
63 | {
64 | outFile[0] = fileStartCallback(fInfo);
65 | }
66 | };
67 |
68 | var buf = new byte[blazerStream.MaxUncompressedBlockSize];
69 | while (true)
70 | {
71 | var cnt = blazerStream.Read(buf, 0, buf.Length);
72 | if (cnt == 0)
73 | break;
74 | if (outFile[0] != null)
75 | outFile[0].Write(buf, 0, cnt);
76 | }
77 |
78 | if (prevFile != null && ((prevFile.Attributes & FileAttributes.Directory) == 0) && outFile[0] != null)
79 | {
80 | fileEndCallback(prevFile, outFile[0]);
81 | }
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/Blazer.Net/Helpers/DataArrayCompressorHelper.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | using Force.Blazer.Algorithms;
4 |
5 | namespace Force.Blazer.Helpers
6 | {
7 | ///
8 | /// Helper class for creating compressed arrays with data with length prefix
9 | /// Can be useful for resources preparation
10 | /// No algorithm information is stored
11 | ///
12 | public static class DataArrayCompressorHelper
13 | {
14 | ///
15 | /// Compresses source data with specified encoder
16 | ///
17 | /// array of source data
18 | /// selected encoder
19 | /// array of compressed data
20 | public static byte[] CompressDataToArray(byte[] sourceData, IEncoder encoder)
21 | {
22 | return CompressDataToArray(sourceData, 0, sourceData.Length, encoder);
23 | }
24 |
25 | ///
26 | /// Compresses source data with specified encoder
27 | ///
28 | /// array of source data
29 | /// offset of array of source data
30 | /// count data to read from array of source data
31 | /// selected encoder
32 | /// array of compressed data
33 | public static byte[] CompressDataToArray(byte[] sourceData, int offset, int count, IEncoder encoder)
34 | {
35 | encoder.Init(sourceData.Length);
36 | var res = encoder.Encode(sourceData, offset, offset + count);
37 | var targetBuf = res.ExtractToSeparateArray(4);
38 | targetBuf[0] = (byte)count;
39 | targetBuf[1] = (byte)(count >> 8);
40 | targetBuf[2] = (byte)(count >> 16);
41 | targetBuf[3] = (byte)(count >> 24);
42 | return targetBuf;
43 | }
44 |
45 | ///
46 | /// Compresses source data with specified encoder and writes to stream
47 | ///
48 | /// array of source data
49 | /// selected encoder
50 | /// stream to write data
51 | public static void CompressDataToArrayAndWriteToStream(byte[] sourceData, IEncoder encoder, Stream outStream)
52 | {
53 | CompressDataToArrayAndWriteToStream(sourceData, 0, sourceData.Length, encoder, outStream);
54 | }
55 |
56 | ///
57 | /// Compresses source data with specified encoder and writes to stream
58 | ///
59 | /// array of source data
60 | /// offset of array of source data
61 | /// count data to read from array of source data
62 | /// selected encoder
63 | /// stream to write data
64 | public static void CompressDataToArrayAndWriteToStream(byte[] sourceData, int offset, int count, IEncoder encoder, Stream outStream)
65 | {
66 | encoder.Init(sourceData.Length);
67 | var res = encoder.Encode(sourceData, offset, offset + count);
68 | outStream.Write(new[] { (byte)count, (byte)(count >> 8), (byte)(count >> 16), (byte)(count >> 24) }, 0, 4);
69 | outStream.Write(res.Buffer, res.Offset, res.Count);
70 | }
71 |
72 | ///
73 | /// Decompresses data with specified decoder
74 | ///
75 | /// array of compressed data with length prefix
76 | /// selected decoder
77 | /// array of compressed data
78 | public static byte[] DecompressDataArray(byte[] comprData, IDecoder decoder)
79 | {
80 | return DecompressDataArray(comprData, 0, comprData.Length, decoder);
81 | }
82 |
83 | ///
84 | /// Decompresses data with specified decoder
85 | ///
86 | /// array of compressed data with length prefix
87 | /// offset of array of source data
88 | /// count data to read from array of source data
89 | /// selected decoder
90 | /// array of compressed data
91 | public static byte[] DecompressDataArray(byte[] comprData, int offset, int count, IDecoder decoder)
92 | {
93 | var uncomprLength = comprData[offset] | (comprData[offset + 1] << 8) | (comprData[offset + 2] << 16) | (comprData[offset + 3] << 24);
94 | decoder.Init(uncomprLength);
95 | var decoded = decoder.Decode(comprData, offset + 4, offset + count, true);
96 | return decoded.ExtractToSeparateArray();
97 | }
98 |
99 | ///
100 | /// Decompresses data with specified decoder into stream
101 | ///
102 | /// array of compressed data with length prefix
103 | /// selected decoder
104 | /// Stream with uncompressed data
105 | public static Stream DecompressDataArrayToReadableStream(byte[] comprData, IDecoder decoder)
106 | {
107 | return DecompressDataArrayToReadableStream(comprData, 0, comprData.Length, decoder);
108 | }
109 |
110 | ///
111 | /// Decompresses data with specified decoder into stream
112 | ///
113 | /// array of compressed data with length prefix
114 | /// offset of array of source data
115 | /// count data to read from array of source data
116 | /// selected decoder
117 | /// Stream with uncompressed data
118 | public static Stream DecompressDataArrayToReadableStream(byte[] comprData, int offset, int count, IDecoder decoder)
119 | {
120 | var uncomprLength = comprData[offset] | (comprData[offset + 1] << 8) | (comprData[offset + 2] << 16) | (comprData[offset + 3] << 24);
121 | decoder.Init(uncomprLength);
122 | var decoded = decoder.Decode(comprData, offset + 4, offset + count, true);
123 | return new MemoryStream(decoded.Buffer, decoded.Offset, decoded.Count);
124 | }
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/Blazer.Net/Helpers/FileHeaderHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text;
4 |
5 | namespace Force.Blazer.Helpers
6 | {
7 | internal static class FileHeaderHelper
8 | {
9 | private static readonly DateTime MinFileTime = new DateTime(1601, 1, 1);
10 |
11 | public static byte[] GenerateFileHeader(BlazerFileInfo info)
12 | {
13 | if (info.FileName == null) info.FileName = string.Empty;
14 | if (info.CreationTimeUtc < MinFileTime)
15 | info.CreationTimeUtc = MinFileTime;
16 | if (info.LastWriteTimeUtc < MinFileTime)
17 | info.LastWriteTimeUtc = MinFileTime;
18 |
19 | var fileNameBytes = Encoding.UTF8.GetBytes(info.FileName);
20 | var totalHeader = new byte[8 + // length
21 | 8 + // creation time
22 | 8 + // last write time
23 | 2 + // attributes
24 | fileNameBytes.Length];
25 |
26 | Buffer.BlockCopy(BitConverter.GetBytes(info.Length), 0, totalHeader, 0, 8);
27 | Buffer.BlockCopy(BitConverter.GetBytes(info.CreationTimeUtc.ToFileTimeUtc()), 0, totalHeader, 0 + 8, 8);
28 | Buffer.BlockCopy(BitConverter.GetBytes(info.LastWriteTimeUtc.ToFileTimeUtc()), 0, totalHeader, 0 + 8 + 8, 8);
29 | totalHeader[0 + 8 + 8 + 8] = (byte)info.Attributes;
30 | totalHeader[0 + 8 + 8 + 8 + 1] = (byte)((int)info.Attributes >> 8);
31 | Buffer.BlockCopy(fileNameBytes, 0, totalHeader, 0 + 8 + 8 + 8 + 2, fileNameBytes.Length);
32 | return totalHeader;
33 | }
34 |
35 | public static BlazerFileInfo ParseFileHeader(byte[] header, int offset, int count)
36 | {
37 | const int NonNameSize = 8 + 8 + 8 + 2;
38 | if (count < NonNameSize)
39 | throw new InvalidOperationException("Invalid file header");
40 | var fileInfo = new BlazerFileInfo();
41 | fileInfo.Length = BitConverter.ToInt64(header, offset);
42 | fileInfo.CreationTimeUtc = DateTime.FromFileTimeUtc(BitConverter.ToInt64(header, 8 + offset));
43 | fileInfo.LastWriteTimeUtc = DateTime.FromFileTimeUtc(BitConverter.ToInt64(header, 8 + 8 + offset));
44 | fileInfo.Attributes = (FileAttributes)BitConverter.ToInt16(header, 8 + 8 + 8 + offset);
45 | fileInfo.FileName = Encoding.UTF8.GetString(header, NonNameSize + offset, count - NonNameSize);
46 | return fileInfo;
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Blazer.Net/Native/NativeHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Reflection;
4 | using System.Runtime.InteropServices;
5 |
6 | namespace Force.Blazer.Native
7 | {
8 | ///
9 | /// Helper for native implementation ofr Blazer algorithms
10 | ///
11 | public static class NativeHelper
12 | {
13 | // check tests if changed
14 | private const string NativeSuffix = "0.8.3.9";
15 |
16 | #if NETCORE
17 | private const string ResourcePrefix = "Blazer.Net.Resources.Blazer.Native.";
18 | #else
19 | private const string ResourcePrefix = "Force.Blazer.Resources.Blazer.Native.";
20 | #endif
21 |
22 | private static readonly bool _isNativePossible;
23 |
24 | [DllImport("Kernel32.dll")]
25 | private static extern IntPtr LoadLibrary(string path);
26 |
27 | ///
28 | /// Returns is native library is available for usage
29 | ///
30 | public static bool IsNativeAvailable { get; private set; }
31 |
32 | static NativeHelper()
33 | {
34 | _isNativePossible = Init();
35 | IsNativeAvailable = _isNativePossible;
36 | }
37 |
38 | private static bool Init()
39 | {
40 | try
41 | {
42 | InitInternal();
43 | return true;
44 | }
45 | catch (Exception) // will use software realization
46 | {
47 | return false;
48 | }
49 | }
50 |
51 | private static void InitInternal()
52 | {
53 | var architectureSuffix = IntPtr.Size == 8 ? "x64" : "x86";
54 | #if NETCORE
55 | var assembly = typeof(NativeHelper).GetTypeInfo().Assembly;
56 | #else
57 | var assembly = typeof(NativeHelper).Assembly;
58 | #endif
59 | using (var stream =
60 | assembly.GetManifestResourceStream(ResourcePrefix + architectureSuffix + ".dll"))
61 | {
62 | if (stream == null)
63 | throw new InvalidOperationException("Missing resource stream");
64 |
65 | #if NETCORE
66 | var assemblyName = assembly.GetName();
67 | #else
68 | var assemblyName = assembly.GetName(false);
69 | #endif
70 |
71 | var dllPath = Path.Combine(Path.GetTempPath(), assemblyName.Name + "." + NativeSuffix, architectureSuffix);
72 |
73 | var fileName = Path.Combine(dllPath, "Blazer.Native.dll");
74 | if (!File.Exists(fileName) || new FileInfo(fileName).Length == 0)
75 | {
76 | Directory.CreateDirectory(dllPath);
77 | using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite, 16386/*, FileOptions.DeleteOnClose*/))
78 | {
79 | stream.CopyTo(fs);
80 | }
81 | }
82 |
83 | if (LoadLibrary(fileName) == IntPtr.Zero)
84 | throw new InvalidOperationException("Unexpected error in dll loading");
85 | }
86 | }
87 |
88 | ///
89 | /// Sets native implementation is enabled.
90 | ///
91 | /// Native implementation can be turned off manually. If current environment does not support native implementation, software will be used anyway
92 | public static void SetNativeImplementation(bool isEnable)
93 | {
94 | IsNativeAvailable = isEnable && _isNativePossible;
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/Blazer.Net/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // General Information about an assembly is controlled through the following
5 | // set of attributes. Change these attribute values to modify the information
6 | // associated with an assembly.
7 | [assembly: AssemblyTitle("Blazer.Net")]
8 | [assembly: AssemblyDescription("Blazer archiver .NET library")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("Force")]
11 | [assembly: AssemblyProduct("Blazer Archiver")]
12 | [assembly: AssemblyCopyright("Copyright © Force 2016-2018")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // Setting ComVisible to false makes the types in this assembly not visible
17 | // to COM components. If you need to access a type in this assembly from
18 | // COM, set the ComVisible attribute to true on that type.
19 | [assembly: ComVisible(false)]
20 |
21 | // The following GUID is for the ID of the typelib if this project is exposed to COM
22 | [assembly: Guid("05672ef8-45b2-45c1-b0bb-853142618ab4")]
23 |
24 | // Version information for an assembly consists of the following four values:
25 | //
26 | // Major Version
27 | // Minor Version
28 | // Build Number
29 | // Revision
30 | //
31 | // You can specify all the values or you can default the Build and Revision Numbers
32 | // by using the '*' as shown below:
33 | // [assembly: AssemblyVersion("1.0.*")]
34 | [assembly: AssemblyVersion("0.10.0.0")]
35 | [assembly: AssemblyFileVersion("0.10.1.14")]
36 |
--------------------------------------------------------------------------------
/Blazer.Net/pack.cmd:
--------------------------------------------------------------------------------
1 | C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe ..\Blazer.sln /t:Rebuild /p:Configuration=Release /p:SolutionDir=%~dp0..\
2 | dotnet build -c BuildCore -f .NETStandard1.3 project.json
3 | "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\sn.exe" -R bin\Release\Blazer.NET.dll ..\private.snk
4 | "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\sn.exe" -R bin\BuildCore\netstandard1.3\Blazer.NET.dll ..\private.snk
5 |
6 | ..\.nuget\nuget.exe pack Blazer.Net.nuspec
7 | xcopy *.nupkg _releases
8 | del *.nupkg
9 |
--------------------------------------------------------------------------------
/Blazer.Net/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.10.1",
3 | "frameworks": {
4 | "net40": {
5 | },
6 | "netstandard1.3": {
7 | "buildOptions": {
8 | "define": ["NETCORE"]
9 | },
10 | "dependencies": {
11 | "NETStandard.Library": "1.6.1"
12 | }
13 | }
14 | },
15 | "buildOptions": {
16 | "embed": ["Resources/Blazer.Native.x64.dll", "Resources/Blazer.Native.x86.dll"],
17 | "xmlDoc": true,
18 | "keyFile": "../public.snk",
19 | "delaySign": true,
20 | "optimize": true
21 | },
22 | "configurations": {
23 | "BuildCore": {
24 | "optimize": true
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/Blazer.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2012
4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Blazer.Native", "Blazer.Native\Blazer.Native.vcxproj", "{A649C696-0A11-42C2-B66D-7645DCE20AFE}"
5 | EndProject
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blazer.Net", "Blazer.Net\Blazer.Net.csproj", "{026EE2B9-3367-480A-8B46-118F4037C827}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blazer.Benchmark", "Blazer.Benchmark\Blazer.Benchmark.csproj", "{C3B4452D-103F-4191-A3FC-7188D7F9D082}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1492CDF4-0A8F-46AE-828A-C6C98C7D52BC}"
11 | ProjectSection(SolutionItems) = preProject
12 | .nuget\NuGet.Config = .nuget\NuGet.Config
13 | .nuget\NuGet.exe = .nuget\NuGet.exe
14 | .nuget\NuGet.targets = .nuget\NuGet.targets
15 | EndProjectSection
16 | EndProject
17 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blazer.Exe", "Blazer.Exe\Blazer.Exe.csproj", "{D1BE8FC3-7D77-4C08-A0D8-D2399A8D903F}"
18 | EndProject
19 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blazer.Net.Tests", "Blazer.Net.Tests\Blazer.Net.Tests.csproj", "{7C1D5EDB-476B-453F-A7EE-E4E8CB8AB2CF}"
20 | EndProject
21 | Global
22 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
23 | Debug|Any CPU = Debug|Any CPU
24 | Debug|AnyCPU = Debug|AnyCPU
25 | Debug|Mixed Platforms = Debug|Mixed Platforms
26 | Debug|x64 = Debug|x64
27 | Debug|x86 = Debug|x86
28 | Release|Any CPU = Release|Any CPU
29 | Release|AnyCPU = Release|AnyCPU
30 | Release|Mixed Platforms = Release|Mixed Platforms
31 | Release|x64 = Release|x64
32 | Release|x86 = Release|x86
33 | EndGlobalSection
34 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
35 | {A649C696-0A11-42C2-B66D-7645DCE20AFE}.Debug|Any CPU.ActiveCfg = Debug|Win32
36 | {A649C696-0A11-42C2-B66D-7645DCE20AFE}.Debug|AnyCPU.ActiveCfg = Debug|x64
37 | {A649C696-0A11-42C2-B66D-7645DCE20AFE}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
38 | {A649C696-0A11-42C2-B66D-7645DCE20AFE}.Debug|x64.ActiveCfg = Debug|x64
39 | {A649C696-0A11-42C2-B66D-7645DCE20AFE}.Debug|x64.Build.0 = Debug|x64
40 | {A649C696-0A11-42C2-B66D-7645DCE20AFE}.Debug|x86.ActiveCfg = Debug|Win32
41 | {A649C696-0A11-42C2-B66D-7645DCE20AFE}.Release|Any CPU.ActiveCfg = Release|Win32
42 | {A649C696-0A11-42C2-B66D-7645DCE20AFE}.Release|AnyCPU.ActiveCfg = Release|x64
43 | {A649C696-0A11-42C2-B66D-7645DCE20AFE}.Release|AnyCPU.Build.0 = Release|x64
44 | {A649C696-0A11-42C2-B66D-7645DCE20AFE}.Release|Mixed Platforms.ActiveCfg = Release|x64
45 | {A649C696-0A11-42C2-B66D-7645DCE20AFE}.Release|x64.ActiveCfg = Release|x64
46 | {A649C696-0A11-42C2-B66D-7645DCE20AFE}.Release|x64.Build.0 = Release|x64
47 | {A649C696-0A11-42C2-B66D-7645DCE20AFE}.Release|x86.ActiveCfg = Release|Win32
48 | {A649C696-0A11-42C2-B66D-7645DCE20AFE}.Release|x86.Build.0 = Release|Win32
49 | {026EE2B9-3367-480A-8B46-118F4037C827}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
50 | {026EE2B9-3367-480A-8B46-118F4037C827}.Debug|Any CPU.Build.0 = Debug|Any CPU
51 | {026EE2B9-3367-480A-8B46-118F4037C827}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
52 | {026EE2B9-3367-480A-8B46-118F4037C827}.Debug|AnyCPU.Build.0 = Debug|Any CPU
53 | {026EE2B9-3367-480A-8B46-118F4037C827}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
54 | {026EE2B9-3367-480A-8B46-118F4037C827}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
55 | {026EE2B9-3367-480A-8B46-118F4037C827}.Debug|x64.ActiveCfg = Debug|Any CPU
56 | {026EE2B9-3367-480A-8B46-118F4037C827}.Debug|x86.ActiveCfg = Debug|Any CPU
57 | {026EE2B9-3367-480A-8B46-118F4037C827}.Release|Any CPU.ActiveCfg = Release|Any CPU
58 | {026EE2B9-3367-480A-8B46-118F4037C827}.Release|Any CPU.Build.0 = Release|Any CPU
59 | {026EE2B9-3367-480A-8B46-118F4037C827}.Release|AnyCPU.ActiveCfg = Release|Any CPU
60 | {026EE2B9-3367-480A-8B46-118F4037C827}.Release|AnyCPU.Build.0 = Release|Any CPU
61 | {026EE2B9-3367-480A-8B46-118F4037C827}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
62 | {026EE2B9-3367-480A-8B46-118F4037C827}.Release|Mixed Platforms.Build.0 = Release|Any CPU
63 | {026EE2B9-3367-480A-8B46-118F4037C827}.Release|x64.ActiveCfg = Release|Any CPU
64 | {026EE2B9-3367-480A-8B46-118F4037C827}.Release|x86.ActiveCfg = Release|Any CPU
65 | {C3B4452D-103F-4191-A3FC-7188D7F9D082}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
66 | {C3B4452D-103F-4191-A3FC-7188D7F9D082}.Debug|Any CPU.Build.0 = Debug|Any CPU
67 | {C3B4452D-103F-4191-A3FC-7188D7F9D082}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
68 | {C3B4452D-103F-4191-A3FC-7188D7F9D082}.Debug|AnyCPU.Build.0 = Debug|Any CPU
69 | {C3B4452D-103F-4191-A3FC-7188D7F9D082}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
70 | {C3B4452D-103F-4191-A3FC-7188D7F9D082}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
71 | {C3B4452D-103F-4191-A3FC-7188D7F9D082}.Debug|x64.ActiveCfg = Debug|Any CPU
72 | {C3B4452D-103F-4191-A3FC-7188D7F9D082}.Debug|x86.ActiveCfg = Debug|Any CPU
73 | {C3B4452D-103F-4191-A3FC-7188D7F9D082}.Release|Any CPU.ActiveCfg = Release|Any CPU
74 | {C3B4452D-103F-4191-A3FC-7188D7F9D082}.Release|Any CPU.Build.0 = Release|Any CPU
75 | {C3B4452D-103F-4191-A3FC-7188D7F9D082}.Release|AnyCPU.ActiveCfg = Release|Any CPU
76 | {C3B4452D-103F-4191-A3FC-7188D7F9D082}.Release|AnyCPU.Build.0 = Release|Any CPU
77 | {C3B4452D-103F-4191-A3FC-7188D7F9D082}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
78 | {C3B4452D-103F-4191-A3FC-7188D7F9D082}.Release|Mixed Platforms.Build.0 = Release|Any CPU
79 | {C3B4452D-103F-4191-A3FC-7188D7F9D082}.Release|x64.ActiveCfg = Release|Any CPU
80 | {C3B4452D-103F-4191-A3FC-7188D7F9D082}.Release|x86.ActiveCfg = Release|Any CPU
81 | {D1BE8FC3-7D77-4C08-A0D8-D2399A8D903F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
82 | {D1BE8FC3-7D77-4C08-A0D8-D2399A8D903F}.Debug|Any CPU.Build.0 = Debug|Any CPU
83 | {D1BE8FC3-7D77-4C08-A0D8-D2399A8D903F}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
84 | {D1BE8FC3-7D77-4C08-A0D8-D2399A8D903F}.Debug|AnyCPU.Build.0 = Debug|Any CPU
85 | {D1BE8FC3-7D77-4C08-A0D8-D2399A8D903F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
86 | {D1BE8FC3-7D77-4C08-A0D8-D2399A8D903F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
87 | {D1BE8FC3-7D77-4C08-A0D8-D2399A8D903F}.Debug|x64.ActiveCfg = Debug|Any CPU
88 | {D1BE8FC3-7D77-4C08-A0D8-D2399A8D903F}.Debug|x86.ActiveCfg = Debug|Any CPU
89 | {D1BE8FC3-7D77-4C08-A0D8-D2399A8D903F}.Release|Any CPU.ActiveCfg = Release|Any CPU
90 | {D1BE8FC3-7D77-4C08-A0D8-D2399A8D903F}.Release|Any CPU.Build.0 = Release|Any CPU
91 | {D1BE8FC3-7D77-4C08-A0D8-D2399A8D903F}.Release|AnyCPU.ActiveCfg = Release|Any CPU
92 | {D1BE8FC3-7D77-4C08-A0D8-D2399A8D903F}.Release|AnyCPU.Build.0 = Release|Any CPU
93 | {D1BE8FC3-7D77-4C08-A0D8-D2399A8D903F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
94 | {D1BE8FC3-7D77-4C08-A0D8-D2399A8D903F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
95 | {D1BE8FC3-7D77-4C08-A0D8-D2399A8D903F}.Release|x64.ActiveCfg = Release|Any CPU
96 | {D1BE8FC3-7D77-4C08-A0D8-D2399A8D903F}.Release|x86.ActiveCfg = Release|Any CPU
97 | {7C1D5EDB-476B-453F-A7EE-E4E8CB8AB2CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
98 | {7C1D5EDB-476B-453F-A7EE-E4E8CB8AB2CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
99 | {7C1D5EDB-476B-453F-A7EE-E4E8CB8AB2CF}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
100 | {7C1D5EDB-476B-453F-A7EE-E4E8CB8AB2CF}.Debug|AnyCPU.Build.0 = Debug|Any CPU
101 | {7C1D5EDB-476B-453F-A7EE-E4E8CB8AB2CF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
102 | {7C1D5EDB-476B-453F-A7EE-E4E8CB8AB2CF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
103 | {7C1D5EDB-476B-453F-A7EE-E4E8CB8AB2CF}.Debug|x64.ActiveCfg = Debug|Any CPU
104 | {7C1D5EDB-476B-453F-A7EE-E4E8CB8AB2CF}.Debug|x86.ActiveCfg = Debug|Any CPU
105 | {7C1D5EDB-476B-453F-A7EE-E4E8CB8AB2CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
106 | {7C1D5EDB-476B-453F-A7EE-E4E8CB8AB2CF}.Release|Any CPU.Build.0 = Release|Any CPU
107 | {7C1D5EDB-476B-453F-A7EE-E4E8CB8AB2CF}.Release|AnyCPU.ActiveCfg = Release|Any CPU
108 | {7C1D5EDB-476B-453F-A7EE-E4E8CB8AB2CF}.Release|AnyCPU.Build.0 = Release|Any CPU
109 | {7C1D5EDB-476B-453F-A7EE-E4E8CB8AB2CF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
110 | {7C1D5EDB-476B-453F-A7EE-E4E8CB8AB2CF}.Release|Mixed Platforms.Build.0 = Release|Any CPU
111 | {7C1D5EDB-476B-453F-A7EE-E4E8CB8AB2CF}.Release|x64.ActiveCfg = Release|Any CPU
112 | {7C1D5EDB-476B-453F-A7EE-E4E8CB8AB2CF}.Release|x86.ActiveCfg = Release|Any CPU
113 | EndGlobalSection
114 | GlobalSection(SolutionProperties) = preSolution
115 | HideSolutionNode = FALSE
116 | EndGlobalSection
117 | EndGlobal
118 |
--------------------------------------------------------------------------------
/Doc/Images/chart_blocksize1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/force-net/blazer/5520e017a2f5d1b55f5ab978036b138faa765e38/Doc/Images/chart_blocksize1.png
--------------------------------------------------------------------------------
/Doc/Images/chart_comprrate1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/force-net/blazer/5520e017a2f5d1b55f5ab978036b138faa765e38/Doc/Images/chart_comprrate1.png
--------------------------------------------------------------------------------
/Doc/Images/chart_comprrate2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/force-net/blazer/5520e017a2f5d1b55f5ab978036b138faa765e38/Doc/Images/chart_comprrate2.png
--------------------------------------------------------------------------------
/Doc/Images/chart_pattern1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/force-net/blazer/5520e017a2f5d1b55f5ab978036b138faa765e38/Doc/Images/chart_pattern1.png
--------------------------------------------------------------------------------
/Doc/PatternedCompression.md:
--------------------------------------------------------------------------------
1 | # Compression with preliminary pattern
2 |
3 | Imagine, you have lot of similar data. This data can be log messages, SOAP integration XMLs, status logs. And you want to save this data **independently** (if you don't need to do this, you can compress all messages into solid archive. It is best variant for compression, but as result all messages should be extracted if only one needed for view).
4 | These messages can be stored in file system or database, but you want to store each message separately to keep fast access to it.
5 |
6 | You want to compress this messages to save storage, but these messages are small and compress not very good as result.
7 |
8 | But Blazer has a feature to compress these messages with pattern. As pattern you can choose any of these messages or prepare it manually to include more data.
9 |
10 | ```
11 | // creating patterned compressor
12 | var p = BlazerPatternedHelper.CreateStream();
13 | // one-time init of data
14 | p.PreparePattern(patternedData);
15 |
16 | // every time you want to compress data, use similar line
17 | p.EncodeWithPattern(dataToCompress)
18 |
19 | // same code for decompress
20 | p.DecodeWithPattern(dataToDecompress)
21 | ```
22 |
23 | ## What is benefit in numbers?
24 | This is complex question. If all messages are same, every new message will be compressed in 3-6 bytes and benefit will be fantastic.
25 | If all messages are totally different, there are no benefits for this compression type.
26 |
27 | Also, there are some philosophic question for pattern selection. It can be any message (e.g. first) or specially constructed template. This can increase compression rate for some per cents.
28 |
29 | For example, we can choose messages with this format:
30 |
31 | ```
32 |
33 |
34 | 2016-07-04T01:09:51
35 | INFO
36 | System
37 | 25
38 | xsxlnt e fg qamm
39 |
40 | ```
41 |
42 | All fields can be changed, but in some limits (e.g. EventDate is always date, Level is INFO, DEBUG, ERROR or WARN). With these messages results are:
43 |
44 | 
45 |
46 | Or in table view:
47 |
48 | Name | Rate (lower is better)
49 | --------------------|-------------------------
50 | GZip (only deflated block, without headers) | 66.266%
51 | Blazer Independent compression | 82.157%
52 | Blazer Patterned compression | **22.616%**
53 | Blazer Patterned compression with another template | **20.506%**
54 |
55 | So, patterned compression in this case is **3 times better** than GZip! (and really faster).
56 |
57 | _(You can find code which generates messages and produces results in sources)_
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 force
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/blazer-nuget-ico.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/force-net/blazer/5520e017a2f5d1b55f5ab978036b138faa765e38/blazer-nuget-ico.png
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "projects": [ "src", "test" ],
3 | "sdk": {
4 | "version": "1.0.0-preview2-1-003177"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/public.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/force-net/blazer/5520e017a2f5d1b55f5ab978036b138faa765e38/public.snk
--------------------------------------------------------------------------------