├── .gitattributes ├── .gitignore ├── BinaryExtensions.png ├── BinaryExtensions.sln ├── BinaryExtensions ├── BinaryExtensions.csproj ├── BinaryExtensions.csproj.DotSettings ├── BinaryExtensions │ ├── Annotations │ │ └── Annotations.cs │ ├── BinaryExtensions.asmdef │ ├── BinaryReaderExtensions.cs │ ├── Endianness.cs │ ├── EndiannessExtensions.cs │ ├── EndiannessExtensions.g.cs │ ├── EndiannessExtensions.tt │ ├── IntegralTypesExtensions.cs │ ├── LogStream.cs │ ├── LogStreamRegion.cs │ ├── LogStreamScope.cs │ └── StreamExtensions.cs └── Directory.Build.props ├── BinaryExtensionsTests ├── BinaryExtensionsTests.csproj └── UnitTest1.cs ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc 262 | 263 | 264 | ################################################################################ 265 | # BinaryExtensions 266 | ################################################################################ 267 | 268 | -------------------------------------------------------------------------------- /BinaryExtensions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aybe/BinaryExtensions/7675c2711a0c90d10ef88426ec01189bdb17a0e4/BinaryExtensions.png -------------------------------------------------------------------------------- /BinaryExtensions.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30524.135 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BinaryExtensions", "BinaryExtensions\BinaryExtensions.csproj", "{13146840-B64A-4632-9F8A-A6BD238BBCFC}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{69891305-EF56-4E38-876C-F02B869B13D0}" 9 | ProjectSection(SolutionItems) = preProject 10 | README.md = README.md 11 | EndProjectSection 12 | EndProject 13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BinaryExtensionsTests", "BinaryExtensionsTests\BinaryExtensionsTests.csproj", "{100FE0E3-8E57-489C-A4C8-FC5B05CCFEFB}" 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Any CPU = Debug|Any CPU 18 | Release|Any CPU = Release|Any CPU 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {13146840-B64A-4632-9F8A-A6BD238BBCFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {13146840-B64A-4632-9F8A-A6BD238BBCFC}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {13146840-B64A-4632-9F8A-A6BD238BBCFC}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {13146840-B64A-4632-9F8A-A6BD238BBCFC}.Release|Any CPU.Build.0 = Release|Any CPU 25 | {100FE0E3-8E57-489C-A4C8-FC5B05CCFEFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {100FE0E3-8E57-489C-A4C8-FC5B05CCFEFB}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {100FE0E3-8E57-489C-A4C8-FC5B05CCFEFB}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {100FE0E3-8E57-489C-A4C8-FC5B05CCFEFB}.Release|Any CPU.Build.0 = Release|Any CPU 29 | EndGlobalSection 30 | GlobalSection(SolutionProperties) = preSolution 31 | HideSolutionNode = FALSE 32 | EndGlobalSection 33 | GlobalSection(ExtensibilityGlobals) = postSolution 34 | SolutionGuid = {88317CAE-5F4B-4E97-A182-2EF28D208AF2} 35 | EndGlobalSection 36 | EndGlobal 37 | -------------------------------------------------------------------------------- /BinaryExtensions/BinaryExtensions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | true 6 | true 7 | MIT 8 | https://github.com/aybe/BinaryExtensions 9 | BinaryExtensions.png 10 | https://github.com/aybe/BinaryExtensions 11 | See CHANGELOG @ https://github.com/aybe/BinaryExtensions 12 | aybe 13 | Types and extension methods to deal with binary data. 14 | 15 | 16 | git 17 | BinaryReader binary big-endian little-endian endianness LSB MSB 18 | aybe 19 | 1.1.2 20 | true 21 | snupkg 22 | true 23 | 8.0 24 | 1.1.2.0 25 | 26 | 27 | 28 | bin\Debug\netstandard2.0\BinaryExtensions.xml 29 | 30 | 31 | 32 | bin\Release\netstandard2.0\BinaryExtensions.xml 33 | 34 | 35 | 36 | 37 | True 38 | 39 | 40 | 41 | 42 | 43 | 44 | TextTemplatingFileGenerator 45 | EndiannessExtensions.g.cs 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | True 56 | True 57 | EndiannessExtensions.tt 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /BinaryExtensions/BinaryExtensions.csproj.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | CSharp90 3 | True -------------------------------------------------------------------------------- /BinaryExtensions/BinaryExtensions/Annotations/Annotations.cs: -------------------------------------------------------------------------------- 1 | /* MIT License 2 | 3 | Copyright (c) 2016 JetBrains http://www.jetbrains.com 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 | 23 | using System; 24 | using System.Diagnostics; 25 | // ReSharper disable InheritdocConsiderUsage 26 | // ReSharper disable All 27 | #pragma warning disable 28 | #pragma warning disable 1591 29 | // ReSharper disable UnusedMember.Global 30 | // ReSharper disable MemberCanBePrivate.Global 31 | // ReSharper disable UnusedAutoPropertyAccessor.Global 32 | // ReSharper disable IntroduceOptionalParameters.Global 33 | // ReSharper disable MemberCanBeProtected.Global 34 | // ReSharper disable InconsistentNaming 35 | 36 | namespace BinaryExtensions.Annotations 37 | { 38 | /// 39 | /// Indicates that the value of the marked element could be null sometimes, 40 | /// so checking for null is required before its usage. 41 | /// 42 | /// 43 | /// [CanBeNull] object Test() => null; 44 | /// 45 | /// void UseTest() { 46 | /// var p = Test(); 47 | /// var s = p.ToString(); // Warning: Possible 'System.NullReferenceException' 48 | /// } 49 | /// 50 | [AttributeUsage( 51 | AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | 52 | AttributeTargets.Delegate | AttributeTargets.Field | AttributeTargets.Event | 53 | AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.GenericParameter)] 54 | [Conditional("JETBRAINS_ANNOTATIONS")] 55 | internal sealed class CanBeNullAttribute : Attribute { } 56 | 57 | /// 58 | /// Indicates that the value of the marked element can never be null. 59 | /// 60 | /// 61 | /// [NotNull] object Foo() { 62 | /// return null; // Warning: Possible 'null' assignment 63 | /// } 64 | /// 65 | [AttributeUsage( 66 | AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | 67 | AttributeTargets.Delegate | AttributeTargets.Field | AttributeTargets.Event | 68 | AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.GenericParameter)] 69 | [Conditional("JETBRAINS_ANNOTATIONS")] 70 | internal sealed class NotNullAttribute : Attribute { } 71 | 72 | /// 73 | /// Can be applied to symbols of types derived from IEnumerable as well as to symbols of Task 74 | /// and Lazy classes to indicate that the value of a collection item, of the Task.Result property 75 | /// or of the Lazy.Value property can never be null. 76 | /// 77 | /// 78 | /// public void Foo([ItemNotNull]List<string> books) 79 | /// { 80 | /// foreach (var book in books) { 81 | /// if (book != null) // Warning: Expression is always true 82 | /// Console.WriteLine(book.ToUpper()); 83 | /// } 84 | /// } 85 | /// 86 | [AttributeUsage( 87 | AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | 88 | AttributeTargets.Delegate | AttributeTargets.Field)] 89 | [Conditional("JETBRAINS_ANNOTATIONS")] 90 | internal sealed class ItemNotNullAttribute : Attribute { } 91 | 92 | /// 93 | /// Can be applied to symbols of types derived from IEnumerable as well as to symbols of Task 94 | /// and Lazy classes to indicate that the value of a collection item, of the Task.Result property 95 | /// or of the Lazy.Value property can be null. 96 | /// 97 | /// 98 | /// public void Foo([ItemCanBeNull]List<string> books) 99 | /// { 100 | /// foreach (var book in books) 101 | /// { 102 | /// // Warning: Possible 'System.NullReferenceException' 103 | /// Console.WriteLine(book.ToUpper()); 104 | /// } 105 | /// } 106 | /// 107 | [AttributeUsage( 108 | AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | 109 | AttributeTargets.Delegate | AttributeTargets.Field)] 110 | [Conditional("JETBRAINS_ANNOTATIONS")] 111 | internal sealed class ItemCanBeNullAttribute : Attribute { } 112 | 113 | /// 114 | /// Indicates that the marked method builds string by the format pattern and (optional) arguments. 115 | /// The parameter, which contains the format string, should be given in constructor. The format string 116 | /// should be in -like form. 117 | /// 118 | /// 119 | /// [StringFormatMethod("message")] 120 | /// void ShowError(string message, params object[] args) { /* do something */ } 121 | /// 122 | /// void Foo() { 123 | /// ShowError("Failed: {0}"); // Warning: Non-existing argument in format string 124 | /// } 125 | /// 126 | [AttributeUsage( 127 | AttributeTargets.Constructor | AttributeTargets.Method | 128 | AttributeTargets.Property | AttributeTargets.Delegate)] 129 | [Conditional("JETBRAINS_ANNOTATIONS")] 130 | internal sealed class StringFormatMethodAttribute : Attribute 131 | { 132 | /// 133 | /// Specifies which parameter of an annotated method should be treated as the format string 134 | /// 135 | public StringFormatMethodAttribute([NotNull] string formatParameterName) 136 | { 137 | FormatParameterName = formatParameterName; 138 | } 139 | 140 | [NotNull] public string FormatParameterName { get; } 141 | } 142 | 143 | /// 144 | /// Use this annotation to specify a type that contains static or const fields 145 | /// with values for the annotated property/field/parameter. 146 | /// The specified type will be used to improve completion suggestions. 147 | /// 148 | /// 149 | /// namespace TestNamespace 150 | /// { 151 | /// public class Constants 152 | /// { 153 | /// public static int INT_CONST = 1; 154 | /// public const string STRING_CONST = "1"; 155 | /// } 156 | /// 157 | /// public class Class1 158 | /// { 159 | /// [ValueProvider("TestNamespace.Constants")] public int myField; 160 | /// public void Foo([ValueProvider("TestNamespace.Constants")] string str) { } 161 | /// 162 | /// public void Test() 163 | /// { 164 | /// Foo(/*try completion here*/);// 165 | /// myField = /*try completion here*/ 166 | /// } 167 | /// } 168 | /// } 169 | /// 170 | [AttributeUsage( 171 | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Field, 172 | AllowMultiple = true)] 173 | [Conditional("JETBRAINS_ANNOTATIONS")] 174 | internal sealed class ValueProviderAttribute : Attribute 175 | { 176 | public ValueProviderAttribute([NotNull] string name) 177 | { 178 | Name = name; 179 | } 180 | 181 | [NotNull] public string Name { get; } 182 | } 183 | 184 | /// 185 | /// Indicates that the integral value falls into the specified interval. 186 | /// It's allowed to specify multiple non-intersecting intervals. 187 | /// Values of interval boundaries are inclusive. 188 | /// 189 | /// 190 | /// void Foo([ValueRange(0, 100)] int value) { 191 | /// if (value == -1) { // Warning: Expression is always 'false' 192 | /// ... 193 | /// } 194 | /// } 195 | /// 196 | [AttributeUsage( 197 | AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property | 198 | AttributeTargets.Method | AttributeTargets.Delegate, 199 | AllowMultiple = true)] 200 | [Conditional("JETBRAINS_ANNOTATIONS")] 201 | internal sealed class ValueRangeAttribute : Attribute 202 | { 203 | public object From { get; } 204 | public object To { get; } 205 | 206 | public ValueRangeAttribute(long from, long to) 207 | { 208 | From = from; 209 | To = to; 210 | } 211 | 212 | public ValueRangeAttribute(ulong from, ulong to) 213 | { 214 | From = from; 215 | To = to; 216 | } 217 | 218 | public ValueRangeAttribute(long value) 219 | { 220 | From = To = value; 221 | } 222 | 223 | public ValueRangeAttribute(ulong value) 224 | { 225 | From = To = value; 226 | } 227 | } 228 | 229 | /// 230 | /// Indicates that the integral value never falls below zero. 231 | /// 232 | /// 233 | /// void Foo([NonNegativeValue] int value) { 234 | /// if (value == -1) { // Warning: Expression is always 'false' 235 | /// ... 236 | /// } 237 | /// } 238 | /// 239 | [AttributeUsage( 240 | AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property | 241 | AttributeTargets.Method | AttributeTargets.Delegate)] 242 | [Conditional("JETBRAINS_ANNOTATIONS")] 243 | internal sealed class NonNegativeValueAttribute : Attribute { } 244 | 245 | /// 246 | /// Indicates that the function argument should be a string literal and match one 247 | /// of the parameters of the caller function. For example, ReSharper annotates 248 | /// the parameter of . 249 | /// 250 | /// 251 | /// void Foo(string param) { 252 | /// if (param == null) 253 | /// throw new ArgumentNullException("par"); // Warning: Cannot resolve symbol 254 | /// } 255 | /// 256 | [AttributeUsage(AttributeTargets.Parameter)] 257 | [Conditional("JETBRAINS_ANNOTATIONS")] 258 | internal sealed class InvokerParameterNameAttribute : Attribute { } 259 | 260 | /// 261 | /// Indicates that the method is contained in a type that implements 262 | /// System.ComponentModel.INotifyPropertyChanged interface and this method 263 | /// is used to notify that some property value changed. 264 | /// 265 | /// 266 | /// The method should be non-static and conform to one of the supported signatures: 267 | /// 268 | /// NotifyChanged(string) 269 | /// NotifyChanged(params string[]) 270 | /// NotifyChanged{T}(Expression{Func{T}}) 271 | /// NotifyChanged{T,U}(Expression{Func{T,U}}) 272 | /// SetProperty{T}(ref T, T, string) 273 | /// 274 | /// 275 | /// 276 | /// public class Foo : INotifyPropertyChanged { 277 | /// public event PropertyChangedEventHandler PropertyChanged; 278 | /// 279 | /// [NotifyPropertyChangedInvocator] 280 | /// protected virtual void NotifyChanged(string propertyName) { ... } 281 | /// 282 | /// string _name; 283 | /// 284 | /// public string Name { 285 | /// get { return _name; } 286 | /// set { _name = value; NotifyChanged("LastName"); /* Warning */ } 287 | /// } 288 | /// } 289 | /// 290 | /// Examples of generated notifications: 291 | /// 292 | /// NotifyChanged("Property") 293 | /// NotifyChanged(() => Property) 294 | /// NotifyChanged((VM x) => x.Property) 295 | /// SetProperty(ref myField, value, "Property") 296 | /// 297 | /// 298 | [AttributeUsage(AttributeTargets.Method)] 299 | [Conditional("JETBRAINS_ANNOTATIONS")] 300 | internal sealed class NotifyPropertyChangedInvocatorAttribute : Attribute 301 | { 302 | public NotifyPropertyChangedInvocatorAttribute() { } 303 | public NotifyPropertyChangedInvocatorAttribute([NotNull] string parameterName) 304 | { 305 | ParameterName = parameterName; 306 | } 307 | 308 | [CanBeNull] public string ParameterName { get; } 309 | } 310 | 311 | /// 312 | /// Describes dependency between method input and output. 313 | /// 314 | /// 315 | ///

Function Definition Table syntax:

316 | /// 317 | /// FDT ::= FDTRow [;FDTRow]* 318 | /// FDTRow ::= Input => Output | Output <= Input 319 | /// Input ::= ParameterName: Value [, Input]* 320 | /// Output ::= [ParameterName: Value]* {halt|stop|void|nothing|Value} 321 | /// Value ::= true | false | null | notnull | canbenull 322 | /// 323 | /// If the method has a single input parameter, its name could be omitted.
324 | /// Using halt (or void/nothing, which is the same) for the method output 325 | /// means that the method doesn't return normally (throws or terminates the process).
326 | /// Value canbenull is only applicable for output parameters.
327 | /// You can use multiple [ContractAnnotation] for each FDT row, or use single attribute 328 | /// with rows separated by semicolon. There is no notion of order rows, all rows are checked 329 | /// for applicability and applied per each program state tracked by the analysis engine.
330 | ///
331 | /// 332 | /// 333 | /// [ContractAnnotation("=> halt")] 334 | /// public void TerminationMethod() 335 | /// 336 | /// 337 | /// [ContractAnnotation("null <= param:null")] // reverse condition syntax 338 | /// public string GetName(string surname) 339 | /// 340 | /// 341 | /// [ContractAnnotation("s:null => true")] 342 | /// public bool IsNullOrEmpty(string s) // string.IsNullOrEmpty() 343 | /// 344 | /// 345 | /// // A method that returns null if the parameter is null, 346 | /// // and not null if the parameter is not null 347 | /// [ContractAnnotation("null => null; notnull => notnull")] 348 | /// public object Transform(object data) 349 | /// 350 | /// 351 | /// [ContractAnnotation("=> true, result: notnull; => false, result: null")] 352 | /// public bool TryParse(string s, out Person result) 353 | /// 354 | /// 355 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] 356 | [Conditional("JETBRAINS_ANNOTATIONS")] 357 | internal sealed class ContractAnnotationAttribute : Attribute 358 | { 359 | public ContractAnnotationAttribute([NotNull] string contract) 360 | : this(contract, false) { } 361 | 362 | public ContractAnnotationAttribute([NotNull] string contract, bool forceFullStates) 363 | { 364 | Contract = contract; 365 | ForceFullStates = forceFullStates; 366 | } 367 | 368 | [NotNull] public string Contract { get; } 369 | 370 | public bool ForceFullStates { get; } 371 | } 372 | 373 | /// 374 | /// Indicates whether the marked element should be localized. 375 | /// 376 | /// 377 | /// [LocalizationRequiredAttribute(true)] 378 | /// class Foo { 379 | /// string str = "my string"; // Warning: Localizable string 380 | /// } 381 | /// 382 | [AttributeUsage(AttributeTargets.All)] 383 | [Conditional("JETBRAINS_ANNOTATIONS")] 384 | internal sealed class LocalizationRequiredAttribute : Attribute 385 | { 386 | public LocalizationRequiredAttribute() : this(true) { } 387 | 388 | public LocalizationRequiredAttribute(bool required) 389 | { 390 | Required = required; 391 | } 392 | 393 | public bool Required { get; } 394 | } 395 | 396 | /// 397 | /// Indicates that the value of the marked type (or its derivatives) 398 | /// cannot be compared using '==' or '!=' operators and Equals() 399 | /// should be used instead. However, using '==' or '!=' for comparison 400 | /// with null is always permitted. 401 | /// 402 | /// 403 | /// [CannotApplyEqualityOperator] 404 | /// class NoEquality { } 405 | /// 406 | /// class UsesNoEquality { 407 | /// void Test() { 408 | /// var ca1 = new NoEquality(); 409 | /// var ca2 = new NoEquality(); 410 | /// if (ca1 != null) { // OK 411 | /// bool condition = ca1 == ca2; // Warning 412 | /// } 413 | /// } 414 | /// } 415 | /// 416 | [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Struct)] 417 | [Conditional("JETBRAINS_ANNOTATIONS")] 418 | internal sealed class CannotApplyEqualityOperatorAttribute : Attribute { } 419 | 420 | /// 421 | /// When applied to a target attribute, specifies a requirement for any type marked 422 | /// with the target attribute to implement or inherit specific type or types. 423 | /// 424 | /// 425 | /// [BaseTypeRequired(typeof(IComponent)] // Specify requirement 426 | /// class ComponentAttribute : Attribute { } 427 | /// 428 | /// [Component] // ComponentAttribute requires implementing IComponent interface 429 | /// class MyComponent : IComponent { } 430 | /// 431 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] 432 | [BaseTypeRequired(typeof(Attribute))] 433 | [Conditional("JETBRAINS_ANNOTATIONS")] 434 | internal sealed class BaseTypeRequiredAttribute : Attribute 435 | { 436 | public BaseTypeRequiredAttribute([NotNull] Type baseType) 437 | { 438 | BaseType = baseType; 439 | } 440 | 441 | [NotNull] public Type BaseType { get; } 442 | } 443 | 444 | /// 445 | /// Indicates that the marked symbol is used implicitly (e.g. via reflection, in external library), 446 | /// so this symbol will not be reported as unused (as well as by other usage inspections). 447 | /// 448 | [AttributeUsage(AttributeTargets.All)] 449 | [Conditional("JETBRAINS_ANNOTATIONS")] 450 | internal sealed class UsedImplicitlyAttribute : Attribute 451 | { 452 | public UsedImplicitlyAttribute() 453 | : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } 454 | 455 | public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags) 456 | : this(useKindFlags, ImplicitUseTargetFlags.Default) { } 457 | 458 | public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags) 459 | : this(ImplicitUseKindFlags.Default, targetFlags) { } 460 | 461 | public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) 462 | { 463 | UseKindFlags = useKindFlags; 464 | TargetFlags = targetFlags; 465 | } 466 | 467 | public ImplicitUseKindFlags UseKindFlags { get; } 468 | 469 | public ImplicitUseTargetFlags TargetFlags { get; } 470 | } 471 | 472 | /// 473 | /// Can be applied to attributes, type parameters, and parameters of a type assignable from . 474 | /// When applied to an attribute, the decorated attribute behaves the same as . 475 | /// When applied to a type parameter or to a parameter of type , indicates that the corresponding type 476 | /// is used implicitly. 477 | /// 478 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.GenericParameter | AttributeTargets.Parameter)] 479 | [Conditional("JETBRAINS_ANNOTATIONS")] 480 | internal sealed class MeansImplicitUseAttribute : Attribute 481 | { 482 | public MeansImplicitUseAttribute() 483 | : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } 484 | 485 | public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags) 486 | : this(useKindFlags, ImplicitUseTargetFlags.Default) { } 487 | 488 | public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags) 489 | : this(ImplicitUseKindFlags.Default, targetFlags) { } 490 | 491 | public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) 492 | { 493 | UseKindFlags = useKindFlags; 494 | TargetFlags = targetFlags; 495 | } 496 | 497 | [UsedImplicitly] public ImplicitUseKindFlags UseKindFlags { get; } 498 | 499 | [UsedImplicitly] public ImplicitUseTargetFlags TargetFlags { get; } 500 | } 501 | 502 | /// 503 | /// Specify the details of implicitly used symbol when it is marked 504 | /// with or . 505 | /// 506 | [Flags] 507 | internal enum ImplicitUseKindFlags 508 | { 509 | Default = Access | Assign | InstantiatedWithFixedConstructorSignature, 510 | /// Only entity marked with attribute considered used. 511 | Access = 1, 512 | /// Indicates implicit assignment to a member. 513 | Assign = 2, 514 | /// 515 | /// Indicates implicit instantiation of a type with fixed constructor signature. 516 | /// That means any unused constructor parameters won't be reported as such. 517 | /// 518 | InstantiatedWithFixedConstructorSignature = 4, 519 | /// Indicates implicit instantiation of a type. 520 | InstantiatedNoFixedConstructorSignature = 8, 521 | } 522 | 523 | /// 524 | /// Specify what is considered to be used implicitly when marked 525 | /// with or . 526 | /// 527 | [Flags] 528 | internal enum ImplicitUseTargetFlags 529 | { 530 | Default = Itself, 531 | Itself = 1, 532 | /// Members of entity marked with attribute are considered used. 533 | Members = 2, 534 | /// Inherited entities are considered used. 535 | WithInheritors = 4, 536 | /// Entity marked with attribute and all its members considered used. 537 | WithMembers = Itself | Members 538 | } 539 | 540 | /// 541 | /// This attribute is intended to mark publicly available API 542 | /// which should not be removed and so is treated as used. 543 | /// 544 | [MeansImplicitUse(ImplicitUseTargetFlags.WithMembers)] 545 | [AttributeUsage(AttributeTargets.All, Inherited = false)] 546 | [Conditional("JETBRAINS_ANNOTATIONS")] 547 | internal sealed class PublicAPIAttribute : Attribute 548 | { 549 | public PublicAPIAttribute() { } 550 | 551 | public PublicAPIAttribute([NotNull] string comment) 552 | { 553 | Comment = comment; 554 | } 555 | 556 | [CanBeNull] public string Comment { get; } 557 | } 558 | 559 | /// 560 | /// Tells code analysis engine if the parameter is completely handled when the invoked method is on stack. 561 | /// If the parameter is a delegate, indicates that delegate is executed while the method is executed. 562 | /// If the parameter is an enumerable, indicates that it is enumerated while the method is executed. 563 | /// 564 | [AttributeUsage(AttributeTargets.Parameter)] 565 | [Conditional("JETBRAINS_ANNOTATIONS")] 566 | internal sealed class InstantHandleAttribute : Attribute { } 567 | 568 | /// 569 | /// Indicates that a method does not make any observable state changes. 570 | /// The same as System.Diagnostics.Contracts.PureAttribute. 571 | /// 572 | /// 573 | /// [Pure] int Multiply(int x, int y) => x * y; 574 | /// 575 | /// void M() { 576 | /// Multiply(123, 42); // Warning: Return value of pure method is not used 577 | /// } 578 | /// 579 | [AttributeUsage(AttributeTargets.Method)] 580 | [Conditional("JETBRAINS_ANNOTATIONS")] 581 | internal sealed class PureAttribute : Attribute { } 582 | 583 | /// 584 | /// Indicates that the return value of the method invocation must be used. 585 | /// 586 | /// 587 | /// Methods decorated with this attribute (in contrast to pure methods) might change state, 588 | /// but make no sense without using their return value.
589 | /// Similarly to , this attribute 590 | /// will help detecting usages of the method when the return value in not used. 591 | /// Additionally, you can optionally specify a custom message, which will be used when showing warnings, e.g. 592 | /// [MustUseReturnValue("Use the return value to...")]. 593 | ///
594 | [AttributeUsage(AttributeTargets.Method)] 595 | [Conditional("JETBRAINS_ANNOTATIONS")] 596 | internal sealed class MustUseReturnValueAttribute : Attribute 597 | { 598 | public MustUseReturnValueAttribute() { } 599 | 600 | public MustUseReturnValueAttribute([NotNull] string justification) 601 | { 602 | Justification = justification; 603 | } 604 | 605 | [CanBeNull] public string Justification { get; } 606 | } 607 | 608 | /// 609 | /// Indicates the type member or parameter of some type, that should be used instead of all other ways 610 | /// to get the value of that type. This annotation is useful when you have some "context" value evaluated 611 | /// and stored somewhere, meaning that all other ways to get this value must be consolidated with existing one. 612 | /// 613 | /// 614 | /// class Foo { 615 | /// [ProvidesContext] IBarService _barService = ...; 616 | /// 617 | /// void ProcessNode(INode node) { 618 | /// DoSomething(node, node.GetGlobalServices().Bar); 619 | /// // ^ Warning: use value of '_barService' field 620 | /// } 621 | /// } 622 | /// 623 | [AttributeUsage( 624 | AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.Method | 625 | AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.GenericParameter)] 626 | [Conditional("JETBRAINS_ANNOTATIONS")] 627 | internal sealed class ProvidesContextAttribute : Attribute { } 628 | 629 | /// 630 | /// Indicates that a parameter is a path to a file or a folder within a web project. 631 | /// Path can be relative or absolute, starting from web root (~). 632 | /// 633 | [AttributeUsage(AttributeTargets.Parameter)] 634 | [Conditional("JETBRAINS_ANNOTATIONS")] 635 | internal sealed class PathReferenceAttribute : Attribute 636 | { 637 | public PathReferenceAttribute() { } 638 | 639 | public PathReferenceAttribute([NotNull, PathReference] string basePath) 640 | { 641 | BasePath = basePath; 642 | } 643 | 644 | [CanBeNull] public string BasePath { get; } 645 | } 646 | 647 | /// 648 | /// An extension method marked with this attribute is processed by code completion 649 | /// as a 'Source Template'. When the extension method is completed over some expression, its source code 650 | /// is automatically expanded like a template at call site. 651 | /// 652 | /// 653 | /// Template method body can contain valid source code and/or special comments starting with '$'. 654 | /// Text inside these comments is added as source code when the template is applied. Template parameters 655 | /// can be used either as additional method parameters or as identifiers wrapped in two '$' signs. 656 | /// Use the attribute to specify macros for parameters. 657 | /// 658 | /// 659 | /// In this example, the 'forEach' method is a source template available over all values 660 | /// of enumerable types, producing ordinary C# 'foreach' statement and placing caret inside block: 661 | /// 662 | /// [SourceTemplate] 663 | /// public static void forEach<T>(this IEnumerable<T> xs) { 664 | /// foreach (var x in xs) { 665 | /// //$ $END$ 666 | /// } 667 | /// } 668 | /// 669 | /// 670 | [AttributeUsage(AttributeTargets.Method)] 671 | [Conditional("JETBRAINS_ANNOTATIONS")] 672 | internal sealed class SourceTemplateAttribute : Attribute { } 673 | 674 | /// 675 | /// Allows specifying a macro for a parameter of a source template. 676 | /// 677 | /// 678 | /// You can apply the attribute on the whole method or on any of its additional parameters. The macro expression 679 | /// is defined in the property. When applied on a method, the target 680 | /// template parameter is defined in the property. To apply the macro silently 681 | /// for the parameter, set the property value = -1. 682 | /// 683 | /// 684 | /// Applying the attribute on a source template method: 685 | /// 686 | /// [SourceTemplate, Macro(Target = "item", Expression = "suggestVariableName()")] 687 | /// public static void forEach<T>(this IEnumerable<T> collection) { 688 | /// foreach (var item in collection) { 689 | /// //$ $END$ 690 | /// } 691 | /// } 692 | /// 693 | /// Applying the attribute on a template method parameter: 694 | /// 695 | /// [SourceTemplate] 696 | /// public static void something(this Entity x, [Macro(Expression = "guid()", Editable = -1)] string newguid) { 697 | /// /*$ var $x$Id = "$newguid$" + x.ToString(); 698 | /// x.DoSomething($x$Id); */ 699 | /// } 700 | /// 701 | /// 702 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method, AllowMultiple = true)] 703 | [Conditional("JETBRAINS_ANNOTATIONS")] 704 | internal sealed class MacroAttribute : Attribute 705 | { 706 | /// 707 | /// Allows specifying a macro that will be executed for a source template 708 | /// parameter when the template is expanded. 709 | /// 710 | [CanBeNull] public string Expression { get; set; } 711 | 712 | /// 713 | /// Allows specifying which occurrence of the target parameter becomes editable when the template is deployed. 714 | /// 715 | /// 716 | /// If the target parameter is used several times in the template, only one occurrence becomes editable; 717 | /// other occurrences are changed synchronously. To specify the zero-based index of the editable occurrence, 718 | /// use values >= 0. To make the parameter non-editable when the template is expanded, use -1. 719 | /// 720 | public int Editable { get; set; } 721 | 722 | /// 723 | /// Identifies the target parameter of a source template if the 724 | /// is applied on a template method. 725 | /// 726 | [CanBeNull] public string Target { get; set; } 727 | } 728 | 729 | [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] 730 | [Conditional("JETBRAINS_ANNOTATIONS")] 731 | internal sealed class AspMvcAreaMasterLocationFormatAttribute : Attribute 732 | { 733 | public AspMvcAreaMasterLocationFormatAttribute([NotNull] string format) 734 | { 735 | Format = format; 736 | } 737 | 738 | [NotNull] public string Format { get; } 739 | } 740 | 741 | [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] 742 | [Conditional("JETBRAINS_ANNOTATIONS")] 743 | internal sealed class AspMvcAreaPartialViewLocationFormatAttribute : Attribute 744 | { 745 | public AspMvcAreaPartialViewLocationFormatAttribute([NotNull] string format) 746 | { 747 | Format = format; 748 | } 749 | 750 | [NotNull] public string Format { get; } 751 | } 752 | 753 | [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] 754 | [Conditional("JETBRAINS_ANNOTATIONS")] 755 | internal sealed class AspMvcAreaViewLocationFormatAttribute : Attribute 756 | { 757 | public AspMvcAreaViewLocationFormatAttribute([NotNull] string format) 758 | { 759 | Format = format; 760 | } 761 | 762 | [NotNull] public string Format { get; } 763 | } 764 | 765 | [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] 766 | [Conditional("JETBRAINS_ANNOTATIONS")] 767 | internal sealed class AspMvcMasterLocationFormatAttribute : Attribute 768 | { 769 | public AspMvcMasterLocationFormatAttribute([NotNull] string format) 770 | { 771 | Format = format; 772 | } 773 | 774 | [NotNull] public string Format { get; } 775 | } 776 | 777 | [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] 778 | [Conditional("JETBRAINS_ANNOTATIONS")] 779 | internal sealed class AspMvcPartialViewLocationFormatAttribute : Attribute 780 | { 781 | public AspMvcPartialViewLocationFormatAttribute([NotNull] string format) 782 | { 783 | Format = format; 784 | } 785 | 786 | [NotNull] public string Format { get; } 787 | } 788 | 789 | [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] 790 | [Conditional("JETBRAINS_ANNOTATIONS")] 791 | internal sealed class AspMvcViewLocationFormatAttribute : Attribute 792 | { 793 | public AspMvcViewLocationFormatAttribute([NotNull] string format) 794 | { 795 | Format = format; 796 | } 797 | 798 | [NotNull] public string Format { get; } 799 | } 800 | 801 | /// 802 | /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter 803 | /// is an MVC action. If applied to a method, the MVC action name is calculated 804 | /// implicitly from the context. Use this attribute for custom wrappers similar to 805 | /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String). 806 | /// 807 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] 808 | [Conditional("JETBRAINS_ANNOTATIONS")] 809 | internal sealed class AspMvcActionAttribute : Attribute 810 | { 811 | public AspMvcActionAttribute() { } 812 | 813 | public AspMvcActionAttribute([NotNull] string anonymousProperty) 814 | { 815 | AnonymousProperty = anonymousProperty; 816 | } 817 | 818 | [CanBeNull] public string AnonymousProperty { get; } 819 | } 820 | 821 | /// 822 | /// ASP.NET MVC attribute. Indicates that the marked parameter is an MVC area. 823 | /// Use this attribute for custom wrappers similar to 824 | /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String). 825 | /// 826 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] 827 | [Conditional("JETBRAINS_ANNOTATIONS")] 828 | internal sealed class AspMvcAreaAttribute : Attribute 829 | { 830 | public AspMvcAreaAttribute() { } 831 | 832 | public AspMvcAreaAttribute([NotNull] string anonymousProperty) 833 | { 834 | AnonymousProperty = anonymousProperty; 835 | } 836 | 837 | [CanBeNull] public string AnonymousProperty { get; } 838 | } 839 | 840 | /// 841 | /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter is 842 | /// an MVC controller. If applied to a method, the MVC controller name is calculated 843 | /// implicitly from the context. Use this attribute for custom wrappers similar to 844 | /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String, String). 845 | /// 846 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] 847 | [Conditional("JETBRAINS_ANNOTATIONS")] 848 | internal sealed class AspMvcControllerAttribute : Attribute 849 | { 850 | public AspMvcControllerAttribute() { } 851 | 852 | public AspMvcControllerAttribute([NotNull] string anonymousProperty) 853 | { 854 | AnonymousProperty = anonymousProperty; 855 | } 856 | 857 | [CanBeNull] public string AnonymousProperty { get; } 858 | } 859 | 860 | /// 861 | /// ASP.NET MVC attribute. Indicates that the marked parameter is an MVC Master. Use this attribute 862 | /// for custom wrappers similar to System.Web.Mvc.Controller.View(String, String). 863 | /// 864 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] 865 | [Conditional("JETBRAINS_ANNOTATIONS")] 866 | internal sealed class AspMvcMasterAttribute : Attribute { } 867 | 868 | /// 869 | /// ASP.NET MVC attribute. Indicates that the marked parameter is an MVC model type. Use this attribute 870 | /// for custom wrappers similar to System.Web.Mvc.Controller.View(String, Object). 871 | /// 872 | [AttributeUsage(AttributeTargets.Parameter)] 873 | [Conditional("JETBRAINS_ANNOTATIONS")] 874 | internal sealed class AspMvcModelTypeAttribute : Attribute { } 875 | 876 | /// 877 | /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter is an MVC 878 | /// partial view. If applied to a method, the MVC partial view name is calculated implicitly 879 | /// from the context. Use this attribute for custom wrappers similar to 880 | /// System.Web.Mvc.Html.RenderPartialExtensions.RenderPartial(HtmlHelper, String). 881 | /// 882 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] 883 | [Conditional("JETBRAINS_ANNOTATIONS")] 884 | internal sealed class AspMvcPartialViewAttribute : Attribute { } 885 | 886 | /// 887 | /// ASP.NET MVC attribute. Allows disabling inspections for MVC views within a class or a method. 888 | /// 889 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] 890 | [Conditional("JETBRAINS_ANNOTATIONS")] 891 | internal sealed class AspMvcSuppressViewErrorAttribute : Attribute { } 892 | 893 | /// 894 | /// ASP.NET MVC attribute. Indicates that a parameter is an MVC display template. 895 | /// Use this attribute for custom wrappers similar to 896 | /// System.Web.Mvc.Html.DisplayExtensions.DisplayForModel(HtmlHelper, String). 897 | /// 898 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] 899 | [Conditional("JETBRAINS_ANNOTATIONS")] 900 | internal sealed class AspMvcDisplayTemplateAttribute : Attribute { } 901 | 902 | /// 903 | /// ASP.NET MVC attribute. Indicates that the marked parameter is an MVC editor template. 904 | /// Use this attribute for custom wrappers similar to 905 | /// System.Web.Mvc.Html.EditorExtensions.EditorForModel(HtmlHelper, String). 906 | /// 907 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] 908 | [Conditional("JETBRAINS_ANNOTATIONS")] 909 | internal sealed class AspMvcEditorTemplateAttribute : Attribute { } 910 | 911 | /// 912 | /// ASP.NET MVC attribute. Indicates that the marked parameter is an MVC template. 913 | /// Use this attribute for custom wrappers similar to 914 | /// System.ComponentModel.DataAnnotations.UIHintAttribute(System.String). 915 | /// 916 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] 917 | [Conditional("JETBRAINS_ANNOTATIONS")] 918 | internal sealed class AspMvcTemplateAttribute : Attribute { } 919 | 920 | /// 921 | /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter 922 | /// is an MVC view component. If applied to a method, the MVC view name is calculated implicitly 923 | /// from the context. Use this attribute for custom wrappers similar to 924 | /// System.Web.Mvc.Controller.View(Object). 925 | /// 926 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] 927 | [Conditional("JETBRAINS_ANNOTATIONS")] 928 | internal sealed class AspMvcViewAttribute : Attribute { } 929 | 930 | /// 931 | /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter 932 | /// is an MVC view component name. 933 | /// 934 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] 935 | [Conditional("JETBRAINS_ANNOTATIONS")] 936 | internal sealed class AspMvcViewComponentAttribute : Attribute { } 937 | 938 | /// 939 | /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter 940 | /// is an MVC view component view. If applied to a method, the MVC view component view name is default. 941 | /// 942 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] 943 | [Conditional("JETBRAINS_ANNOTATIONS")] 944 | internal sealed class AspMvcViewComponentViewAttribute : Attribute { } 945 | 946 | /// 947 | /// ASP.NET MVC attribute. When applied to a parameter of an attribute, 948 | /// indicates that this parameter is an MVC action name. 949 | /// 950 | /// 951 | /// [ActionName("Foo")] 952 | /// public ActionResult Login(string returnUrl) { 953 | /// ViewBag.ReturnUrl = Url.Action("Foo"); // OK 954 | /// return RedirectToAction("Bar"); // Error: Cannot resolve action 955 | /// } 956 | /// 957 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)] 958 | [Conditional("JETBRAINS_ANNOTATIONS")] 959 | internal sealed class AspMvcActionSelectorAttribute : Attribute { } 960 | 961 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Field)] 962 | [Conditional("JETBRAINS_ANNOTATIONS")] 963 | internal sealed class HtmlElementAttributesAttribute : Attribute 964 | { 965 | public HtmlElementAttributesAttribute() { } 966 | 967 | public HtmlElementAttributesAttribute([NotNull] string name) 968 | { 969 | Name = name; 970 | } 971 | 972 | [CanBeNull] public string Name { get; } 973 | } 974 | 975 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] 976 | [Conditional("JETBRAINS_ANNOTATIONS")] 977 | internal sealed class HtmlAttributeValueAttribute : Attribute 978 | { 979 | public HtmlAttributeValueAttribute([NotNull] string name) 980 | { 981 | Name = name; 982 | } 983 | 984 | [NotNull] public string Name { get; } 985 | } 986 | 987 | /// 988 | /// Razor attribute. Indicates that the marked parameter or method is a Razor section. 989 | /// Use this attribute for custom wrappers similar to 990 | /// System.Web.WebPages.WebPageBase.RenderSection(String). 991 | /// 992 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] 993 | [Conditional("JETBRAINS_ANNOTATIONS")] 994 | internal sealed class RazorSectionAttribute : Attribute { } 995 | 996 | /// 997 | /// Indicates how method, constructor invocation, or property access 998 | /// over collection type affects the contents of the collection. 999 | /// Use to specify the access type. 1000 | /// 1001 | /// 1002 | /// Using this attribute only makes sense if all collection methods are marked with this attribute. 1003 | /// 1004 | /// 1005 | /// public class MyStringCollection : List<string> 1006 | /// { 1007 | /// [CollectionAccess(CollectionAccessType.Read)] 1008 | /// public string GetFirstString() 1009 | /// { 1010 | /// return this.ElementAt(0); 1011 | /// } 1012 | /// } 1013 | /// class Test 1014 | /// { 1015 | /// public void Foo() 1016 | /// { 1017 | /// // Warning: Contents of the collection is never updated 1018 | /// var col = new MyStringCollection(); 1019 | /// string x = col.GetFirstString(); 1020 | /// } 1021 | /// } 1022 | /// 1023 | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property)] 1024 | [Conditional("JETBRAINS_ANNOTATIONS")] 1025 | internal sealed class CollectionAccessAttribute : Attribute 1026 | { 1027 | public CollectionAccessAttribute(CollectionAccessType collectionAccessType) 1028 | { 1029 | CollectionAccessType = collectionAccessType; 1030 | } 1031 | 1032 | public CollectionAccessType CollectionAccessType { get; } 1033 | } 1034 | 1035 | /// 1036 | /// Provides a value for the to define 1037 | /// how the collection method invocation affects the contents of the collection. 1038 | /// 1039 | [Flags] 1040 | internal enum CollectionAccessType 1041 | { 1042 | /// Method does not use or modify content of the collection. 1043 | None = 0, 1044 | /// Method only reads content of the collection but does not modify it. 1045 | Read = 1, 1046 | /// Method can change content of the collection but does not add new elements. 1047 | ModifyExistingContent = 2, 1048 | /// Method can add new elements to the collection. 1049 | UpdatedContent = ModifyExistingContent | 4 1050 | } 1051 | 1052 | /// 1053 | /// Indicates that the marked method is assertion method, i.e. it halts the control flow if 1054 | /// one of the conditions is satisfied. To set the condition, mark one of the parameters with 1055 | /// attribute. 1056 | /// 1057 | [AttributeUsage(AttributeTargets.Method)] 1058 | [Conditional("JETBRAINS_ANNOTATIONS")] 1059 | internal sealed class AssertionMethodAttribute : Attribute { } 1060 | 1061 | /// 1062 | /// Indicates the condition parameter of the assertion method. The method itself should be 1063 | /// marked by attribute. The mandatory argument of 1064 | /// the attribute is the assertion type. 1065 | /// 1066 | [AttributeUsage(AttributeTargets.Parameter)] 1067 | [Conditional("JETBRAINS_ANNOTATIONS")] 1068 | internal sealed class AssertionConditionAttribute : Attribute 1069 | { 1070 | public AssertionConditionAttribute(AssertionConditionType conditionType) 1071 | { 1072 | ConditionType = conditionType; 1073 | } 1074 | 1075 | public AssertionConditionType ConditionType { get; } 1076 | } 1077 | 1078 | /// 1079 | /// Specifies assertion type. If the assertion method argument satisfies the condition, 1080 | /// then the execution continues. Otherwise, execution is assumed to be halted. 1081 | /// 1082 | internal enum AssertionConditionType 1083 | { 1084 | /// Marked parameter should be evaluated to true. 1085 | IS_TRUE = 0, 1086 | /// Marked parameter should be evaluated to false. 1087 | IS_FALSE = 1, 1088 | /// Marked parameter should be evaluated to null value. 1089 | IS_NULL = 2, 1090 | /// Marked parameter should be evaluated to not null value. 1091 | IS_NOT_NULL = 3, 1092 | } 1093 | 1094 | /// 1095 | /// Indicates that the marked method unconditionally terminates control flow execution. 1096 | /// For example, it could unconditionally throw exception. 1097 | /// 1098 | [Obsolete("Use [ContractAnnotation('=> halt')] instead")] 1099 | [AttributeUsage(AttributeTargets.Method)] 1100 | [Conditional("JETBRAINS_ANNOTATIONS")] 1101 | internal sealed class TerminatesProgramAttribute : Attribute { } 1102 | 1103 | /// 1104 | /// Indicates that method is pure LINQ method, with postponed enumeration (like Enumerable.Select, 1105 | /// .Where). This annotation allows inference of [InstantHandle] annotation for parameters 1106 | /// of delegate type by analyzing LINQ method chains. 1107 | /// 1108 | [AttributeUsage(AttributeTargets.Method)] 1109 | [Conditional("JETBRAINS_ANNOTATIONS")] 1110 | internal sealed class LinqTunnelAttribute : Attribute { } 1111 | 1112 | /// 1113 | /// Indicates that IEnumerable passed as a parameter is not enumerated. 1114 | /// Use this annotation to suppress the 'Possible multiple enumeration of IEnumerable' inspection. 1115 | /// 1116 | /// 1117 | /// static void ThrowIfNull<T>([NoEnumeration] T v, string n) where T : class 1118 | /// { 1119 | /// // custom check for null but no enumeration 1120 | /// } 1121 | /// 1122 | /// void Foo(IEnumerable<string> values) 1123 | /// { 1124 | /// ThrowIfNull(values, nameof(values)); 1125 | /// var x = values.ToList(); // No warnings about multiple enumeration 1126 | /// } 1127 | /// 1128 | [AttributeUsage(AttributeTargets.Parameter)] 1129 | [Conditional("JETBRAINS_ANNOTATIONS")] 1130 | internal sealed class NoEnumerationAttribute : Attribute { } 1131 | 1132 | /// 1133 | /// Indicates that the marked parameter is a regular expression pattern. 1134 | /// 1135 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] 1136 | [Conditional("JETBRAINS_ANNOTATIONS")] 1137 | internal sealed class RegexPatternAttribute : Attribute { } 1138 | 1139 | /// 1140 | /// Prevents the Member Reordering feature from tossing members of the marked class. 1141 | /// 1142 | /// 1143 | /// The attribute must be mentioned in your member reordering patterns. 1144 | /// 1145 | [AttributeUsage( 1146 | AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.Enum)] 1147 | [Conditional("JETBRAINS_ANNOTATIONS")] 1148 | internal sealed class NoReorderAttribute : Attribute { } 1149 | 1150 | /// 1151 | /// XAML attribute. Indicates the type that has ItemsSource property and should be treated 1152 | /// as ItemsControl-derived type, to enable inner items DataContext type resolve. 1153 | /// 1154 | [AttributeUsage(AttributeTargets.Class)] 1155 | [Conditional("JETBRAINS_ANNOTATIONS")] 1156 | internal sealed class XamlItemsControlAttribute : Attribute { } 1157 | 1158 | /// 1159 | /// XAML attribute. Indicates the property of some BindingBase-derived type, that 1160 | /// is used to bind some item of ItemsControl-derived type. This annotation will 1161 | /// enable the DataContext type resolve for XAML bindings for such properties. 1162 | /// 1163 | /// 1164 | /// Property should have the tree ancestor of the ItemsControl type or 1165 | /// marked with the attribute. 1166 | /// 1167 | [AttributeUsage(AttributeTargets.Property)] 1168 | [Conditional("JETBRAINS_ANNOTATIONS")] 1169 | internal sealed class XamlItemBindingOfItemsControlAttribute : Attribute { } 1170 | 1171 | /// 1172 | /// XAML attribute. Indicates the property of some Style-derived type, that 1173 | /// is used to style items of ItemsControl-derived type. This annotation will 1174 | /// enable the DataContext type resolve for XAML bindings for such properties. 1175 | /// 1176 | /// 1177 | /// Property should have the tree ancestor of the ItemsControl type or 1178 | /// marked with the attribute. 1179 | /// 1180 | [AttributeUsage(AttributeTargets.Property)] 1181 | [Conditional("JETBRAINS_ANNOTATIONS")] 1182 | internal sealed class XamlItemStyleOfItemsControlAttribute : Attribute { } 1183 | 1184 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] 1185 | [Conditional("JETBRAINS_ANNOTATIONS")] 1186 | internal sealed class AspChildControlTypeAttribute : Attribute 1187 | { 1188 | public AspChildControlTypeAttribute([NotNull] string tagName, [NotNull] Type controlType) 1189 | { 1190 | TagName = tagName; 1191 | ControlType = controlType; 1192 | } 1193 | 1194 | [NotNull] public string TagName { get; } 1195 | 1196 | [NotNull] public Type ControlType { get; } 1197 | } 1198 | 1199 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)] 1200 | [Conditional("JETBRAINS_ANNOTATIONS")] 1201 | internal sealed class AspDataFieldAttribute : Attribute { } 1202 | 1203 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)] 1204 | [Conditional("JETBRAINS_ANNOTATIONS")] 1205 | internal sealed class AspDataFieldsAttribute : Attribute { } 1206 | 1207 | [AttributeUsage(AttributeTargets.Property)] 1208 | [Conditional("JETBRAINS_ANNOTATIONS")] 1209 | internal sealed class AspMethodPropertyAttribute : Attribute { } 1210 | 1211 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] 1212 | [Conditional("JETBRAINS_ANNOTATIONS")] 1213 | internal sealed class AspRequiredAttributeAttribute : Attribute 1214 | { 1215 | public AspRequiredAttributeAttribute([NotNull] string attribute) 1216 | { 1217 | Attribute = attribute; 1218 | } 1219 | 1220 | [NotNull] public string Attribute { get; } 1221 | } 1222 | 1223 | [AttributeUsage(AttributeTargets.Property)] 1224 | [Conditional("JETBRAINS_ANNOTATIONS")] 1225 | internal sealed class AspTypePropertyAttribute : Attribute 1226 | { 1227 | public bool CreateConstructorReferences { get; } 1228 | 1229 | public AspTypePropertyAttribute(bool createConstructorReferences) 1230 | { 1231 | CreateConstructorReferences = createConstructorReferences; 1232 | } 1233 | } 1234 | 1235 | [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] 1236 | [Conditional("JETBRAINS_ANNOTATIONS")] 1237 | internal sealed class RazorImportNamespaceAttribute : Attribute 1238 | { 1239 | public RazorImportNamespaceAttribute([NotNull] string name) 1240 | { 1241 | Name = name; 1242 | } 1243 | 1244 | [NotNull] public string Name { get; } 1245 | } 1246 | 1247 | [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] 1248 | [Conditional("JETBRAINS_ANNOTATIONS")] 1249 | internal sealed class RazorInjectionAttribute : Attribute 1250 | { 1251 | public RazorInjectionAttribute([NotNull] string type, [NotNull] string fieldName) 1252 | { 1253 | Type = type; 1254 | FieldName = fieldName; 1255 | } 1256 | 1257 | [NotNull] public string Type { get; } 1258 | 1259 | [NotNull] public string FieldName { get; } 1260 | } 1261 | 1262 | [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] 1263 | [Conditional("JETBRAINS_ANNOTATIONS")] 1264 | internal sealed class RazorDirectiveAttribute : Attribute 1265 | { 1266 | public RazorDirectiveAttribute([NotNull] string directive) 1267 | { 1268 | Directive = directive; 1269 | } 1270 | 1271 | [NotNull] public string Directive { get; } 1272 | } 1273 | 1274 | [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] 1275 | [Conditional("JETBRAINS_ANNOTATIONS")] 1276 | internal sealed class RazorPageBaseTypeAttribute : Attribute 1277 | { 1278 | public RazorPageBaseTypeAttribute([NotNull] string baseType) 1279 | { 1280 | BaseType = baseType; 1281 | } 1282 | public RazorPageBaseTypeAttribute([NotNull] string baseType, string pageName) 1283 | { 1284 | BaseType = baseType; 1285 | PageName = pageName; 1286 | } 1287 | 1288 | [NotNull] public string BaseType { get; } 1289 | [CanBeNull] public string PageName { get; } 1290 | } 1291 | 1292 | [AttributeUsage(AttributeTargets.Method)] 1293 | [Conditional("JETBRAINS_ANNOTATIONS")] 1294 | internal sealed class RazorHelperCommonAttribute : Attribute { } 1295 | 1296 | [AttributeUsage(AttributeTargets.Property)] 1297 | [Conditional("JETBRAINS_ANNOTATIONS")] 1298 | internal sealed class RazorLayoutAttribute : Attribute { } 1299 | 1300 | [AttributeUsage(AttributeTargets.Method)] 1301 | [Conditional("JETBRAINS_ANNOTATIONS")] 1302 | internal sealed class RazorWriteLiteralMethodAttribute : Attribute { } 1303 | 1304 | [AttributeUsage(AttributeTargets.Method)] 1305 | [Conditional("JETBRAINS_ANNOTATIONS")] 1306 | internal sealed class RazorWriteMethodAttribute : Attribute { } 1307 | 1308 | [AttributeUsage(AttributeTargets.Parameter)] 1309 | [Conditional("JETBRAINS_ANNOTATIONS")] 1310 | internal sealed class RazorWriteMethodParameterAttribute : Attribute { } 1311 | } -------------------------------------------------------------------------------- /BinaryExtensions/BinaryExtensions/BinaryExtensions.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "BinaryExtensions" 3 | } 4 | -------------------------------------------------------------------------------- /BinaryExtensions/BinaryExtensions/BinaryReaderExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using BinaryExtensions.Annotations; 4 | 5 | namespace BinaryExtensions 6 | { 7 | /// 8 | /// Extension methods for . 9 | /// 10 | [PublicAPI] 11 | public static class BinaryReaderExtensions 12 | { 13 | /// 14 | /// Reads an array of items using a function. 15 | /// 16 | /// 17 | /// The type of item to read. 18 | /// 19 | /// 20 | /// The source binary reader. 21 | /// 22 | /// 23 | /// The function for reading an item. 24 | /// 25 | /// 26 | /// The number of items to read. 27 | /// 28 | /// 29 | /// The array of items read. 30 | /// 31 | /// 32 | /// or is null. 33 | /// 34 | /// 35 | /// is less than or equal to zero. 36 | /// 37 | [NotNull] 38 | [ItemNotNull] 39 | public static T[] Read([NotNull] this BinaryReader reader, [NotNull] Func func, int count) 40 | { 41 | if (reader == null) 42 | throw new ArgumentNullException(nameof(reader)); 43 | 44 | if (func == null) 45 | throw new ArgumentNullException(nameof(func)); 46 | 47 | if (count <= 0) 48 | throw new ArgumentOutOfRangeException(nameof(count)); 49 | 50 | var items = new T[count]; 51 | 52 | for (var i = 0; i < count; i++) 53 | { 54 | items[i] = func(reader); 55 | } 56 | 57 | return items; 58 | } 59 | 60 | /// 61 | /// Reads an enumeration. 62 | /// 63 | /// 64 | /// The type of enumeration. 65 | /// 66 | /// 67 | /// The source binary reader. 68 | /// 69 | /// 70 | /// The endianness for the enumeration. 71 | /// 72 | /// 73 | /// The enumeration read. 74 | /// 75 | /// 76 | /// is null. 77 | /// 78 | [NotNull] 79 | public static T ReadEnum([NotNull] this BinaryReader reader, Endianness endianness = Endianness.Native) 80 | where T : Enum 81 | { 82 | if (reader == null) 83 | throw new ArgumentNullException(nameof(reader)); 84 | 85 | var enumType = typeof(T); 86 | var underlyingType = Enum.GetUnderlyingType(enumType); 87 | var typeCode = Type.GetTypeCode(underlyingType); 88 | 89 | // ReSharper disable once SwitchExpressionHandlesSomeKnownEnumValuesWithExceptionInDefault 90 | object value = typeCode switch 91 | { 92 | TypeCode.Byte => reader.ReadByte(), 93 | TypeCode.Int16 => reader.ReadInt16(endianness), 94 | TypeCode.Int32 => reader.ReadInt32(endianness), 95 | TypeCode.Int64 => reader.ReadInt64(endianness), 96 | TypeCode.SByte => reader.ReadSByte(), 97 | TypeCode.UInt16 => reader.ReadUInt16(endianness), 98 | TypeCode.UInt32 => reader.ReadUInt32(endianness), 99 | TypeCode.UInt64 => reader.ReadUInt64(endianness), 100 | _ => throw new InvalidOperationException() 101 | }; 102 | 103 | var result = (T) Enum.ToObject(enumType, value); 104 | 105 | return result; 106 | } 107 | 108 | /// 109 | /// Reads all bytes from the current position to the end of the stream. 110 | /// 111 | /// 112 | /// The source binary reader. 113 | /// 114 | /// 115 | /// The array of bytes read. 116 | /// 117 | /// 118 | /// is null. 119 | /// 120 | /// 121 | /// There is more than bytes to read. 122 | /// 123 | public static byte[] ReadToEnd([NotNull] this BinaryReader reader) 124 | { 125 | if (reader is null) 126 | throw new ArgumentNullException(nameof(reader)); 127 | 128 | var count = reader.BaseStream.Length - reader.BaseStream.Position; 129 | var bytes = reader.ReadBytes(count.ToInt32()); 130 | 131 | return bytes; 132 | } 133 | } 134 | } -------------------------------------------------------------------------------- /BinaryExtensions/BinaryExtensions/Endianness.cs: -------------------------------------------------------------------------------- 1 | namespace BinaryExtensions 2 | { 3 | /// 4 | /// Specifies the byte order for an integral type. 5 | /// 6 | public enum Endianness 7 | { 8 | /// 9 | /// Platform endianness. 10 | /// 11 | Native, 12 | 13 | /// 14 | /// Big-endian, i.e. MSB. 15 | /// 16 | BigEndian, 17 | 18 | /// 19 | /// Little-endian, i.e. LSB. 20 | /// 21 | LittleEndian 22 | } 23 | } -------------------------------------------------------------------------------- /BinaryExtensions/BinaryExtensions/EndiannessExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using BinaryExtensions.Annotations; 4 | 5 | namespace BinaryExtensions 6 | { 7 | /// 8 | /// Extension methods for endianness. 9 | /// 10 | public static partial class EndiannessExtensions 11 | { 12 | /// 13 | /// Gets the endianness for this environment. 14 | /// 15 | [PublicAPI] 16 | public static Endianness Endianness { get; } = 17 | BitConverter.IsLittleEndian 18 | ? Endianness.LittleEndian 19 | : Endianness.BigEndian; 20 | 21 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 22 | private static short ReverseEndianness(short value) 23 | { 24 | return (short) ReverseEndianness((ushort) value); 25 | } 26 | 27 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 28 | private static int ReverseEndianness(int value) 29 | { 30 | return (int) ReverseEndianness((uint) value); 31 | } 32 | 33 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 34 | private static long ReverseEndianness(long value) 35 | { 36 | return (long) ReverseEndianness((ulong) value); 37 | } 38 | 39 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 40 | private static ushort ReverseEndianness(ushort value) 41 | { 42 | return (ushort) ((value >> 8) + (value << 8)); 43 | } 44 | 45 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 46 | private static uint ReverseEndianness(uint value) 47 | { 48 | var value1 = value & 0x00FF00FFu; 49 | var value2 = value & 0xFF00FF00u; 50 | var value3 = ((value1 >> 8) | (value1 << (32 - 8))) + ((value2 << 8) | (value2 >> (32 - 8))); 51 | 52 | return value3; 53 | } 54 | 55 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 56 | private static ulong ReverseEndianness(ulong value) 57 | { 58 | var value1 = (ulong) ReverseEndianness((uint) value) << 32; 59 | var value2 = ReverseEndianness((uint) (value >> 32)); 60 | var value3 = value1 + value2; 61 | 62 | return value3; 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /BinaryExtensions/BinaryExtensions/EndiannessExtensions.g.cs: -------------------------------------------------------------------------------- 1 | // this file was auto-generated 2 | using System; 3 | using System.IO; 4 | 5 | namespace BinaryExtensions 6 | { 7 | public static partial class EndiannessExtensions 8 | { 9 | /// Reads a 16-bit signed integer from current stream. 10 | /// The source binary reader. 11 | /// The endianness of the integer. 12 | /// The integer read from the stream. 13 | /// is null. 14 | /// Not enough bytes to read the integer from current position. 15 | public static Int16 ReadInt16(this BinaryReader reader, Endianness endianness) 16 | { 17 | if (reader == null) 18 | throw new ArgumentNullException(nameof(reader)); 19 | 20 | if (reader.BaseStream.Position + sizeof(Int16) > reader.BaseStream.Length) 21 | throw new EndOfStreamException(); 22 | 23 | var value = reader.ReadInt16(); 24 | 25 | return endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 26 | } 27 | 28 | /// Reads a 32-bit signed integer from current stream. 29 | /// The source binary reader. 30 | /// The endianness of the integer. 31 | /// The integer read from the stream. 32 | /// is null. 33 | /// Not enough bytes to read the integer from current position. 34 | public static Int32 ReadInt32(this BinaryReader reader, Endianness endianness) 35 | { 36 | if (reader == null) 37 | throw new ArgumentNullException(nameof(reader)); 38 | 39 | if (reader.BaseStream.Position + sizeof(Int32) > reader.BaseStream.Length) 40 | throw new EndOfStreamException(); 41 | 42 | var value = reader.ReadInt32(); 43 | 44 | return endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 45 | } 46 | 47 | /// Reads a 64-bit signed integer from current stream. 48 | /// The source binary reader. 49 | /// The endianness of the integer. 50 | /// The integer read from the stream. 51 | /// is null. 52 | /// Not enough bytes to read the integer from current position. 53 | public static Int64 ReadInt64(this BinaryReader reader, Endianness endianness) 54 | { 55 | if (reader == null) 56 | throw new ArgumentNullException(nameof(reader)); 57 | 58 | if (reader.BaseStream.Position + sizeof(Int64) > reader.BaseStream.Length) 59 | throw new EndOfStreamException(); 60 | 61 | var value = reader.ReadInt64(); 62 | 63 | return endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 64 | } 65 | 66 | /// Reads a 16-bit unsigned integer from current stream. 67 | /// The source binary reader. 68 | /// The endianness of the integer. 69 | /// The integer read from the stream. 70 | /// is null. 71 | /// Not enough bytes to read the integer from current position. 72 | public static UInt16 ReadUInt16(this BinaryReader reader, Endianness endianness) 73 | { 74 | if (reader == null) 75 | throw new ArgumentNullException(nameof(reader)); 76 | 77 | if (reader.BaseStream.Position + sizeof(UInt16) > reader.BaseStream.Length) 78 | throw new EndOfStreamException(); 79 | 80 | var value = reader.ReadUInt16(); 81 | 82 | return endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 83 | } 84 | 85 | /// Reads a 32-bit unsigned integer from current stream. 86 | /// The source binary reader. 87 | /// The endianness of the integer. 88 | /// The integer read from the stream. 89 | /// is null. 90 | /// Not enough bytes to read the integer from current position. 91 | public static UInt32 ReadUInt32(this BinaryReader reader, Endianness endianness) 92 | { 93 | if (reader == null) 94 | throw new ArgumentNullException(nameof(reader)); 95 | 96 | if (reader.BaseStream.Position + sizeof(UInt32) > reader.BaseStream.Length) 97 | throw new EndOfStreamException(); 98 | 99 | var value = reader.ReadUInt32(); 100 | 101 | return endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 102 | } 103 | 104 | /// Reads a 64-bit unsigned integer from current stream. 105 | /// The source binary reader. 106 | /// The endianness of the integer. 107 | /// The integer read from the stream. 108 | /// is null. 109 | /// Not enough bytes to read the integer from current position. 110 | public static UInt64 ReadUInt64(this BinaryReader reader, Endianness endianness) 111 | { 112 | if (reader == null) 113 | throw new ArgumentNullException(nameof(reader)); 114 | 115 | if (reader.BaseStream.Position + sizeof(UInt64) > reader.BaseStream.Length) 116 | throw new EndOfStreamException(); 117 | 118 | var value = reader.ReadUInt64(); 119 | 120 | return endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 121 | } 122 | 123 | /// Reads a 16-bit signed integer from this array. 124 | /// The source array. 125 | /// The position to read the integer from . 126 | /// The endianness of the integer. 127 | /// The integer read from the array. 128 | /// is null. 129 | /// Not enough bytes to read the integer from . 130 | public static Int16 ReadInt16(this byte[] array, int index, Endianness endianness) 131 | { 132 | if (array == null) 133 | throw new ArgumentNullException(nameof(array)); 134 | 135 | if (index < 0 || index + sizeof(Int16) > array.Length) 136 | throw new ArgumentOutOfRangeException(nameof(index)); 137 | 138 | var value = BitConverter.ToInt16(array, index); 139 | 140 | return endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 141 | } 142 | 143 | /// Reads a 32-bit signed integer from this array. 144 | /// The source array. 145 | /// The position to read the integer from . 146 | /// The endianness of the integer. 147 | /// The integer read from the array. 148 | /// is null. 149 | /// Not enough bytes to read the integer from . 150 | public static Int32 ReadInt32(this byte[] array, int index, Endianness endianness) 151 | { 152 | if (array == null) 153 | throw new ArgumentNullException(nameof(array)); 154 | 155 | if (index < 0 || index + sizeof(Int32) > array.Length) 156 | throw new ArgumentOutOfRangeException(nameof(index)); 157 | 158 | var value = BitConverter.ToInt32(array, index); 159 | 160 | return endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 161 | } 162 | 163 | /// Reads a 64-bit signed integer from this array. 164 | /// The source array. 165 | /// The position to read the integer from . 166 | /// The endianness of the integer. 167 | /// The integer read from the array. 168 | /// is null. 169 | /// Not enough bytes to read the integer from . 170 | public static Int64 ReadInt64(this byte[] array, int index, Endianness endianness) 171 | { 172 | if (array == null) 173 | throw new ArgumentNullException(nameof(array)); 174 | 175 | if (index < 0 || index + sizeof(Int64) > array.Length) 176 | throw new ArgumentOutOfRangeException(nameof(index)); 177 | 178 | var value = BitConverter.ToInt64(array, index); 179 | 180 | return endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 181 | } 182 | 183 | /// Reads a 16-bit unsigned integer from this array. 184 | /// The source array. 185 | /// The position to read the integer from . 186 | /// The endianness of the integer. 187 | /// The integer read from the array. 188 | /// is null. 189 | /// Not enough bytes to read the integer from . 190 | public static UInt16 ReadUInt16(this byte[] array, int index, Endianness endianness) 191 | { 192 | if (array == null) 193 | throw new ArgumentNullException(nameof(array)); 194 | 195 | if (index < 0 || index + sizeof(UInt16) > array.Length) 196 | throw new ArgumentOutOfRangeException(nameof(index)); 197 | 198 | var value = BitConverter.ToUInt16(array, index); 199 | 200 | return endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 201 | } 202 | 203 | /// Reads a 32-bit unsigned integer from this array. 204 | /// The source array. 205 | /// The position to read the integer from . 206 | /// The endianness of the integer. 207 | /// The integer read from the array. 208 | /// is null. 209 | /// Not enough bytes to read the integer from . 210 | public static UInt32 ReadUInt32(this byte[] array, int index, Endianness endianness) 211 | { 212 | if (array == null) 213 | throw new ArgumentNullException(nameof(array)); 214 | 215 | if (index < 0 || index + sizeof(UInt32) > array.Length) 216 | throw new ArgumentOutOfRangeException(nameof(index)); 217 | 218 | var value = BitConverter.ToUInt32(array, index); 219 | 220 | return endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 221 | } 222 | 223 | /// Reads a 64-bit unsigned integer from this array. 224 | /// The source array. 225 | /// The position to read the integer from . 226 | /// The endianness of the integer. 227 | /// The integer read from the array. 228 | /// is null. 229 | /// Not enough bytes to read the integer from . 230 | public static UInt64 ReadUInt64(this byte[] array, int index, Endianness endianness) 231 | { 232 | if (array == null) 233 | throw new ArgumentNullException(nameof(array)); 234 | 235 | if (index < 0 || index + sizeof(UInt64) > array.Length) 236 | throw new ArgumentOutOfRangeException(nameof(index)); 237 | 238 | var value = BitConverter.ToUInt64(array, index); 239 | 240 | return endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 241 | } 242 | 243 | 244 | /// Tries to read a 16-bit signed integer from current stream. 245 | /// The source binary reader. 246 | /// The endianness of the integer. 247 | /// The variable receiving the integer. 248 | /// true if the integer was read from stream; otherwise, false. 249 | /// is null. 250 | public static bool TryReadInt16(this BinaryReader reader, Endianness endianness, out Int16 result) 251 | { 252 | result = default; 253 | 254 | if (reader == null) 255 | throw new ArgumentNullException(nameof(reader)); 256 | 257 | if (reader.BaseStream.Position + sizeof(Int16) > reader.BaseStream.Length) 258 | return false; 259 | 260 | var value = reader.ReadInt16(endianness); 261 | 262 | result = endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 263 | 264 | return true; 265 | } 266 | 267 | 268 | /// Tries to read a 32-bit signed integer from current stream. 269 | /// The source binary reader. 270 | /// The endianness of the integer. 271 | /// The variable receiving the integer. 272 | /// true if the integer was read from stream; otherwise, false. 273 | /// is null. 274 | public static bool TryReadInt32(this BinaryReader reader, Endianness endianness, out Int32 result) 275 | { 276 | result = default; 277 | 278 | if (reader == null) 279 | throw new ArgumentNullException(nameof(reader)); 280 | 281 | if (reader.BaseStream.Position + sizeof(Int32) > reader.BaseStream.Length) 282 | return false; 283 | 284 | var value = reader.ReadInt32(endianness); 285 | 286 | result = endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 287 | 288 | return true; 289 | } 290 | 291 | 292 | /// Tries to read a 64-bit signed integer from current stream. 293 | /// The source binary reader. 294 | /// The endianness of the integer. 295 | /// The variable receiving the integer. 296 | /// true if the integer was read from stream; otherwise, false. 297 | /// is null. 298 | public static bool TryReadInt64(this BinaryReader reader, Endianness endianness, out Int64 result) 299 | { 300 | result = default; 301 | 302 | if (reader == null) 303 | throw new ArgumentNullException(nameof(reader)); 304 | 305 | if (reader.BaseStream.Position + sizeof(Int64) > reader.BaseStream.Length) 306 | return false; 307 | 308 | var value = reader.ReadInt64(endianness); 309 | 310 | result = endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 311 | 312 | return true; 313 | } 314 | 315 | 316 | /// Tries to read a 16-bit unsigned integer from current stream. 317 | /// The source binary reader. 318 | /// The endianness of the integer. 319 | /// The variable receiving the integer. 320 | /// true if the integer was read from stream; otherwise, false. 321 | /// is null. 322 | public static bool TryReadUInt16(this BinaryReader reader, Endianness endianness, out UInt16 result) 323 | { 324 | result = default; 325 | 326 | if (reader == null) 327 | throw new ArgumentNullException(nameof(reader)); 328 | 329 | if (reader.BaseStream.Position + sizeof(UInt16) > reader.BaseStream.Length) 330 | return false; 331 | 332 | var value = reader.ReadUInt16(endianness); 333 | 334 | result = endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 335 | 336 | return true; 337 | } 338 | 339 | 340 | /// Tries to read a 32-bit unsigned integer from current stream. 341 | /// The source binary reader. 342 | /// The endianness of the integer. 343 | /// The variable receiving the integer. 344 | /// true if the integer was read from stream; otherwise, false. 345 | /// is null. 346 | public static bool TryReadUInt32(this BinaryReader reader, Endianness endianness, out UInt32 result) 347 | { 348 | result = default; 349 | 350 | if (reader == null) 351 | throw new ArgumentNullException(nameof(reader)); 352 | 353 | if (reader.BaseStream.Position + sizeof(UInt32) > reader.BaseStream.Length) 354 | return false; 355 | 356 | var value = reader.ReadUInt32(endianness); 357 | 358 | result = endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 359 | 360 | return true; 361 | } 362 | 363 | 364 | /// Tries to read a 64-bit unsigned integer from current stream. 365 | /// The source binary reader. 366 | /// The endianness of the integer. 367 | /// The variable receiving the integer. 368 | /// true if the integer was read from stream; otherwise, false. 369 | /// is null. 370 | public static bool TryReadUInt64(this BinaryReader reader, Endianness endianness, out UInt64 result) 371 | { 372 | result = default; 373 | 374 | if (reader == null) 375 | throw new ArgumentNullException(nameof(reader)); 376 | 377 | if (reader.BaseStream.Position + sizeof(UInt64) > reader.BaseStream.Length) 378 | return false; 379 | 380 | var value = reader.ReadUInt64(endianness); 381 | 382 | result = endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 383 | 384 | return true; 385 | } 386 | 387 | 388 | /// Tries to read a 16-bit signed integer from this array. 389 | /// The source array. 390 | /// The position to read the integer from . 391 | /// The endianness of the integer to read. 392 | /// The variable receiving the integer. 393 | /// true if the integer was read from array; otherwise, false. 394 | /// is null. 395 | public static bool TryReadInt16(this byte[] array, int index, Endianness endianness, out Int16 result) 396 | { 397 | result = default; 398 | 399 | if (array == null) 400 | throw new ArgumentNullException(nameof(array)); 401 | 402 | if (index < 0 || index + sizeof(Int16) > array.Length) 403 | return false; 404 | 405 | var value = BitConverter.ToInt16(array, index); 406 | 407 | value = endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 408 | 409 | return true; 410 | } 411 | 412 | /// Tries to read a 32-bit signed integer from this array. 413 | /// The source array. 414 | /// The position to read the integer from . 415 | /// The endianness of the integer to read. 416 | /// The variable receiving the integer. 417 | /// true if the integer was read from array; otherwise, false. 418 | /// is null. 419 | public static bool TryReadInt32(this byte[] array, int index, Endianness endianness, out Int32 result) 420 | { 421 | result = default; 422 | 423 | if (array == null) 424 | throw new ArgumentNullException(nameof(array)); 425 | 426 | if (index < 0 || index + sizeof(Int32) > array.Length) 427 | return false; 428 | 429 | var value = BitConverter.ToInt32(array, index); 430 | 431 | value = endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 432 | 433 | return true; 434 | } 435 | 436 | /// Tries to read a 64-bit signed integer from this array. 437 | /// The source array. 438 | /// The position to read the integer from . 439 | /// The endianness of the integer to read. 440 | /// The variable receiving the integer. 441 | /// true if the integer was read from array; otherwise, false. 442 | /// is null. 443 | public static bool TryReadInt64(this byte[] array, int index, Endianness endianness, out Int64 result) 444 | { 445 | result = default; 446 | 447 | if (array == null) 448 | throw new ArgumentNullException(nameof(array)); 449 | 450 | if (index < 0 || index + sizeof(Int64) > array.Length) 451 | return false; 452 | 453 | var value = BitConverter.ToInt64(array, index); 454 | 455 | value = endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 456 | 457 | return true; 458 | } 459 | 460 | /// Tries to read a 16-bit unsigned integer from this array. 461 | /// The source array. 462 | /// The position to read the integer from . 463 | /// The endianness of the integer to read. 464 | /// The variable receiving the integer. 465 | /// true if the integer was read from array; otherwise, false. 466 | /// is null. 467 | public static bool TryReadUInt16(this byte[] array, int index, Endianness endianness, out UInt16 result) 468 | { 469 | result = default; 470 | 471 | if (array == null) 472 | throw new ArgumentNullException(nameof(array)); 473 | 474 | if (index < 0 || index + sizeof(UInt16) > array.Length) 475 | return false; 476 | 477 | var value = BitConverter.ToUInt16(array, index); 478 | 479 | value = endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 480 | 481 | return true; 482 | } 483 | 484 | /// Tries to read a 32-bit unsigned integer from this array. 485 | /// The source array. 486 | /// The position to read the integer from . 487 | /// The endianness of the integer to read. 488 | /// The variable receiving the integer. 489 | /// true if the integer was read from array; otherwise, false. 490 | /// is null. 491 | public static bool TryReadUInt32(this byte[] array, int index, Endianness endianness, out UInt32 result) 492 | { 493 | result = default; 494 | 495 | if (array == null) 496 | throw new ArgumentNullException(nameof(array)); 497 | 498 | if (index < 0 || index + sizeof(UInt32) > array.Length) 499 | return false; 500 | 501 | var value = BitConverter.ToUInt32(array, index); 502 | 503 | value = endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 504 | 505 | return true; 506 | } 507 | 508 | /// Tries to read a 64-bit unsigned integer from this array. 509 | /// The source array. 510 | /// The position to read the integer from . 511 | /// The endianness of the integer to read. 512 | /// The variable receiving the integer. 513 | /// true if the integer was read from array; otherwise, false. 514 | /// is null. 515 | public static bool TryReadUInt64(this byte[] array, int index, Endianness endianness, out UInt64 result) 516 | { 517 | result = default; 518 | 519 | if (array == null) 520 | throw new ArgumentNullException(nameof(array)); 521 | 522 | if (index < 0 || index + sizeof(UInt64) > array.Length) 523 | return false; 524 | 525 | var value = BitConverter.ToUInt64(array, index); 526 | 527 | value = endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 528 | 529 | return true; 530 | } 531 | } 532 | } 533 | -------------------------------------------------------------------------------- /BinaryExtensions/BinaryExtensions/EndiannessExtensions.tt: -------------------------------------------------------------------------------- 1 | <#@ template debug="true" hostspecific="true" language="C#" #> 2 | <#@ assembly name="System.Core" #> 3 | <#@ output extension=".g.cs" #> 4 | // this file was auto-generated 5 | using System; 6 | using System.IO; 7 | 8 | namespace BinaryExtensions 9 | { 10 | public static partial class EndiannessExtensions 11 | { 12 | <# 13 | var types = new (string Type, string Text)[] 14 | { 15 | (nameof(Int16), "a 16-bit signed"), 16 | (nameof(Int32), "a 32-bit signed"), 17 | (nameof(Int64), "a 64-bit signed"), 18 | (nameof(UInt16), "a 16-bit unsigned"), 19 | (nameof(UInt32), "a 32-bit unsigned"), 20 | (nameof(UInt64), "a 64-bit unsigned") 21 | }; 22 | 23 | foreach (var (type, text) in types) 24 | { 25 | #> 26 | /// Reads <#= text #> integer from current stream. 27 | /// The source binary reader. 28 | /// The endianness of the integer. 29 | /// The integer read from the stream. 30 | /// is null. 31 | /// Not enough bytes to read the integer from current position. 32 | public static <#= type #> Read<#= type #>(this BinaryReader reader, Endianness endianness) 33 | { 34 | if (reader == null) 35 | throw new ArgumentNullException(nameof(reader)); 36 | 37 | if (reader.BaseStream.Position + sizeof(<#= type #>) > reader.BaseStream.Length) 38 | throw new EndOfStreamException(); 39 | 40 | var value = reader.Read<#= type #>(); 41 | 42 | return endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 43 | } 44 | 45 | <# 46 | } 47 | 48 | foreach (var (type, text) in types) 49 | { 50 | #> 51 | /// Reads <#= text #> integer from this array. 52 | /// The source array. 53 | /// The position to read the integer from . 54 | /// The endianness of the integer. 55 | /// The integer read from the array. 56 | /// is null. 57 | /// Not enough bytes to read the integer from . 58 | public static <#= type #> Read<#=type #>(this byte[] array, int index, Endianness endianness) 59 | { 60 | if (array == null) 61 | throw new ArgumentNullException(nameof(array)); 62 | 63 | if (index < 0 || index + sizeof(<#=type #>) > array.Length) 64 | throw new ArgumentOutOfRangeException(nameof(index)); 65 | 66 | var value = BitConverter.To<#=type #>(array, index); 67 | 68 | return endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 69 | } 70 | 71 | <# 72 | } 73 | foreach (var (type, text) in types) 74 | { 75 | #> 76 | 77 | /// Tries to read <#= text #> integer from current stream. 78 | /// The source binary reader. 79 | /// The endianness of the integer. 80 | /// The variable receiving the integer. 81 | /// true if the integer was read from stream; otherwise, false. 82 | /// is null. 83 | public static bool TryRead<#= type #>(this BinaryReader reader, Endianness endianness, out <#= type #> result) 84 | { 85 | result = default; 86 | 87 | if (reader == null) 88 | throw new ArgumentNullException(nameof(reader)); 89 | 90 | if (reader.BaseStream.Position + sizeof(<#= type #>) > reader.BaseStream.Length) 91 | return false; 92 | 93 | var value = reader.Read<#= type #>(endianness); 94 | 95 | result = endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 96 | 97 | return true; 98 | } 99 | 100 | <# 101 | } 102 | foreach (var (type, text) in types) 103 | { 104 | #> 105 | 106 | /// Tries to read <#= text #> integer from this array. 107 | /// The source array. 108 | /// The position to read the integer from . 109 | /// The endianness of the integer to read. 110 | /// The variable receiving the integer. 111 | /// true if the integer was read from array; otherwise, false. 112 | /// is null. 113 | public static bool TryRead<#=type #>(this byte[] array, int index, Endianness endianness, out <#= type #> result) 114 | { 115 | result = default; 116 | 117 | if (array == null) 118 | throw new ArgumentNullException(nameof(array)); 119 | 120 | if (index < 0 || index + sizeof(<#=type #>) > array.Length) 121 | return false; 122 | 123 | var value = BitConverter.To<#=type #>(array, index); 124 | 125 | value = endianness == Endianness || endianness == Endianness.Native ? value : ReverseEndianness(value); 126 | 127 | return true; 128 | } 129 | <# 130 | } 131 | #> 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /BinaryExtensions/BinaryExtensions/IntegralTypesExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using BinaryExtensions.Annotations; 3 | 4 | namespace BinaryExtensions 5 | { 6 | /// 7 | /// Extension methods for integral types. 8 | /// 9 | [PublicAPI] 10 | public static class IntegralTypesExtensions 11 | { 12 | /// 13 | /// Converts this integer to a 32-bit signed integer. 14 | /// 15 | /// 16 | /// The integer to convert. 17 | /// 18 | /// 19 | /// The integer as a 32-bit signed integer. 20 | /// 21 | public static int ToInt32(this long value) 22 | { 23 | return Convert.ToInt32(value); 24 | } 25 | 26 | /// 27 | /// Converts this integer to a 32-bit signed integer. 28 | /// 29 | /// 30 | /// The integer to convert. 31 | /// 32 | /// 33 | /// The integer as a 32-bit signed integer. 34 | /// 35 | public static int ToInt32(this uint value) 36 | { 37 | return Convert.ToInt32(value); 38 | } 39 | 40 | /// 41 | /// Converts this integer to a 32-bit signed integer. 42 | /// 43 | /// 44 | /// The integer to convert. 45 | /// 46 | /// 47 | /// The integer as a 32-bit signed integer. 48 | /// 49 | public static int ToInt32(this ulong value) 50 | { 51 | return Convert.ToInt32(value); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /BinaryExtensions/BinaryExtensions/LogStream.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using BinaryExtensions.Annotations; 6 | 7 | namespace BinaryExtensions 8 | { 9 | /// 10 | /// A stream that wraps and logs read and written regions of another stream. 11 | /// 12 | [PublicAPI] 13 | public class LogStream : Stream 14 | { 15 | #region Static Fields and Constants 16 | 17 | private const int InvalidRegionIndex = -1; 18 | 19 | #endregion 20 | 21 | #region Constructors 22 | 23 | /// 24 | /// Initializes a new instance of . 25 | /// 26 | /// 27 | /// The stream to wrap. 28 | /// 29 | /// 30 | /// Whether or not to dispose after disposing. 31 | /// 32 | /// 33 | /// is null. 34 | /// 35 | public LogStream([NotNull] Stream stream, bool leaveOpen = false) 36 | { 37 | Stream = stream ?? throw new ArgumentNullException(nameof(stream)); 38 | StreamLeaveOpen = leaveOpen; 39 | } 40 | 41 | #endregion 42 | 43 | #region Fields 44 | 45 | private readonly List RegionsR = new List(); 46 | 47 | private readonly List RegionsW = new List(); 48 | 49 | private readonly Stream Stream; 50 | 51 | private readonly bool StreamLeaveOpen; 52 | 53 | private bool IsDisposed; 54 | 55 | private int RegionsRIndex = InvalidRegionIndex; 56 | 57 | private string RegionsRName; 58 | 59 | private int RegionsWIndex = InvalidRegionIndex; 60 | 61 | private string RegionsWName; 62 | 63 | #endregion 64 | 65 | #region Overrides 66 | 67 | /// 68 | public override bool CanRead => Stream.CanRead; 69 | 70 | /// 71 | public override bool CanSeek => Stream.CanSeek; 72 | 73 | /// 74 | public override bool CanWrite => Stream.CanWrite; 75 | 76 | /// 77 | public override long Length => Stream.Length; 78 | 79 | /// 80 | public override long Position 81 | { 82 | get => Stream.Position; 83 | set => Stream.Position = value; 84 | } 85 | 86 | /// 87 | protected override void Dispose(bool disposing) 88 | { 89 | if (!IsDisposed) 90 | { 91 | if (disposing && !StreamLeaveOpen) 92 | { 93 | Stream.Dispose(); 94 | } 95 | 96 | IsDisposed = true; 97 | } 98 | 99 | base.Dispose(disposing); 100 | } 101 | 102 | /// 103 | public override void Flush() 104 | { 105 | Stream.Flush(); 106 | } 107 | 108 | /// 109 | public override int Read(byte[] buffer, int offset, int count) 110 | { 111 | using var _ = new LogStreamScope(Stream, RegionsR); 112 | return Stream.Read(buffer, offset, count); 113 | } 114 | 115 | /// 116 | public override long Seek(long offset, SeekOrigin origin) 117 | { 118 | return Stream.Seek(offset, origin); 119 | } 120 | 121 | /// 122 | public override void SetLength(long value) 123 | { 124 | Stream.SetLength(value); 125 | } 126 | 127 | /// 128 | public override void Write(byte[] buffer, int offset, int count) 129 | { 130 | using var _ = new LogStreamScope(Stream, RegionsW); 131 | Stream.Write(buffer, offset, count); 132 | } 133 | 134 | #endregion 135 | 136 | #region Methods 137 | 138 | private static void BeginGroup( 139 | [NotNull] string callee, [NotNull] string caller, 140 | [NotNull] IList regions, ref int regionIndex, ref string regionName, string name) 141 | { 142 | if (regions is null) 143 | throw new ArgumentNullException(nameof(regions)); 144 | 145 | if (callee is null) 146 | throw new ArgumentNullException(nameof(callee)); 147 | 148 | if (caller is null) 149 | throw new ArgumentNullException(nameof(caller)); 150 | 151 | if (regionIndex != InvalidRegionIndex) 152 | throw new InvalidOperationException($"A preceding call to {callee} was not followed by a call to {caller}."); 153 | 154 | regionIndex = regions.Count; 155 | regionName = name; 156 | } 157 | 158 | private static void EndGroup( 159 | [NotNull] string callee, [NotNull] string caller, 160 | [NotNull] IList regions, ref int regionIndex, ref string regionName) 161 | { 162 | if (callee is null) 163 | throw new ArgumentNullException(nameof(callee)); 164 | 165 | if (caller is null) 166 | throw new ArgumentNullException(nameof(caller)); 167 | 168 | if (regions is null) 169 | throw new ArgumentNullException(nameof(regions)); 170 | 171 | if (regionIndex == InvalidRegionIndex) 172 | throw new InvalidOperationException($"A preceding call to {caller} was not followed by a call to {callee}."); 173 | 174 | var enumerable = regions.Skip(regionIndex).Take(regions.Count - regionIndex); 175 | 176 | using var enumerator = enumerable.GetEnumerator(); 177 | 178 | if (enumerator.MoveNext() == false) 179 | throw new InvalidOperationException("Source stream state hasn't changed."); 180 | 181 | var current = enumerator.Current; 182 | var position = current.Position; 183 | var length = 0L; 184 | var count = 1; 185 | 186 | while (enumerator.MoveNext()) // ensure they're all contiguous or overlapping 187 | { 188 | var region = enumerator.Current; 189 | 190 | if (region.Position > current.Position + current.Length) 191 | throw new InvalidOperationException("Only successive or overlapping accesses are allowed."); 192 | 193 | length += region.Length; 194 | count += 1; 195 | current = region; 196 | } 197 | 198 | // concat into single one 199 | 200 | for (var i = 0; i < count; i++) 201 | { 202 | regions.RemoveAt(regions.Count - 1); 203 | } 204 | 205 | regions.Add(new LogStreamRegion(position, length, regionName)); 206 | 207 | regionIndex = InvalidRegionIndex; 208 | regionName = null; 209 | } 210 | 211 | private IReadOnlyList GetRegionsIntersect([NotNull] IEnumerable regions) 212 | { 213 | if (regions is null) 214 | throw new ArgumentNullException(nameof(regions)); 215 | 216 | var source = regions.OrderBy(s => s.Position).ThenBy(s => s.Length).ToList(); 217 | 218 | for (var i = 0; i < source.Count - 1; i++) // concat overlapping regions 219 | { 220 | var region1 = source[i]; 221 | var region2 = source[i + 1]; 222 | 223 | if (region1.Position + region1.Length < region2.Position) 224 | continue; 225 | 226 | var pos = region1.Position; 227 | var max = Math.Max(region1.Position + region1.Length, region2.Position + region2.Length); 228 | var len = max - pos; 229 | var name1 = region1.Name?.Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()); 230 | var name2 = region2.Name?.Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()); 231 | var name3 = string.Join(", ", string.Concat(name1, name2)); 232 | 233 | source[i] = new LogStreamRegion(pos, len, name3); 234 | source.RemoveAt(i + 1); 235 | i--; // do it again 236 | } 237 | 238 | var target = new List 239 | { 240 | new LogStreamRegion(0, Stream.Length) 241 | }; 242 | 243 | foreach (var region in source) // extract non-accessed regions 244 | { 245 | var old = target[target.Count - 1]; 246 | var oldPos = old.Position; 247 | var oldLen = region.Position - oldPos; 248 | 249 | target[target.Count - 1] = new LogStreamRegion(oldPos, oldLen, old.Name); 250 | 251 | var newPos = region.Position + region.Length; 252 | var newLen = Stream.Length - newPos; 253 | 254 | target.Add(new LogStreamRegion(newPos, newLen, region.Name)); 255 | } 256 | 257 | target = target.Where(s => s.Length > 0).ToList(); // simple fix 258 | 259 | return target.AsReadOnly(); 260 | } 261 | 262 | /// 263 | /// Begins a group that concatenates successive reads. 264 | /// 265 | /// 266 | /// The name for the group. 267 | /// 268 | /// 269 | /// A preceding call to was not followed by a call to . 270 | /// 271 | [PublicAPI] 272 | public void BeginReadGroup(string name = null) 273 | { 274 | BeginGroup(nameof(BeginReadGroup), nameof(EndGroup), RegionsR, ref RegionsRIndex, ref RegionsRName, name); 275 | } 276 | 277 | /// 278 | /// Begins a group that concatenates successive writes. 279 | /// 280 | /// 281 | /// The name for the group. 282 | /// 283 | /// 284 | /// A preceding call to was not followed by a call to . 285 | /// 286 | [PublicAPI] 287 | public void BeginWriteGroup(string name = null) 288 | { 289 | BeginGroup(nameof(BeginWriteGroup), nameof(EndWriteGroup), RegionsW, ref RegionsWIndex, ref RegionsWName, name); 290 | } 291 | 292 | /// 293 | /// Ends a group that concatenates successive reads. 294 | /// 295 | /// 296 | /// A preceding call to was not followed by a call to . 297 | /// 298 | /// 299 | /// No data was read from source stream. 300 | /// 301 | /// 302 | /// Only successive or overlapping reads are allowed. 303 | /// 304 | [PublicAPI] 305 | public void EndReadGroup() 306 | { 307 | EndGroup(nameof(EndReadGroup), nameof(BeginReadGroup), RegionsR, ref RegionsRIndex, ref RegionsRName); 308 | } 309 | 310 | /// 311 | /// Ends a group that concatenates successive writes. 312 | /// 313 | /// 314 | /// A preceding call to was not followed by a call to . 315 | /// 316 | /// 317 | /// No data was written to source stream. 318 | /// 319 | /// 320 | /// Only successive or overlapping writes are allowed. 321 | /// 322 | [PublicAPI] 323 | public void EndWriteGroup() 324 | { 325 | EndGroup(nameof(EndWriteGroup), nameof(BeginWriteGroup), RegionsW, ref RegionsWIndex, ref RegionsWName); 326 | } 327 | 328 | /// 329 | /// Gets the list of regions that have been read. 330 | /// 331 | /// 332 | /// A list containing regions that have been read. 333 | /// 334 | [PublicAPI] 335 | [NotNull] 336 | public IReadOnlyList GetRegionsRead() 337 | { 338 | return RegionsR.AsReadOnly(); 339 | } 340 | 341 | /// 342 | /// Gets the of regions that haven't been read. 343 | /// 344 | /// 345 | /// A list containing regions that haven't been read. 346 | /// 347 | [PublicAPI] 348 | [NotNull] 349 | public IReadOnlyList GetRegionsReadIntersect() 350 | { 351 | return GetRegionsIntersect(RegionsR); 352 | } 353 | 354 | /// 355 | /// Gets the list of regions that have been written. 356 | /// 357 | /// 358 | /// A list containing regions that have been written. 359 | /// 360 | [PublicAPI] 361 | [NotNull] 362 | public IReadOnlyList GetRegionsWritten() 363 | { 364 | return RegionsW.AsReadOnly(); 365 | } 366 | 367 | /// 368 | /// Gets the of regions that haven't been written. 369 | /// 370 | /// 371 | /// A list containing regions that haven't been written. 372 | /// 373 | [PublicAPI] 374 | [NotNull] 375 | public IReadOnlyList GetRegionsWrittenIntersect() 376 | { 377 | return GetRegionsIntersect(RegionsW); 378 | } 379 | 380 | #endregion 381 | } 382 | } -------------------------------------------------------------------------------- /BinaryExtensions/BinaryExtensions/LogStreamRegion.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using BinaryExtensions.Annotations; 3 | 4 | namespace BinaryExtensions 5 | { 6 | /// 7 | /// Represents a region in a stream. 8 | /// 9 | [PublicAPI] 10 | public readonly struct LogStreamRegion : IEquatable 11 | { 12 | /// 13 | /// Gets the position for this instance. 14 | /// 15 | public long Position { get; } 16 | 17 | /// 18 | /// Gets the length for this instance. 19 | /// 20 | public long Length { get; } 21 | 22 | /// 23 | /// Gets the name for this instance. 24 | /// 25 | [CanBeNull] 26 | public string Name { get; } 27 | 28 | /// 29 | /// Initializes a new instance of . 30 | /// 31 | /// 32 | /// The position for the region. 33 | /// 34 | /// 35 | /// The length for the region. 36 | /// 37 | /// 38 | /// The name for the region. 39 | /// 40 | public LogStreamRegion(long position, long length, [CanBeNull] string name = null) 41 | { 42 | Position = position; 43 | Length = length; 44 | Name = name; 45 | } 46 | 47 | /// 48 | public bool Equals(LogStreamRegion other) 49 | { 50 | return Position == other.Position && Length == other.Length && Name == other.Name; 51 | } 52 | 53 | /// 54 | public override bool Equals(object obj) 55 | { 56 | return obj is LogStreamRegion other && Equals(other); 57 | } 58 | 59 | /// 60 | public override int GetHashCode() 61 | { 62 | unchecked 63 | { 64 | var hashCode = Position.GetHashCode(); 65 | hashCode = (hashCode * 397) ^ Length.GetHashCode(); 66 | hashCode = (hashCode * 397) ^ (Name != null ? Name.GetHashCode() : 0); 67 | return hashCode; 68 | } 69 | } 70 | 71 | /// 72 | /// Determines whether the specified instances are equal. 73 | /// 74 | /// 75 | /// The first instance to compare. 76 | /// 77 | /// 78 | /// The second instance to compare. 79 | /// 80 | /// 81 | /// true if is equal to , otherwise false. 82 | /// 83 | public static bool operator ==(LogStreamRegion left, LogStreamRegion right) 84 | { 85 | return left.Equals(right); 86 | } 87 | 88 | /// 89 | /// Determines whether the specified instances are not equal. 90 | /// 91 | /// 92 | /// The first instance to compare. 93 | /// 94 | /// 95 | /// The second instance to compare. 96 | /// 97 | /// 98 | /// true if is not equal to , otherwise false. 99 | /// 100 | public static bool operator !=(LogStreamRegion left, LogStreamRegion right) 101 | { 102 | return !left.Equals(right); 103 | } 104 | 105 | /// 106 | public override string ToString() 107 | { 108 | return $"{nameof(Position)}: {Position}, {nameof(Length)}: {Length}, {nameof(Name)}: {Name}"; 109 | } 110 | } 111 | } -------------------------------------------------------------------------------- /BinaryExtensions/BinaryExtensions/LogStreamScope.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using BinaryExtensions.Annotations; 5 | 6 | namespace BinaryExtensions 7 | { 8 | internal readonly struct LogStreamScope : IDisposable 9 | { 10 | [NotNull] 11 | private Stream Stream { get; } 12 | 13 | [NotNull] 14 | private IList Regions { get; } 15 | 16 | private long Position { get; } 17 | 18 | public LogStreamScope([NotNull] Stream stream, [NotNull] IList regions) 19 | { 20 | Stream = stream ?? throw new ArgumentNullException(nameof(stream)); 21 | Regions = regions ?? throw new ArgumentNullException(nameof(regions)); 22 | Position = stream.Position; 23 | } 24 | 25 | public void Dispose() 26 | { 27 | Regions.Add(new LogStreamRegion(Position, Stream.Position - Position)); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /BinaryExtensions/BinaryExtensions/StreamExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using BinaryExtensions.Annotations; 5 | 6 | namespace BinaryExtensions 7 | { 8 | /// 9 | /// Extension methods for . 10 | /// 11 | [PublicAPI] 12 | public static class StreamExtensions 13 | { 14 | /// 15 | /// Gets a binary reader based on this stream. 16 | /// 17 | /// 18 | /// The source stream. 19 | /// 20 | /// 21 | /// The encoding for the binary reader, null for . 22 | /// 23 | /// 24 | /// true to leave the stream open after the binary reader is disposed; otherwise, false. 25 | /// 26 | /// 27 | /// The binary reader. 28 | /// 29 | /// 30 | /// is null. 31 | /// 32 | [NotNull] 33 | public static BinaryReader GetBinaryReader([NotNull] this Stream stream, [CanBeNull] Encoding encoding = null, bool leaveOpen = true) 34 | { 35 | if (stream == null) 36 | throw new ArgumentNullException(nameof(stream)); 37 | 38 | var reader = new BinaryReader(stream, encoding ?? Encoding.Default, leaveOpen); 39 | 40 | return reader; 41 | } 42 | 43 | /// 44 | /// Reads bytes at current position from this stream. 45 | /// 46 | /// 47 | /// The source stream. 48 | /// 49 | /// 50 | /// The number of bytes to read. 51 | /// 52 | /// 53 | /// The array of bytes read. 54 | /// 55 | /// 56 | /// is null. 57 | /// 58 | /// 59 | /// is less than or equal to zero. 60 | /// 61 | /// 62 | /// bytes could not be read from . 63 | /// 64 | [NotNull] 65 | public static byte[] ReadBytes([NotNull] this Stream stream, int count) 66 | { 67 | if (stream == null) 68 | throw new ArgumentNullException(nameof(stream)); 69 | 70 | if (count <= 0) 71 | throw new ArgumentOutOfRangeException(nameof(count)); 72 | 73 | var buffer = new byte[count]; 74 | 75 | var read = stream.Read(buffer, 0, buffer.Length); 76 | 77 | if (read != count) 78 | { 79 | throw new EndOfStreamException(); 80 | } 81 | 82 | return buffer; 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /BinaryExtensions/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | $(DefaultItemExcludes);**\*.meta 4 | 5 | -------------------------------------------------------------------------------- /BinaryExtensionsTests/BinaryExtensionsTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /BinaryExtensionsTests/UnitTest1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using BinaryExtensions; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | 6 | namespace BinaryExtensionsTests 7 | { 8 | [TestClass] 9 | public class UnitTest1 10 | { 11 | [TestMethod] 12 | public void FullyReadStreamHasNoIntersectRegions() 13 | { 14 | var buffer = new byte[1000]; 15 | var random = new Random(0); 16 | random.NextBytes(buffer); 17 | using var source = new MemoryStream(buffer); 18 | using var target = new LogStream(source); 19 | using var reader = new BinaryReader(target); 20 | reader.ReadToEnd(); 21 | var intersect = target.GetRegionsReadIntersect(); 22 | Assert.IsTrue(intersect.Count == 0); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 https://github.com/aybe 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BinaryExtensions 2 | ![BinaryExtensions](BinaryExtensions.png) 3 | 4 | [![NuGet](https://img.shields.io/badge/nuget-latest-blue.svg)](https://www.nuget.org/packages/BinaryExtensions) 5 | 6 | Types and extension methods to deal with binary data. 7 | 8 | ## Features 9 | 10 | - read primitives in any endianness using `Read` and `TryRead` extension methods for `BinaryReader` and `byte[]` 11 | - a logged stream that logs read and written regions in a wrapped stream 12 | - e.g. reverse-engineering a file format and find what's currently been unexplored in the file by your logic 13 | 14 | ## CHANGELOG 15 | 16 | 1.1.2 (11/19/2020) 17 | - added BinaryReader.ReadToEnd method 18 | - fixed LogStream.GetRegionsReadIntersect that was returning empty regions for fully read streams 19 | - added tests project 20 | - enforced C# 8.0 version so project can still be used in Unity 21 | - using internal annotations to prevent conflicts, e.g. when using UnityEngine.CoreModule in non-Unity projects 22 | - don't include XML documentation in repository 23 | 24 | 1.1.1 (10/2/2020) 25 | - publishing release configuration instead 26 | 27 | 1.1.0 (10/2/2020) 28 | - **breaking changes** 29 | - not overloading `System.IO` namespace anymore 30 | - not everything has been back ported yet 31 | - switching to .NET Standard 2.1 32 | - better NuGet package with sources and symbols 33 | - now using T4 templates for code generation 34 | - version bump to 1.1.0 35 | - new icon 36 | 37 | 1.0.* (11/18/2018) 38 | - seamless reading of integral types in big-endian or little-endian format, environment endianness being irrelevant 39 | - functions are exposed as extension methods for `BinaryReader` and all integral types 40 | - endian-aware integral types, just declare structs and read them in one go with `ReadStruct` 41 | - a `LoggedBinaryReader` that logs read and unread regions, very useful when deciphering some complex file format 42 | --------------------------------------------------------------------------------