From d4726706ead9f9799a3f2e192458012e8f57054c Mon Sep 17 00:00:00 2001 From: Ben Shillito Date: Mon, 31 Oct 2016 13:31:36 +0000 Subject: [PATCH] REORG: Exposed common base classes and functions so other assemblies can access them. Base classes and functions have now been made public, this makes them accessible from other assemblies. Changes have also been made to configurations in the solutions, tidying them up to only use AnyCPU. --- .gitignore | 7 +- 51degrees 4.sln | 70 +--------- Examples/Meta Data/Meta Data.csproj | 2 +- FoundationV3/FiftyOne.Foundation 4.csproj | 7 +- FoundationV3/FiftyOne.Foundation SQL.sqlproj | 2 + FoundationV3/Mobile/Detection/BaseDataSet.cs | 73 ++++++++++ FoundationV3/Mobile/Detection/Controller.cs | 12 +- FoundationV3/Mobile/Detection/DataSet.cs | 10 +- .../Mobile/Detection/Entities/AsciiString.cs | 13 +- .../Mobile/Detection/Entities/BaseEntity.cs | 124 ++--------------- .../Mobile/Detection/Entities/Component.cs | 2 +- FoundationV3/Mobile/Detection/Entities/Map.cs | 2 +- .../Entities/Memory/EntityFactories.cs | 32 ++++- .../Entities/Memory/MemoryBaseList.cs | 23 ++-- .../Entities/Memory/MemoryFixedList.cs | 20 ++- .../Entities/Memory/MemoryVariableList.cs | 27 ++-- .../Detection/Entities/Memory/NodeV31.cs | 2 +- .../Detection/Entities/Memory/Profile.cs | 4 +- .../Entities/Memory/PropertiesList.cs | 4 +- .../Mobile/Detection/Entities/Node.cs | 6 +- .../Detection/Entities/NodeIndexBase.cs | 4 +- .../Mobile/Detection/Entities/Profile.cs | 54 ++++---- .../Detection/Entities/ProfileOffset.cs | 2 +- .../Mobile/Detection/Entities/Property.cs | 2 +- .../Mobile/Detection/Entities/Signature.cs | 2 +- .../Detection/Entities/Stream/BaseList.cs | 20 +-- .../Mobile/Detection/Entities/Stream/Cache.cs | 8 +- .../Detection/Entities/Stream/CacheList.cs | 16 ++- .../Detection/Entities/Stream/DataSet.cs | 4 +- .../Entities/Stream/EntityFactories.cs | 38 ++++-- .../Entities/Stream/FixedCacheList.cs | 20 +-- .../Detection/Entities/Stream/FixedList.cs | 16 ++- .../Entities/Stream/IStreamDataSet.cs | 36 +++++ .../Detection/Entities/Stream/NodeV31.cs | 2 +- .../Mobile/Detection/Entities/Stream/Pool.cs | 11 +- .../Detection/Entities/Stream/Profile.cs | 4 +- .../Detection/Entities/Stream/VariableList.cs | 22 +-- .../Mobile/Detection/Entities/Utf8String.cs | 108 +++++++++++++++ .../Mobile/Detection/Entities/Utils.cs | 105 ++++++++++++++ .../Mobile/Detection/Entities/Value.cs | 2 +- .../Detection/Factories/EntityFactories.cs | 129 +++++++++--------- .../Detection/Factories/MemoryFactory.cs | 30 ++-- .../Detection/Factories/StreamFactory.cs | 27 ++-- .../Mobile/Detection/IReadonlyList.cs | 4 +- .../Mobile/Detection/Readers/Reader.cs | 7 +- .../Mobile/Detection/Readers/Source.cs | 24 ++-- FoundationV3/Mobile/Detection/Search.cs | 124 ++++++++++++++--- Integration Tests/Integration Tests.csproj | 21 ++- README.md | 18 ++- 49 files changed, 827 insertions(+), 475 deletions(-) create mode 100644 FoundationV3/Mobile/Detection/BaseDataSet.cs create mode 100644 FoundationV3/Mobile/Detection/Entities/Stream/IStreamDataSet.cs create mode 100644 FoundationV3/Mobile/Detection/Entities/Utf8String.cs create mode 100644 FoundationV3/Mobile/Detection/Entities/Utils.cs diff --git a/.gitignore b/.gitignore index bd74113..64f0764 100644 --- a/.gitignore +++ b/.gitignore @@ -186,11 +186,14 @@ UpgradeLog*.htm # Microsoft Fakes Log.txt + +# 51Degrees *.lic *Enterprise*.dat *Premium*.dat *Enterprise*.trie *Premium*.trie -App_Data/Cache/ +**/App_Data/Cache million.csv -*.snk \ No newline at end of file +*.snk + diff --git a/51degrees 4.sln b/51degrees 4.sln index 61a8b32..aee3c04 100644 --- a/51degrees 4.sln +++ b/51degrees 4.sln @@ -66,133 +66,71 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {A0A7C5CE-1B06-4BB3-AB9D-DB055C6EDF69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A0A7C5CE-1B06-4BB3-AB9D-DB055C6EDF69}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A0A7C5CE-1B06-4BB3-AB9D-DB055C6EDF69}.Debug|x64.ActiveCfg = Debug|Any CPU - {A0A7C5CE-1B06-4BB3-AB9D-DB055C6EDF69}.Debug|x64.Build.0 = Debug|Any CPU {A0A7C5CE-1B06-4BB3-AB9D-DB055C6EDF69}.Release|Any CPU.ActiveCfg = Release|Any CPU {A0A7C5CE-1B06-4BB3-AB9D-DB055C6EDF69}.Release|Any CPU.Build.0 = Release|Any CPU - {A0A7C5CE-1B06-4BB3-AB9D-DB055C6EDF69}.Release|x64.ActiveCfg = Release|Any CPU - {A0A7C5CE-1B06-4BB3-AB9D-DB055C6EDF69}.Release|x64.Build.0 = Release|Any CPU {9D658044-FB65-4939-8449-A3A1DEBBB31A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9D658044-FB65-4939-8449-A3A1DEBBB31A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9D658044-FB65-4939-8449-A3A1DEBBB31A}.Debug|x64.ActiveCfg = Debug|x64 - {9D658044-FB65-4939-8449-A3A1DEBBB31A}.Debug|x64.Build.0 = Debug|x64 {9D658044-FB65-4939-8449-A3A1DEBBB31A}.Release|Any CPU.ActiveCfg = Release|Any CPU {9D658044-FB65-4939-8449-A3A1DEBBB31A}.Release|Any CPU.Build.0 = Release|Any CPU - {9D658044-FB65-4939-8449-A3A1DEBBB31A}.Release|x64.ActiveCfg = Release|x64 - {9D658044-FB65-4939-8449-A3A1DEBBB31A}.Release|x64.Build.0 = Release|x64 - {1211A461-73CA-4D7E-86A7-983540F12539}.Debug|Any CPU.ActiveCfg = Debug|x64 - {1211A461-73CA-4D7E-86A7-983540F12539}.Debug|x64.ActiveCfg = Debug|x64 - {1211A461-73CA-4D7E-86A7-983540F12539}.Debug|x64.Build.0 = Debug|x64 - {1211A461-73CA-4D7E-86A7-983540F12539}.Release|Any CPU.ActiveCfg = Release|x64 - {1211A461-73CA-4D7E-86A7-983540F12539}.Release|x64.ActiveCfg = Release|x64 - {1211A461-73CA-4D7E-86A7-983540F12539}.Release|x64.Build.0 = Release|x64 + {1211A461-73CA-4D7E-86A7-983540F12539}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1211A461-73CA-4D7E-86A7-983540F12539}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1211A461-73CA-4D7E-86A7-983540F12539}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1211A461-73CA-4D7E-86A7-983540F12539}.Release|Any CPU.Build.0 = Release|Any CPU {6535DE09-9EFF-4876-9D65-6483EFD453AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6535DE09-9EFF-4876-9D65-6483EFD453AD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6535DE09-9EFF-4876-9D65-6483EFD453AD}.Debug|x64.ActiveCfg = Debug|Any CPU - {6535DE09-9EFF-4876-9D65-6483EFD453AD}.Debug|x64.Build.0 = Debug|Any CPU {6535DE09-9EFF-4876-9D65-6483EFD453AD}.Release|Any CPU.ActiveCfg = Release|Any CPU {6535DE09-9EFF-4876-9D65-6483EFD453AD}.Release|Any CPU.Build.0 = Release|Any CPU - {6535DE09-9EFF-4876-9D65-6483EFD453AD}.Release|x64.ActiveCfg = Release|Any CPU - {6535DE09-9EFF-4876-9D65-6483EFD453AD}.Release|x64.Build.0 = Release|Any CPU {324F06B4-50D5-4F6E-9DEE-2DA05B2B3B18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {324F06B4-50D5-4F6E-9DEE-2DA05B2B3B18}.Debug|Any CPU.Build.0 = Debug|Any CPU - {324F06B4-50D5-4F6E-9DEE-2DA05B2B3B18}.Debug|x64.ActiveCfg = Debug|x64 - {324F06B4-50D5-4F6E-9DEE-2DA05B2B3B18}.Debug|x64.Build.0 = Debug|x64 {324F06B4-50D5-4F6E-9DEE-2DA05B2B3B18}.Release|Any CPU.ActiveCfg = Release|Any CPU {324F06B4-50D5-4F6E-9DEE-2DA05B2B3B18}.Release|Any CPU.Build.0 = Release|Any CPU - {324F06B4-50D5-4F6E-9DEE-2DA05B2B3B18}.Release|x64.ActiveCfg = Release|x64 - {324F06B4-50D5-4F6E-9DEE-2DA05B2B3B18}.Release|x64.Build.0 = Release|x64 {069D6175-9007-40DD-A313-F63C9377A680}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {069D6175-9007-40DD-A313-F63C9377A680}.Debug|Any CPU.Build.0 = Debug|Any CPU - {069D6175-9007-40DD-A313-F63C9377A680}.Debug|x64.ActiveCfg = Debug|x64 - {069D6175-9007-40DD-A313-F63C9377A680}.Debug|x64.Build.0 = Debug|x64 {069D6175-9007-40DD-A313-F63C9377A680}.Release|Any CPU.ActiveCfg = Release|Any CPU {069D6175-9007-40DD-A313-F63C9377A680}.Release|Any CPU.Build.0 = Release|Any CPU - {069D6175-9007-40DD-A313-F63C9377A680}.Release|x64.ActiveCfg = Release|x64 - {069D6175-9007-40DD-A313-F63C9377A680}.Release|x64.Build.0 = Release|x64 {FB500454-EC93-4FEA-BDD8-FBA018EF2C3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FB500454-EC93-4FEA-BDD8-FBA018EF2C3C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FB500454-EC93-4FEA-BDD8-FBA018EF2C3C}.Debug|x64.ActiveCfg = Debug|x64 - {FB500454-EC93-4FEA-BDD8-FBA018EF2C3C}.Debug|x64.Build.0 = Debug|x64 {FB500454-EC93-4FEA-BDD8-FBA018EF2C3C}.Release|Any CPU.ActiveCfg = Release|Any CPU {FB500454-EC93-4FEA-BDD8-FBA018EF2C3C}.Release|Any CPU.Build.0 = Release|Any CPU - {FB500454-EC93-4FEA-BDD8-FBA018EF2C3C}.Release|x64.ActiveCfg = Release|x64 - {FB500454-EC93-4FEA-BDD8-FBA018EF2C3C}.Release|x64.Build.0 = Release|x64 {DBA7559B-EF3C-496D-BDC7-9EF76A5D3EB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DBA7559B-EF3C-496D-BDC7-9EF76A5D3EB9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DBA7559B-EF3C-496D-BDC7-9EF76A5D3EB9}.Debug|x64.ActiveCfg = Debug|x64 - {DBA7559B-EF3C-496D-BDC7-9EF76A5D3EB9}.Debug|x64.Build.0 = Debug|x64 {DBA7559B-EF3C-496D-BDC7-9EF76A5D3EB9}.Release|Any CPU.ActiveCfg = Release|Any CPU {DBA7559B-EF3C-496D-BDC7-9EF76A5D3EB9}.Release|Any CPU.Build.0 = Release|Any CPU - {DBA7559B-EF3C-496D-BDC7-9EF76A5D3EB9}.Release|x64.ActiveCfg = Release|x64 - {DBA7559B-EF3C-496D-BDC7-9EF76A5D3EB9}.Release|x64.Build.0 = Release|x64 {091CBBA9-94C4-486B-B630-6533E787A489}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {091CBBA9-94C4-486B-B630-6533E787A489}.Debug|Any CPU.Build.0 = Debug|Any CPU - {091CBBA9-94C4-486B-B630-6533E787A489}.Debug|x64.ActiveCfg = Debug|x64 - {091CBBA9-94C4-486B-B630-6533E787A489}.Debug|x64.Build.0 = Debug|x64 {091CBBA9-94C4-486B-B630-6533E787A489}.Release|Any CPU.ActiveCfg = Release|Any CPU {091CBBA9-94C4-486B-B630-6533E787A489}.Release|Any CPU.Build.0 = Release|Any CPU - {091CBBA9-94C4-486B-B630-6533E787A489}.Release|x64.ActiveCfg = Release|x64 - {091CBBA9-94C4-486B-B630-6533E787A489}.Release|x64.Build.0 = Release|x64 {9BD47A7B-6D73-46BD-82D5-E7E9BE347646}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9BD47A7B-6D73-46BD-82D5-E7E9BE347646}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9BD47A7B-6D73-46BD-82D5-E7E9BE347646}.Debug|x64.ActiveCfg = Debug|x64 - {9BD47A7B-6D73-46BD-82D5-E7E9BE347646}.Debug|x64.Build.0 = Debug|x64 {9BD47A7B-6D73-46BD-82D5-E7E9BE347646}.Release|Any CPU.ActiveCfg = Release|Any CPU {9BD47A7B-6D73-46BD-82D5-E7E9BE347646}.Release|Any CPU.Build.0 = Release|Any CPU - {9BD47A7B-6D73-46BD-82D5-E7E9BE347646}.Release|x64.ActiveCfg = Release|x64 - {9BD47A7B-6D73-46BD-82D5-E7E9BE347646}.Release|x64.Build.0 = Release|x64 {F4B351DA-1474-4F6B-83D1-75B62CB19CD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F4B351DA-1474-4F6B-83D1-75B62CB19CD7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F4B351DA-1474-4F6B-83D1-75B62CB19CD7}.Debug|x64.ActiveCfg = Debug|x64 - {F4B351DA-1474-4F6B-83D1-75B62CB19CD7}.Debug|x64.Build.0 = Debug|x64 {F4B351DA-1474-4F6B-83D1-75B62CB19CD7}.Release|Any CPU.ActiveCfg = Release|Any CPU {F4B351DA-1474-4F6B-83D1-75B62CB19CD7}.Release|Any CPU.Build.0 = Release|Any CPU - {F4B351DA-1474-4F6B-83D1-75B62CB19CD7}.Release|x64.ActiveCfg = Release|x64 - {F4B351DA-1474-4F6B-83D1-75B62CB19CD7}.Release|x64.Build.0 = Release|x64 {608157FD-165C-40F4-AF79-BC812C9BC70E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {608157FD-165C-40F4-AF79-BC812C9BC70E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {608157FD-165C-40F4-AF79-BC812C9BC70E}.Debug|x64.ActiveCfg = Debug|Any CPU - {608157FD-165C-40F4-AF79-BC812C9BC70E}.Debug|x64.Build.0 = Debug|Any CPU {608157FD-165C-40F4-AF79-BC812C9BC70E}.Release|Any CPU.ActiveCfg = Release|Any CPU {608157FD-165C-40F4-AF79-BC812C9BC70E}.Release|Any CPU.Build.0 = Release|Any CPU - {608157FD-165C-40F4-AF79-BC812C9BC70E}.Release|x64.ActiveCfg = Release|Any CPU - {608157FD-165C-40F4-AF79-BC812C9BC70E}.Release|x64.Build.0 = Release|Any CPU {B91129C0-224A-4AA7-BE18-C13EB2E2BDFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B91129C0-224A-4AA7-BE18-C13EB2E2BDFD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B91129C0-224A-4AA7-BE18-C13EB2E2BDFD}.Debug|x64.ActiveCfg = Debug|x64 - {B91129C0-224A-4AA7-BE18-C13EB2E2BDFD}.Debug|x64.Build.0 = Debug|x64 {B91129C0-224A-4AA7-BE18-C13EB2E2BDFD}.Release|Any CPU.ActiveCfg = Release|Any CPU {B91129C0-224A-4AA7-BE18-C13EB2E2BDFD}.Release|Any CPU.Build.0 = Release|Any CPU - {B91129C0-224A-4AA7-BE18-C13EB2E2BDFD}.Release|x64.ActiveCfg = Release|x64 - {B91129C0-224A-4AA7-BE18-C13EB2E2BDFD}.Release|x64.Build.0 = Release|x64 {EA6A83FE-D698-4E4D-821E-1B5BCC22D501}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EA6A83FE-D698-4E4D-821E-1B5BCC22D501}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EA6A83FE-D698-4E4D-821E-1B5BCC22D501}.Debug|x64.ActiveCfg = Debug|x64 - {EA6A83FE-D698-4E4D-821E-1B5BCC22D501}.Debug|x64.Build.0 = Debug|x64 {EA6A83FE-D698-4E4D-821E-1B5BCC22D501}.Release|Any CPU.ActiveCfg = Release|Any CPU {EA6A83FE-D698-4E4D-821E-1B5BCC22D501}.Release|Any CPU.Build.0 = Release|Any CPU - {EA6A83FE-D698-4E4D-821E-1B5BCC22D501}.Release|x64.ActiveCfg = Release|x64 - {EA6A83FE-D698-4E4D-821E-1B5BCC22D501}.Release|x64.Build.0 = Release|x64 {334A1D9F-82F5-41C0-8583-76823D8BF2B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {334A1D9F-82F5-41C0-8583-76823D8BF2B1}.Debug|Any CPU.Build.0 = Debug|Any CPU {334A1D9F-82F5-41C0-8583-76823D8BF2B1}.Debug|Any CPU.Deploy.0 = Debug|Any CPU - {334A1D9F-82F5-41C0-8583-76823D8BF2B1}.Debug|x64.ActiveCfg = Debug|x64 - {334A1D9F-82F5-41C0-8583-76823D8BF2B1}.Debug|x64.Build.0 = Debug|x64 - {334A1D9F-82F5-41C0-8583-76823D8BF2B1}.Debug|x64.Deploy.0 = Debug|x64 {334A1D9F-82F5-41C0-8583-76823D8BF2B1}.Release|Any CPU.ActiveCfg = Release|Any CPU {334A1D9F-82F5-41C0-8583-76823D8BF2B1}.Release|Any CPU.Build.0 = Release|Any CPU {334A1D9F-82F5-41C0-8583-76823D8BF2B1}.Release|Any CPU.Deploy.0 = Release|Any CPU - {334A1D9F-82F5-41C0-8583-76823D8BF2B1}.Release|x64.ActiveCfg = Release|x64 - {334A1D9F-82F5-41C0-8583-76823D8BF2B1}.Release|x64.Build.0 = Release|x64 - {334A1D9F-82F5-41C0-8583-76823D8BF2B1}.Release|x64.Deploy.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Examples/Meta Data/Meta Data.csproj b/Examples/Meta Data/Meta Data.csproj index 7160b0e..a89c8f7 100644 --- a/Examples/Meta Data/Meta Data.csproj +++ b/Examples/Meta Data/Meta Data.csproj @@ -23,7 +23,7 @@ 4 - x64 + AnyCPU pdbonly true bin\x64\Release\ diff --git a/FoundationV3/FiftyOne.Foundation 4.csproj b/FoundationV3/FiftyOne.Foundation 4.csproj index d588e66..aee14e2 100644 --- a/FoundationV3/FiftyOne.Foundation 4.csproj +++ b/FoundationV3/FiftyOne.Foundation 4.csproj @@ -88,7 +88,7 @@ bin\Release4\FiftyOne.Foundation.xml true pdbonly - x64 + AnyCPU bin\Release4\FiftyOne.Foundation.dll.CodeAnalysisLog.xml true GlobalSuppressions.cs @@ -143,6 +143,7 @@ Code + @@ -162,10 +163,12 @@ + + @@ -339,8 +342,10 @@ + + diff --git a/FoundationV3/FiftyOne.Foundation SQL.sqlproj b/FoundationV3/FiftyOne.Foundation SQL.sqlproj index 2f820fe..a1e24b4 100644 --- a/FoundationV3/FiftyOne.Foundation SQL.sqlproj +++ b/FoundationV3/FiftyOne.Foundation SQL.sqlproj @@ -165,6 +165,8 @@ + + diff --git a/FoundationV3/Mobile/Detection/BaseDataSet.cs b/FoundationV3/Mobile/Detection/BaseDataSet.cs new file mode 100644 index 0000000..8162d8c --- /dev/null +++ b/FoundationV3/Mobile/Detection/BaseDataSet.cs @@ -0,0 +1,73 @@ +/* ********************************************************************* + * This Source Code Form is copyright of 51Degrees Mobile Experts Limited. + * Copyright © 2015 51Degrees Mobile Experts Limited, 5 Charlotte Close, + * Caversham, Reading, Berkshire, United Kingdom RG4 7BY + * + * This Source Code Form is the subject of the following patent + * applications, owned by 51Degrees Mobile Experts Limited of 5 Charlotte + * Close, Caversham, Reading, Berkshire, United Kingdom RG4 7BY: + * European Patent Application No. 13192291.6; and + * United States Patent Application Nos. 14/085,223 and 14/085,301. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. + * + * If a copy of the MPL was not distributed with this file, You can obtain + * one at http://mozilla.org/MPL/2.0/. + * + * This Source Code Form is “Incompatible With Secondary Licenses”, as + * defined by the Mozilla Public License, v. 2.0. + * ********************************************************************* */ + +using System; + +namespace FiftyOne.Foundation.Mobile.Detection.Entities +{ + public abstract class BaseDataSet : IDisposable + { + /// + /// Set when the disposed method is called indicating the data + /// set is no longer valid and can't be used. + /// + public bool Disposed { get; private set; } + + /// + /// Constructs a new instance of . + /// + protected BaseDataSet() + { + } + + #region Destructor + + /// + /// Disposes of all the lists that form the dataset. + /// + ~BaseDataSet() + { + Dispose(false); + } + + /// + /// Disposes of all the lists that form the dataset. + /// + public void Dispose() + { + Dispose(true); + } + + /// + /// Disposes of the readonly lists used by the dataset. + /// + /// + /// True if the calling method is Dispose, false for the finaliser. + /// + protected virtual void Dispose(bool disposing) + { + Disposed = true; + GC.SuppressFinalize(this); + } + + #endregion + } +} \ No newline at end of file diff --git a/FoundationV3/Mobile/Detection/Controller.cs b/FoundationV3/Mobile/Detection/Controller.cs index abe7a12..be317fb 100644 --- a/FoundationV3/Mobile/Detection/Controller.cs +++ b/FoundationV3/Mobile/Detection/Controller.cs @@ -509,8 +509,8 @@ protected override int GetScore(MatchState state, Node node) var newTargetIndex = targetIndex + 1; while (newNodeIndex < node.Length && newTargetIndex < target.Length && - BaseEntity.GetIsNumeric(target[newTargetIndex]) && - BaseEntity.GetIsNumeric(node[newNodeIndex])) + Utils.GetIsNumeric(target[newTargetIndex]) && + Utils.GetIsNumeric(node[newNodeIndex])) { newNodeIndex++; newTargetIndex++; @@ -522,8 +522,8 @@ protected override int GetScore(MatchState state, Node node) var characters = 0; while ( nodeIndex >= 0 && - BaseEntity.GetIsNumeric(target[targetIndex]) && - BaseEntity.GetIsNumeric(node[nodeIndex])) + Utils.GetIsNumeric(target[targetIndex]) && + Utils.GetIsNumeric(node[nodeIndex])) { nodeIndex--; targetIndex--; @@ -535,8 +535,8 @@ protected override int GetScore(MatchState state, Node node) if (characters > 1) { return Math.Abs( - BaseEntity.GetNumber(target, targetIndex + 1, characters) - - BaseEntity.GetNumber(node, nodeIndex + 1, characters)); + Utils.GetNumber(target, targetIndex + 1, characters) - + Utils.GetNumber(node, nodeIndex + 1, characters)); } return 0; diff --git a/FoundationV3/Mobile/Detection/DataSet.cs b/FoundationV3/Mobile/Detection/DataSet.cs index 71b900b..650c90a 100644 --- a/FoundationV3/Mobile/Detection/DataSet.cs +++ b/FoundationV3/Mobile/Detection/DataSet.cs @@ -694,20 +694,20 @@ public string Format /// /// A list of all the components the data set contains. /// - public MemoryFixedList Components + public MemoryFixedList Components { get { return _components; } } - internal MemoryFixedList _components; + internal MemoryFixedList _components; /// /// A list of all the maps the data set contains. /// - public MemoryFixedList Maps + public MemoryFixedList Maps { get { return _maps; } } - internal MemoryFixedList _maps; + internal MemoryFixedList _maps; /// /// A list of all properties the data set contains. @@ -796,7 +796,7 @@ internal ISimpleList SignatureNodeOffsets /// /// A list of ASCII byte arrays for strings used by the dataset. /// - internal IReadonlyList Strings; + internal IReadonlyList> Strings; #endregion diff --git a/FoundationV3/Mobile/Detection/Entities/AsciiString.cs b/FoundationV3/Mobile/Detection/Entities/AsciiString.cs index 200e35e..b169657 100644 --- a/FoundationV3/Mobile/Detection/Entities/AsciiString.cs +++ b/FoundationV3/Mobile/Detection/Entities/AsciiString.cs @@ -28,7 +28,7 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities /// ASCII format strings are the only ones used in the data set. Many /// native string formats use Unicode format using 2 bytes for every /// character. This is inefficient when only ASCII values are being - /// stored. The class wraps a byte array of + /// stored. The class wraps a byte array of /// ASCII characters and exposes them as a native string type when /// required. /// @@ -41,21 +41,24 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities /// /// For more information see https://51degrees.com/Support/Documentation/Net /// - internal class AsciiString : BaseEntity + /// + /// The type of the shared data set the AsciiString relates to. + /// + internal class AsciiString : BaseEntity { #region Fields /// /// The value of the string in ASCII bytes. /// - internal readonly byte[] Value; + public readonly byte[] Value; #endregion #region Constructor /// - /// Constructs a new instance of . + /// Constructs a new instance of . /// /// /// The data set whose strings list the string is contained within. @@ -67,7 +70,7 @@ internal class AsciiString : BaseEntity /// /// Binary reader positioned at the start of the AsciiString. /// - internal AsciiString(DataSet dataSet, int offset, BinaryReader reader) + internal AsciiString(T dataSet, int offset, BinaryReader reader) : base(dataSet, offset) { // Read the length of the array minus 1 to remove the diff --git a/FoundationV3/Mobile/Detection/Entities/BaseEntity.cs b/FoundationV3/Mobile/Detection/Entities/BaseEntity.cs index 702f51c..22d176d 100644 --- a/FoundationV3/Mobile/Detection/Entities/BaseEntity.cs +++ b/FoundationV3/Mobile/Detection/Entities/BaseEntity.cs @@ -33,25 +33,19 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities /// used by multiple entities. /// /// - /// For more information see https://51degrees.com/Support/Documentation/Net + /// For more information see + /// https://51degrees.com/Support/Documentation/Net /// - public abstract class BaseEntity : IComparable, IComparable, IEquatable + /// Not intended to be used directly by 3rd parties. + public abstract class BaseEntity : + IComparable>, IComparable, IEquatable { - #region Constants - - /// - /// List if powers used to determine numeric differences. - /// - private static readonly int[] Powers = new[] { 1, 10, 100, 1000, 10000 }; - - #endregion - #region Properties /// /// The data set the entity relates to. /// - public readonly DataSet DataSet; + public readonly T DataSet; /// /// The unique index of the item in the collection of items, or @@ -61,45 +55,12 @@ public abstract class BaseEntity : IComparable, IComparable, IE #endregion - #region Delegates - - /// - /// Used to create a new instance of an entity. - /// - /// - /// The being created or added to. - /// - /// - /// The unique index of offset of the entity in the list - /// - /// - /// Reader connected to the source data structure and positioned to - /// start reading. - /// - /// A new instance of the entity - /// - /// The delegate is used to enable inheriting classes to control how - /// lists containing entities of their type are created. When generic - /// types support parameterised constructors the need for this - /// delegate will be removed. - /// - internal delegate BaseEntity Create(DataSet dataSet, int indexOrOffset, BinaryReader reader); - - /// - /// Used to return the length in bytes of an entity when stored in the - /// underlying data structure. - /// - /// Entity whose length is required - /// The length in bytes of the entity - internal delegate int GetLength(BaseEntity entity); - - #endregion - #region Constructor /// /// Constructs the base item for the data set and index provided. /// + /// Not intended to be used directly by 3rd parties. /// /// The being created /// @@ -107,7 +68,7 @@ public abstract class BaseEntity : IComparable, IComparable, IE /// The unique index of the item in the collection of items, or /// the unique offset to the item in the source data structure. /// - internal BaseEntity(DataSet dataSet, int indexOrOffset) + protected BaseEntity(T dataSet, int indexOrOffset) { DataSet = dataSet; Index = indexOrOffset; @@ -147,7 +108,7 @@ public int CompareTo(int indexOrOffset) /// /// The position of one entity over the other. /// - public int CompareTo(BaseEntity other) + public int CompareTo(BaseEntity other) { return CompareTo(other.Index); } @@ -173,72 +134,5 @@ public override int GetHashCode() } #endregion - - #region Static Methods - - /// - /// An enumerable that can be used to read through the entries. - /// - /// Reader set to the position at the start of the list - /// The number of integers to read to form the array - /// Iterator to read each integer entry. - protected static IEnumerable GetIntegerEnumerator(BinaryReader reader, int count) - { - for (int i = 0; i < count; i++) - { - yield return reader.ReadInt32(); - } - } - - /// - /// Reads an integer array where the first integer is the number of - /// following integers. - /// - /// Reader set to the position at the start of the list - /// The number of integers to read to form the array - /// An array of integers - protected static int[] ReadIntegerArray(BinaryReader reader, int count) - { - var array = new int[count]; - for (int i = 0; i < array.Length; i++) - array[i] = reader.ReadInt32(); - return array; - } - - /// - /// Returns an integer representation of the characters between start and end. - /// Assumes that all the characters are numeric characters. - /// - /// - /// Array of characters with numeric characters present between start and end - /// - /// - /// The first character to use to convert to a number - /// - /// - /// The number of characters to use in the conversion - /// - /// - internal static int GetNumber(byte[] array, int start, int length) - { - int value = 0; - for (int i = start + length - 1, p = 0; i >= start && p < Powers.Length; i--, p++) - { - value += Powers[p] * ((byte)array[i] - (byte)'0'); - } - return value; - } - - /// - /// Determines if the value is an ASCII numeric value. - /// - /// Byte value to be checked - /// True if the value is an ASCII numeric character - internal static bool GetIsNumeric(byte value) - { - return (value >= (byte)'0' && value <= (byte)'9'); - } - - #endregion } } diff --git a/FoundationV3/Mobile/Detection/Entities/Component.cs b/FoundationV3/Mobile/Detection/Entities/Component.cs index b2d82a2..e68476d 100644 --- a/FoundationV3/Mobile/Detection/Entities/Component.cs +++ b/FoundationV3/Mobile/Detection/Entities/Component.cs @@ -39,7 +39,7 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities /// /// For more information see https://51degrees.com/Support/Documentation/Net /// - public abstract class Component : BaseEntity, IComparable, IEquatable + public abstract class Component : BaseEntity, IComparable, IEquatable { #region Fields diff --git a/FoundationV3/Mobile/Detection/Entities/Map.cs b/FoundationV3/Mobile/Detection/Entities/Map.cs index 9e726a5..dc41fd8 100644 --- a/FoundationV3/Mobile/Detection/Entities/Map.cs +++ b/FoundationV3/Mobile/Detection/Entities/Map.cs @@ -26,7 +26,7 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities /// /// Class used to link a property to one or more export maps. /// - public class Map : BaseEntity + public class Map : BaseEntity { #region Fields diff --git a/FoundationV3/Mobile/Detection/Entities/Memory/EntityFactories.cs b/FoundationV3/Mobile/Detection/Entities/Memory/EntityFactories.cs index 0d58e47..5742682 100644 --- a/FoundationV3/Mobile/Detection/Entities/Memory/EntityFactories.cs +++ b/FoundationV3/Mobile/Detection/Entities/Memory/EntityFactories.cs @@ -24,11 +24,33 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities.Memory { + internal class MemoryAsciiStringFactory : BaseEntityFactory, DataSet> + { + /// + /// Creates a new instance of + /// + /// + /// The data set whose strings list the string is contained within + /// + /// + /// The offset to the start of the string within the string data + /// structure + /// + /// + /// Binary reader positioned at the start of the AsciiString + /// + /// A new instance of an + public override AsciiString Create(DataSet dataSet, int offset, Reader reader) + { + return new AsciiString(dataSet, offset, reader); + } + } + /// /// Factory class used to create the new instances of Node V3.1 object. /// Difference is in the length of the Node entity. /// - internal class NodeMemoryFactoryV31 : NodeFactory + internal class NodeMemoryFactoryV31 : NodeFactory { protected override Entities.Node Construct(DataSet dataSet, int offset, Reader reader) { @@ -44,7 +66,7 @@ protected override Entities.Node Construct(DataSet dataSet, int offset, Reader r /// /// The number of bytes used to store the node. /// - internal override int GetLength(Entities.Node entity) + public override int GetLength(Entities.Node entity) { return BaseLength + sizeof(int) + // Length of the ranked signatures count number @@ -58,7 +80,7 @@ internal override int GetLength(Entities.Node entity) /// Factory class used to create the new instances of Node V3.2 object. /// Difference is in the length of the Node entity. /// - internal class NodeMemoryFactoryV32 : NodeFactory + internal class NodeMemoryFactoryV32 : NodeFactory { protected override Entities.Node Construct(DataSet dataSet, int offset, Reader reader) { @@ -74,7 +96,7 @@ protected override Entities.Node Construct(DataSet dataSet, int offset, Reader r /// /// The number of bytes used to store the node. /// - internal override int GetLength(Entities.Node entity) + public override int GetLength(Entities.Node entity) { return BaseLength + sizeof(ushort) + // Length of the ranked signatures count number @@ -89,7 +111,7 @@ internal override int GetLength(Entities.Node entity) /// /// Creates Profile entities for use with memory data set. /// - internal class ProfileMemoryFactory : ProfileFactory + internal class ProfileMemoryFactory : ProfileFactory { protected override Entities.Profile Construct(DataSet dataSet, int offset, Reader reader) { diff --git a/FoundationV3/Mobile/Detection/Entities/Memory/MemoryBaseList.cs b/FoundationV3/Mobile/Detection/Entities/Memory/MemoryBaseList.cs index c71deda..d50557c 100644 --- a/FoundationV3/Mobile/Detection/Entities/Memory/MemoryBaseList.cs +++ b/FoundationV3/Mobile/Detection/Entities/Memory/MemoryBaseList.cs @@ -42,18 +42,19 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities.Memory /// /// Delegate methods are used to create new instances of items to add to /// the list in order to avoid creating many inherited list classes for - /// each type. + /// each item type. /// /// /// The data is held in the private readonly variable _listArray. /// - /// - /// Should not be referenced directly. - /// + /// Not intended to be used directly by 3rd parties. /// - /// The type of the list will contain + /// The type of item the list will contain. + /// + /// + /// The type of the shared data set the item is contained within. /// - public abstract class MemoryBaseList : IEnumerable + public abstract class MemoryBaseList : IEnumerable { #region Fields @@ -65,12 +66,12 @@ public abstract class MemoryBaseList : IEnumerable /// /// Method used to create a new instance of an item in the list. /// - internal readonly BaseEntityFactory EntityFactory; + internal readonly BaseEntityFactory EntityFactory; /// /// The dataset which contains the list. /// - protected internal readonly DataSet _dataSet; + protected internal readonly D _dataSet; /// /// Array of items contained in the list. @@ -99,14 +100,14 @@ public int Count /// /// Reader connected to the source data structure and positioned to start reading /// - internal abstract void Read(Reader reader); + public abstract void Read(Reader reader); #endregion #region Constructor /// - /// Constructs a new instance of . + /// Constructs a new instance of . /// The Read method needs to be called following construction to read /// all the entities which form the list before the list can be used. /// @@ -119,7 +120,7 @@ public int Count /// /// Used to create new instances of the entity. /// - internal MemoryBaseList(DataSet dataSet, Reader reader, BaseEntityFactory entityFactory) + internal MemoryBaseList(D dataSet, Reader reader, BaseEntityFactory entityFactory) { Header = new Header(reader); _array = new T[Header.Count]; diff --git a/FoundationV3/Mobile/Detection/Entities/Memory/MemoryFixedList.cs b/FoundationV3/Mobile/Detection/Entities/Memory/MemoryFixedList.cs index 800cc34..bb57ecb 100644 --- a/FoundationV3/Mobile/Detection/Entities/Memory/MemoryFixedList.cs +++ b/FoundationV3/Mobile/Detection/Entities/Memory/MemoryFixedList.cs @@ -19,11 +19,8 @@ * defined by the Mozilla Public License, v. 2.0. * ********************************************************************* */ -using System.IO; using FiftyOne.Foundation.Mobile.Detection.Factories; using FiftyOne.Foundation.Mobile.Detection.Readers; -using System.Collections.Generic; -using System; namespace FiftyOne.Foundation.Mobile.Detection.Entities.Memory { @@ -49,18 +46,19 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities.Memory /// /// The class supports source stream that doesn't support seeking. /// - /// - /// Should not be referenced directly. - /// + /// Not intended to be used directly by 3rd parties. /// - /// The type of the list will contain + /// The type of item the list will contain. + /// + /// + /// The type of the shared data set the item is contained within. /// - public class MemoryFixedList : MemoryBaseList, IReadonlyList where T : BaseEntity + public class MemoryFixedList : MemoryBaseList, IReadonlyList { #region Constructor /// - /// Constructs a new instance of . + /// Constructs a new instance of . /// /// /// The being created. @@ -72,7 +70,7 @@ public class MemoryFixedList : MemoryBaseList, IReadonlyList where T : /// /// Used to create new instances of the entity. /// - internal MemoryFixedList(DataSet dataSet, Reader reader, BaseEntityFactory entityFactory) + public MemoryFixedList(D dataSet, Reader reader, BaseEntityFactory entityFactory) : base(dataSet, reader, entityFactory) { } @@ -88,7 +86,7 @@ internal MemoryFixedList(DataSet dataSet, Reader reader, BaseEntityFactory en /// Reader connected to the source data structure and positioned to /// start reading. /// - internal override void Read(Reader reader) + public override void Read(Reader reader) { for (int index = 0; index < Header.Count; index++) { diff --git a/FoundationV3/Mobile/Detection/Entities/Memory/MemoryVariableList.cs b/FoundationV3/Mobile/Detection/Entities/Memory/MemoryVariableList.cs index b92907b..4ae9306 100644 --- a/FoundationV3/Mobile/Detection/Entities/Memory/MemoryVariableList.cs +++ b/FoundationV3/Mobile/Detection/Entities/Memory/MemoryVariableList.cs @@ -19,10 +19,9 @@ * defined by the Mozilla Public License, v. 2.0. * ********************************************************************* */ -using System.IO; using FiftyOne.Foundation.Mobile.Detection.Factories; using FiftyOne.Foundation.Mobile.Detection.Readers; -using System.Collections.Generic; +using System; namespace FiftyOne.Foundation.Mobile.Detection.Entities.Memory { @@ -50,13 +49,15 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities.Memory /// /// The class supports source stream that do not support seeking. /// - /// - /// Should not be referenced directly. - /// + /// Not intended to be used directly by 3rd parties. /// - /// The type of the list will contain. + /// The type of item the list will contain. + /// + /// + /// The type of the shared data set the item is contained within. /// - public class MemoryVariableList : MemoryBaseList, IReadonlyList where T : BaseEntity + public class MemoryVariableList : MemoryBaseList, IReadonlyList + where T : IComparable { #region Classes @@ -104,7 +105,7 @@ protected override int CompareTo(T item, int offset) #region Constructor /// - /// Constructs a new instance of . + /// Constructs a new instance of . /// /// /// The being created. @@ -116,10 +117,10 @@ protected override int CompareTo(T item, int offset) /// /// Used to create new instances of the entity. /// - internal MemoryVariableList( - DataSet dataSet, + public MemoryVariableList( + D dataSet, Reader reader, - BaseEntityFactory entityFactory) + BaseEntityFactory entityFactory) : base(dataSet, reader, entityFactory) { } @@ -135,7 +136,7 @@ protected override int CompareTo(T item, int offset) /// Reader connected to the source data structure and positioned to /// start reading. /// - internal override void Read(Reader reader) + public override void Read(Reader reader) { var offset = 0; var startPos = (int)reader.BaseStream.Position; @@ -173,7 +174,7 @@ internal override void Read(Reader reader) var index = _search.BinarySearch(offset); if (index >= 0) return _array[index]; - return null; + return default(T); } } diff --git a/FoundationV3/Mobile/Detection/Entities/Memory/NodeV31.cs b/FoundationV3/Mobile/Detection/Entities/Memory/NodeV31.cs index 0fa7e50..50e7ef0 100644 --- a/FoundationV3/Mobile/Detection/Entities/Memory/NodeV31.cs +++ b/FoundationV3/Mobile/Detection/Entities/Memory/NodeV31.cs @@ -64,7 +64,7 @@ internal class NodeV31 : Node _numericChildren = ReadNodeNumericIndexes(dataSet, reader, NumericChildrenCount); _rankedSignatureIndexes = - BaseEntity.ReadIntegerArray(reader, RankedSignatureCount); + Utils.ReadIntegerArray(reader, RankedSignatureCount); } #endregion diff --git a/FoundationV3/Mobile/Detection/Entities/Memory/Profile.cs b/FoundationV3/Mobile/Detection/Entities/Memory/Profile.cs index 7df0940..ce37064 100644 --- a/FoundationV3/Mobile/Detection/Entities/Memory/Profile.cs +++ b/FoundationV3/Mobile/Detection/Entities/Memory/Profile.cs @@ -55,8 +55,8 @@ public class Profile : Entities.Profile { var valueIndexesCount = reader.ReadInt32(); var signatureIndexesCount = reader.ReadInt32(); - _valueIndexes = BaseEntity.ReadIntegerArray(reader, valueIndexesCount); - _signatureIndexes = BaseEntity.ReadIntegerArray(reader, signatureIndexesCount); + _valueIndexes = Utils.ReadIntegerArray(reader, valueIndexesCount); + _signatureIndexes = Utils.ReadIntegerArray(reader, signatureIndexesCount); } #endregion diff --git a/FoundationV3/Mobile/Detection/Entities/Memory/PropertiesList.cs b/FoundationV3/Mobile/Detection/Entities/Memory/PropertiesList.cs index 86f9fc7..8bbcbb3 100644 --- a/FoundationV3/Mobile/Detection/Entities/Memory/PropertiesList.cs +++ b/FoundationV3/Mobile/Detection/Entities/Memory/PropertiesList.cs @@ -32,7 +32,7 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities.Memory /// A list of properties in memory as a fixed list. Contains an accessor /// which can be used to retrieve entries by property name. /// - public class PropertiesList : MemoryFixedList + public class PropertiesList : MemoryFixedList { #region Constructors @@ -49,7 +49,7 @@ public class PropertiesList : MemoryFixedList /// /// Used to create new instances of the entity. /// - internal PropertiesList(DataSet dataSet, Reader reader, BaseEntityFactory entityFactory) + internal PropertiesList(DataSet dataSet, Reader reader, BaseEntityFactory entityFactory) : base(dataSet, reader, entityFactory) { } diff --git a/FoundationV3/Mobile/Detection/Entities/Node.cs b/FoundationV3/Mobile/Detection/Entities/Node.cs index 527dee5..5b713ca 100644 --- a/FoundationV3/Mobile/Detection/Entities/Node.cs +++ b/FoundationV3/Mobile/Detection/Entities/Node.cs @@ -53,7 +53,7 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities /// /// For more information see https://51degrees.com/Support/Documentation/Net /// - internal abstract class Node : BaseEntity, IComparable + internal abstract class Node : BaseEntity, IComparable { #region Classes @@ -401,7 +401,7 @@ internal int GetCurrentPositionAsNumeric(MatchState state) // If numeric characters were found then return the number. if (i < Position) - return GetNumber( + return Utils.GetNumber( state.TargetUserAgentArray, i + 1, Position - i); @@ -535,7 +535,7 @@ private Node GetNextNode(MatchState state) private bool IsNumeric(byte[] array, int startIndex, int length) { for (int i = startIndex; i < startIndex + length; i++) - if (GetIsNumeric(array[i]) == false) + if (Utils.GetIsNumeric(array[i]) == false) return false; return true; } diff --git a/FoundationV3/Mobile/Detection/Entities/NodeIndexBase.cs b/FoundationV3/Mobile/Detection/Entities/NodeIndexBase.cs index 0bd1a6e..a532f74 100644 --- a/FoundationV3/Mobile/Detection/Entities/NodeIndexBase.cs +++ b/FoundationV3/Mobile/Detection/Entities/NodeIndexBase.cs @@ -24,7 +24,7 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities /// /// Base class used by all node indexes containing common functionality. /// - internal abstract class NodeIndexBase : BaseEntity + internal abstract class NodeIndexBase : BaseEntity { #region Fields @@ -54,7 +54,7 @@ internal Node Node if (_node != null) return _node; - if (DataSet.Nodes is Memory.MemoryBaseList) + if (DataSet.Nodes is Memory.MemoryBaseList) { if (_node == null) { diff --git a/FoundationV3/Mobile/Detection/Entities/Profile.cs b/FoundationV3/Mobile/Detection/Entities/Profile.cs index 7fa74b5..811b9e2 100644 --- a/FoundationV3/Mobile/Detection/Entities/Profile.cs +++ b/FoundationV3/Mobile/Detection/Entities/Profile.cs @@ -57,7 +57,7 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities /// provide better detection results, especially for less common devices. /// For more information see: https://51degrees.com/compare-data-options /// - public abstract class Profile : BaseEntity, IComparable, IEquatable + public abstract class Profile : BaseEntity, IComparable, IEquatable { #region Fields @@ -151,17 +151,21 @@ internal DateTime ReleaseDate get { Values values = null; - if (PropertyIndexToValues.TryGetValue(property.Index, out values) == false) + + // A read / write upgradable guard could be used in the future + // should the performance of GetPropertyValueIndexes prove too + // slow in the future. The use of a lock on the dictionary + // ensures that this implementation is thread safe. + lock (PropertyIndexToValues) { - lock(this) + if (PropertyIndexToValues.TryGetValue( + property.Index, + out values) == false) { - if (PropertyIndexToValues.TryGetValue(property.Index, out values) == false) - { - values = new Entities.Values( - property, - GetPropertyValueIndexes(property)); - PropertyIndexToValues.Add(property.Index, values); - } + values = new Entities.Values( + property, + GetPropertyValueIndexes(property)); + PropertyIndexToValues.Add(property.Index, values); } } return values; @@ -183,7 +187,8 @@ internal DateTime ReleaseDate { if (_propertyIndexToValues == null) { - _propertyIndexToValues = new Dictionary(); + _propertyIndexToValues = + new Dictionary(); } } } @@ -193,7 +198,7 @@ internal DateTime ReleaseDate private IDictionary _propertyIndexToValues; /// - /// A dictionary relating the name of a property to the values returned + /// A dictionary relating the name of a property to the values returned /// by the profile. Used to speed up subsequent data processing. /// private IDictionary PropertyNameToValues @@ -206,7 +211,8 @@ internal DateTime ReleaseDate { if (_propertyNameToValues == null) { - _propertyNameToValues = new Dictionary(); + _propertyNameToValues = + new Dictionary(); } } } @@ -227,7 +233,7 @@ internal DateTime ReleaseDate /// /// /// The type is used to return values so that - /// helper methods like ToBool can be used to convert the response to + /// helper methods like ToBool can be used to convert the response to /// a boolean. /// public Values this[string propertyName] @@ -235,19 +241,21 @@ internal DateTime ReleaseDate get { Values values = null; - if (PropertyNameToValues.TryGetValue(propertyName, out values) == false) + + // A read / write upgradable guard could be used in the future + // should the performance of this[property] prove too slow in + // the future. The use of a lock on the dictionary ensures that + // this implementation is thread safe. + lock (PropertyNameToValues) { - lock (this) + if (PropertyNameToValues.TryGetValue(propertyName, out values) == false) { - if (PropertyNameToValues.TryGetValue(propertyName, out values) == false) + var property = DataSet.Properties[propertyName]; + if (property != null) { - var property = DataSet.Properties[propertyName]; - if (property != null) - { - values = this[property]; - } - PropertyNameToValues.Add(propertyName, values); + values = this[property]; } + PropertyNameToValues.Add(propertyName, values); } } return values; diff --git a/FoundationV3/Mobile/Detection/Entities/ProfileOffset.cs b/FoundationV3/Mobile/Detection/Entities/ProfileOffset.cs index 358c9d7..3c6f47d 100644 --- a/FoundationV3/Mobile/Detection/Entities/ProfileOffset.cs +++ b/FoundationV3/Mobile/Detection/Entities/ProfileOffset.cs @@ -26,7 +26,7 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities /// /// Maps a profile id to its position in the data file. /// - public class ProfileOffset : BaseEntity + public class ProfileOffset : BaseEntity { #region Properties diff --git a/FoundationV3/Mobile/Detection/Entities/Property.cs b/FoundationV3/Mobile/Detection/Entities/Property.cs index dc30751..bf4aed0 100644 --- a/FoundationV3/Mobile/Detection/Entities/Property.cs +++ b/FoundationV3/Mobile/Detection/Entities/Property.cs @@ -66,7 +66,7 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities /// For more information see /// https://51degrees.com/Support/Documentation/Net /// - public class Property : BaseEntity, IComparable, IEquatable + public class Property : BaseEntity, IComparable, IEquatable { #region Constants diff --git a/FoundationV3/Mobile/Detection/Entities/Signature.cs b/FoundationV3/Mobile/Detection/Entities/Signature.cs index 550ea64..c67666e 100644 --- a/FoundationV3/Mobile/Detection/Entities/Signature.cs +++ b/FoundationV3/Mobile/Detection/Entities/Signature.cs @@ -47,7 +47,7 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities /// For more information about signature see /// https://51degrees.com/Support/Documentation/Net /// - public abstract class Signature : BaseEntity, IComparable + public abstract class Signature : BaseEntity, IComparable { #region Fields diff --git a/FoundationV3/Mobile/Detection/Entities/Stream/BaseList.cs b/FoundationV3/Mobile/Detection/Entities/Stream/BaseList.cs index 38c6edb..5455fc0 100644 --- a/FoundationV3/Mobile/Detection/Entities/Stream/BaseList.cs +++ b/FoundationV3/Mobile/Detection/Entities/Stream/BaseList.cs @@ -39,15 +39,19 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities.Stream /// /// Delegate methods are used to create new instances of items to add to /// the list in order to avoid creating many inherited list classes for - /// each type. + /// each item type. /// /// /// Should not be referenced directly. /// /// - /// The type of the list will contain. + /// The type of item the list will contain. /// - public abstract class BaseList where T : BaseEntity + /// + /// The type of the shared data set the item is contained within. + /// + public abstract class BaseList + where D : IStreamDataSet { #region Fields @@ -59,12 +63,12 @@ public abstract class BaseList where T : BaseEntity /// /// Factory used to create new instances of the entity. /// - internal readonly BaseEntityFactory EntityFactory; + internal readonly BaseEntityFactory EntityFactory; /// /// The dataset which contains the list. /// - protected internal readonly DataSet _dataSet; + protected internal readonly D _dataSet; #endregion @@ -105,7 +109,7 @@ public int Count #region Constructor /// - /// Constructs a new instance of ready to + /// Constructs a new instance of ready to /// read entities from the source. /// /// @@ -118,9 +122,9 @@ public int Count /// Used to create new instances of the entity. /// internal BaseList( - DataSet dataSet, + D dataSet, Reader reader, - BaseEntityFactory entityFactory) + BaseEntityFactory entityFactory) { _dataSet = dataSet; Header = new Header(reader); diff --git a/FoundationV3/Mobile/Detection/Entities/Stream/Cache.cs b/FoundationV3/Mobile/Detection/Entities/Stream/Cache.cs index d8dbd3b..e7d172c 100644 --- a/FoundationV3/Mobile/Detection/Entities/Stream/Cache.cs +++ b/FoundationV3/Mobile/Detection/Entities/Stream/Cache.cs @@ -27,13 +27,13 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities.Stream { /// - /// Cache class used by and - /// to cache frequently accessed items. + /// Cache class used by and + /// to cache frequently accessed items. /// /// - /// The type of the cache will contain. + /// The type of item the cache will contain. /// - internal class Cache : Cache where T : BaseEntity + internal class Cache : Cache { /// /// Constructs a new instance of for diff --git a/FoundationV3/Mobile/Detection/Entities/Stream/CacheList.cs b/FoundationV3/Mobile/Detection/Entities/Stream/CacheList.cs index 66f15d8..7d58bd9 100644 --- a/FoundationV3/Mobile/Detection/Entities/Stream/CacheList.cs +++ b/FoundationV3/Mobile/Detection/Entities/Stream/CacheList.cs @@ -44,15 +44,19 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities.Stream /// /// Delegate methods are used to create new instances of items to add to /// the list in order to avoid creating many inherited list classes for - /// each type. + /// each item type. /// /// /// Should not be referenced directly. /// /// - /// The type of the list will contain. + /// The type of items the list will contain. /// - public abstract class CacheList : BaseList, IDisposable, ICacheList, ICacheLoader where T : BaseEntity + /// + /// The type of the shared data set the item is contained within. + /// + public abstract class CacheList : BaseList, IDisposable, ICacheList, ICacheLoader + where D : IStreamDataSet { #region Fields @@ -114,7 +118,7 @@ long ICacheList.CacheRequests #region Constructor /// - /// Constructs a new instance of ready to + /// Constructs a new instance of ready to /// read entities from the source. /// /// @@ -130,9 +134,9 @@ long ICacheList.CacheRequests /// Number of items in list to have capacity to cache. /// internal CacheList( - DataSet dataSet, + D dataSet, Reader reader, - BaseEntityFactory entityFactory, + BaseEntityFactory entityFactory, int cacheSize) : base (dataSet, reader, entityFactory) { _cache = new Cache(cacheSize, this); diff --git a/FoundationV3/Mobile/Detection/Entities/Stream/DataSet.cs b/FoundationV3/Mobile/Detection/Entities/Stream/DataSet.cs index f95cab7..bfb62c4 100644 --- a/FoundationV3/Mobile/Detection/Entities/Stream/DataSet.cs +++ b/FoundationV3/Mobile/Detection/Entities/Stream/DataSet.cs @@ -39,7 +39,7 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities.Stream /// until the dataset is closed. Class provides extra methods to check how /// many readers were created and how many are currently free to use. /// - public class DataSet : Entities.DataSet + public class DataSet : Entities.DataSet, IStreamDataSet { #region Fields @@ -51,7 +51,7 @@ public class DataSet : Entities.DataSet /// /// Pool of readers connected the underlying data file. /// - internal readonly Pool Pool; + public Pool Pool { get; internal set; } #endregion diff --git a/FoundationV3/Mobile/Detection/Entities/Stream/EntityFactories.cs b/FoundationV3/Mobile/Detection/Entities/Stream/EntityFactories.cs index bc78721..8bcd1ac 100644 --- a/FoundationV3/Mobile/Detection/Entities/Stream/EntityFactories.cs +++ b/FoundationV3/Mobile/Detection/Entities/Stream/EntityFactories.cs @@ -24,10 +24,32 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities.Stream { + internal class StreamAsciiStringFactory : BaseEntityFactory, DataSet> + { + /// + /// Creates a new instance of + /// + /// + /// The data set whose strings list the string is contained within + /// + /// + /// The offset to the start of the string within the string data + /// structure + /// + /// + /// Binary reader positioned at the start of the AsciiString + /// + /// A new instance of an + public override AsciiString Create(DataSet dataSet, int offset, Reader reader) + { + return new AsciiString(dataSet, offset, reader); + } + } + /// /// Factory used to create stream entities. /// - internal abstract class NodeStreamFactory : NodeFactory + internal abstract class NodeStreamFactory : NodeFactory { /// /// Pool for the corresponding data set used to get readers. @@ -80,9 +102,9 @@ internal NodeStreamFactoryV31(Pool pool) : base(pool) /// /// A new entity from the data set. /// - protected override Entities.Node Construct(Entities.DataSet dataSet, int offset, Reader reader) + protected override Entities.Node Construct(DataSet dataSet, int offset, Reader reader) { - return new Entities.Stream.NodeV31((DataSet)dataSet, offset, reader); + return new Entities.Stream.NodeV31(dataSet, offset, reader); } } @@ -120,16 +142,16 @@ internal NodeStreamFactoryV32(Pool pool) /// /// A new entity from the data set. /// - protected override Entities.Node Construct(Entities.DataSet dataSet, int offset, Reader reader) + protected override Entities.Node Construct(DataSet dataSet, int offset, Reader reader) { - return new Entities.Stream.NodeV32((DataSet)dataSet, offset, reader); + return new Entities.Stream.NodeV32(dataSet, offset, reader); } } /// /// Factory used to create stream entities. /// - internal class ProfileStreamFactory : ProfileFactory + internal class ProfileStreamFactory : ProfileFactory { /// /// Pool for the corresponding data set used to get readers. @@ -165,9 +187,9 @@ internal ProfileStreamFactory(Pool pool) /// /// A new entity from the data set. /// - protected override Entities.Profile Construct(Entities.DataSet dataSet, int offset, Reader reader) + protected override Entities.Profile Construct(DataSet dataSet, int offset, Reader reader) { - return new Entities.Stream.Profile((DataSet)dataSet, offset, reader); + return new Entities.Stream.Profile(dataSet, offset, reader); } } } diff --git a/FoundationV3/Mobile/Detection/Entities/Stream/FixedCacheList.cs b/FoundationV3/Mobile/Detection/Entities/Stream/FixedCacheList.cs index 4fef39a..3e1e534 100644 --- a/FoundationV3/Mobile/Detection/Entities/Stream/FixedCacheList.cs +++ b/FoundationV3/Mobile/Detection/Entities/Stream/FixedCacheList.cs @@ -53,13 +53,15 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities.Stream /// Data sources which don't support seeking can not be used. Specifically /// compressed data structures can not be used with these lists. /// - /// - /// Should not be referenced directly. - /// + /// Not intended to be used directly by 3rd parties. /// - /// The type of the list will contain. + /// The type of items the list will contain. + /// + /// + /// The type of the shared data set the item is contained within. /// - public class FixedCacheList : FixedList, ICacheList, ICacheLoader where T : BaseEntity + public class FixedCacheList : FixedList, ICacheList, ICacheLoader + where D : IStreamDataSet { #region Fields @@ -121,7 +123,7 @@ long ICacheList.CacheRequests #region Constructor /// - /// Constructs a new instance of . + /// Constructs a new instance of . /// /// /// The being created. @@ -136,10 +138,10 @@ long ICacheList.CacheRequests /// /// Number of items in list to have capacity to cache. /// - internal FixedCacheList( - DataSet dataSet, + public FixedCacheList( + D dataSet, Reader reader, - BaseEntityFactory entityFactory, + BaseEntityFactory entityFactory, int cacheSize) : base(dataSet, reader, entityFactory) { diff --git a/FoundationV3/Mobile/Detection/Entities/Stream/FixedList.cs b/FoundationV3/Mobile/Detection/Entities/Stream/FixedList.cs index 6483c22..a514fab 100644 --- a/FoundationV3/Mobile/Detection/Entities/Stream/FixedList.cs +++ b/FoundationV3/Mobile/Detection/Entities/Stream/FixedList.cs @@ -36,20 +36,24 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities.Stream /// /// Delegate methods are used to create new instances of items to add to /// the list in order to avoid creating many inherited list classes for - /// each type. + /// each item type. /// /// /// Should not be referenced directly. /// /// - /// The type of the list will contain. + /// The type of items the list will contain. /// - public class FixedList : BaseList, IReadonlyList where T : BaseEntity + /// + /// The type of the shared data set the item is contained within. + /// + public class FixedList : BaseList, IReadonlyList + where D : IStreamDataSet { #region Constructor /// - /// Constructs a new instance of ready to + /// Constructs a new instance of ready to /// read entities from the source. /// /// @@ -62,9 +66,9 @@ public class FixedList : BaseList, IReadonlyList where T : BaseEntity /// Used to create new instances of the entity. /// internal FixedList( - DataSet dataSet, + D dataSet, Reader reader, - BaseEntityFactory entityFactory) + BaseEntityFactory entityFactory) : base(dataSet, reader, entityFactory) { } diff --git a/FoundationV3/Mobile/Detection/Entities/Stream/IStreamDataSet.cs b/FoundationV3/Mobile/Detection/Entities/Stream/IStreamDataSet.cs new file mode 100644 index 0000000..9a5c712 --- /dev/null +++ b/FoundationV3/Mobile/Detection/Entities/Stream/IStreamDataSet.cs @@ -0,0 +1,36 @@ +/* ********************************************************************* + * This Source Code Form is copyright of 51Degrees Mobile Experts Limited. + * Copyright © 2015 51Degrees Mobile Experts Limited, 5 Charlotte Close, + * Caversham, Reading, Berkshire, United Kingdom RG4 7BY + * + * This Source Code Form is the subject of the following patent + * applications, owned by 51Degrees Mobile Experts Limited of 5 Charlotte + * Close, Caversham, Reading, Berkshire, United Kingdom RG4 7BY: + * European Patent Application No. 13192291.6; and + * United States Patent Application Nos. 14/085,223 and 14/085,301. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. + * + * If a copy of the MPL was not distributed with this file, You can obtain + * one at http://mozilla.org/MPL/2.0/. + * + * This Source Code Form is “Incompatible With Secondary Licenses”, as + * defined by the Mozilla Public License, v. 2.0. + * ********************************************************************* */ + +namespace FiftyOne.Foundation.Mobile.Detection.Entities.Stream +{ + /// + /// A stream data set will have a pool of sources that can be read from. + /// This interface defines how the pool is exposed across different stream + /// data set implementation. + /// + public interface IStreamDataSet + { + /// + /// Pool of readers associated with the data set. + /// + Pool Pool { get; } + } +} diff --git a/FoundationV3/Mobile/Detection/Entities/Stream/NodeV31.cs b/FoundationV3/Mobile/Detection/Entities/Stream/NodeV31.cs index 5c9f73b..de6dc61 100644 --- a/FoundationV3/Mobile/Detection/Entities/Stream/NodeV31.cs +++ b/FoundationV3/Mobile/Detection/Entities/Stream/NodeV31.cs @@ -89,7 +89,7 @@ internal override IList RankedSignatureIndexes reader.BaseStream.Position = _position + ((sizeof(short) + sizeof(int)) * NumericChildrenCount); _rankedSignatureIndexes = - ReadIntegerArray(reader, RankedSignatureCount); + Utils.ReadIntegerArray(reader, RankedSignatureCount); } finally { diff --git a/FoundationV3/Mobile/Detection/Entities/Stream/Pool.cs b/FoundationV3/Mobile/Detection/Entities/Stream/Pool.cs index 2aa4e1d..496ab5b 100644 --- a/FoundationV3/Mobile/Detection/Entities/Stream/Pool.cs +++ b/FoundationV3/Mobile/Detection/Entities/Stream/Pool.cs @@ -33,14 +33,15 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities.Stream /// recycled across threads and requests. /// /// - /// Used by the to provide multiple readers for + /// Used by the to provide multiple readers for /// the list. /// /// /// The must be disposed of to ensure the readers /// in the pool are closed. /// - internal class Pool + /// Not intended to be used directly by 3rd parties. + public class Pool { #region Fields @@ -87,7 +88,7 @@ internal int ReadersQueued /// /// The data source for the list. /// - internal Pool(SourceBase source) + public Pool(SourceBase source) { Source = source; } @@ -104,7 +105,7 @@ internal Pool(SourceBase source) /// /// Reader open and ready to read from the temp file. /// - internal Reader GetReader() + public Reader GetReader() { lock(_readers) { @@ -124,7 +125,7 @@ internal Reader GetReader() /// /// Reader open and ready to read from the temp file. /// - internal void Release(Reader reader) + public void Release(Reader reader) { lock (_readers) { diff --git a/FoundationV3/Mobile/Detection/Entities/Stream/Profile.cs b/FoundationV3/Mobile/Detection/Entities/Stream/Profile.cs index 7c79fe9..d7223db 100644 --- a/FoundationV3/Mobile/Detection/Entities/Stream/Profile.cs +++ b/FoundationV3/Mobile/Detection/Entities/Stream/Profile.cs @@ -107,7 +107,7 @@ protected internal override int[] ValueIndexes reader.BaseStream.Position = _position; _valueIndexes = - BaseEntity.ReadIntegerArray(reader, _valueIndexesCount); + Utils.ReadIntegerArray(reader, _valueIndexesCount); } finally { @@ -140,7 +140,7 @@ protected internal override int[] SignatureIndexes reader.BaseStream.Position = _position + (_valueIndexesCount * sizeof(int)); _signatureIndexes = - BaseEntity.ReadIntegerArray(reader, _signatureIndexesCount); + Utils.ReadIntegerArray(reader, _signatureIndexesCount); } finally { diff --git a/FoundationV3/Mobile/Detection/Entities/Stream/VariableList.cs b/FoundationV3/Mobile/Detection/Entities/Stream/VariableList.cs index ff475c3..472d262 100644 --- a/FoundationV3/Mobile/Detection/Entities/Stream/VariableList.cs +++ b/FoundationV3/Mobile/Detection/Entities/Stream/VariableList.cs @@ -19,9 +19,7 @@ * defined by the Mozilla Public License, v. 2.0. * ********************************************************************* */ -using System; using System.Collections.Generic; -using System.IO; using FiftyOne.Foundation.Mobile.Detection.Factories; using FiftyOne.Foundation.Mobile.Detection.Readers; @@ -54,18 +52,20 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities.Stream /// Data sources which don't support seeking can not be used. Specifically /// compressed data structures can not be used with these lists. /// - /// - /// Should not be referenced directly. - /// + /// Not intended to be used directly by 3rd parties. /// - /// The type of the list will contain. + /// The type of item the list will contain. + /// + /// + /// The type of the shared data set the item is contained within. /// - public class VariableList : CacheList, IReadonlyList where T : BaseEntity + public class VariableList : CacheList, IReadonlyList + where D : IStreamDataSet { #region Constructor /// - /// Constructs a new instance of . + /// Constructs a new instance of . /// /// /// The being created. @@ -80,10 +80,10 @@ public class VariableList : CacheList, IReadonlyList where T : BaseEnti /// /// Number of items in list to have capacity to cache. /// - internal VariableList( - DataSet dataSet, + public VariableList( + D dataSet, Reader reader, - BaseEntityFactory entityFactory, + BaseEntityFactory entityFactory, int cacheSize) : base(dataSet, reader, entityFactory, cacheSize) { diff --git a/FoundationV3/Mobile/Detection/Entities/Utf8String.cs b/FoundationV3/Mobile/Detection/Entities/Utf8String.cs new file mode 100644 index 0000000..75e9e8b --- /dev/null +++ b/FoundationV3/Mobile/Detection/Entities/Utf8String.cs @@ -0,0 +1,108 @@ +/* ********************************************************************* + * This Source Code Form is copyright of 51Degrees Mobile Experts Limited. + * Copyright © 2015 51Degrees Mobile Experts Limited, 5 Charlotte Close, + * Caversham, Reading, Berkshire, United Kingdom RG4 7BY + * + * This Source Code Form is the subject of the following patent + * applications, owned by 51Degrees Mobile Experts Limited of 5 Charlotte + * Close, Caversham, Reading, Berkshire, United Kingdom RG4 7BY: + * European Patent Application No. 13192291.6; and + * United States Patent Application Nos. 14/085,223 and 14/085,301. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. + * + * If a copy of the MPL was not distributed with this file, You can obtain + * one at http://mozilla.org/MPL/2.0/. + * + * This Source Code Form is “Incompatible With Secondary Licenses”, as + * defined by the Mozilla Public License, v. 2.0. + * ********************************************************************* */ + +using System.Text; +using System.IO; + +namespace FiftyOne.Foundation.Mobile.Detection.Entities +{ + /// + /// UTF8 format strings are the only ones used in the data set. Many + /// native string formats use Unicode format using 2 bytes for every + /// character. This is inefficient when most characters don't need + /// 2 bytes. The class wraps a byte array of + /// UTF8 characters and exposes them as a native string type when + /// required. + /// + /// + /// For more information see + /// https://51degrees.com/Support/Documentation/Net + /// + /// + /// The type of the shared data set the Utf8String relates to. + /// + /// Not intended to be used directly by 3rd parties. + public class Utf8String : BaseEntity + { + #region Fields + + /// + /// The value of the string in UTF8 bytes. + /// + public readonly byte[] Value; + + #endregion + + #region Constructor + + /// + /// Constructs a new instance of . + /// + /// Not intended to be used directly by 3rd parties. + /// + /// The data set whose strings list the string is contained within. + /// + /// + /// The offset to the start of the string within the string data + /// structure. + /// + /// + /// Binary reader positioned at the start of the AsciiString. + /// + public Utf8String(T dataSet, int offset, BinaryReader reader) + : base(dataSet, offset) + { + // Read the length of the array minus 1 to remove the + // last null character which isn't used by .NET. + Value = reader.ReadBytes(reader.ReadInt16() - 1); + + // Read and discard the null value to ensure the file + // position is correct for the next read. + reader.ReadByte(); + } + + #endregion + + #region Methods + + /// + /// .NET string representation of the UTF8 string. + /// + /// + public override string ToString() + { + if (_stringValue == null) + { + lock (this) + { + if (_stringValue == null) + { + _stringValue = Encoding.UTF8.GetString(Value); + } + } + } + return _stringValue; + } + private string _stringValue = null; + + #endregion + } +} diff --git a/FoundationV3/Mobile/Detection/Entities/Utils.cs b/FoundationV3/Mobile/Detection/Entities/Utils.cs new file mode 100644 index 0000000..9c18278 --- /dev/null +++ b/FoundationV3/Mobile/Detection/Entities/Utils.cs @@ -0,0 +1,105 @@ +/* ********************************************************************* + * This Source Code Form is copyright of 51Degrees Mobile Experts Limited. + * Copyright © 2015 51Degrees Mobile Experts Limited, 5 Charlotte Close, + * Caversham, Reading, Berkshire, United Kingdom RG4 7BY + * + * This Source Code Form is the subject of the following patent + * applications, owned by 51Degrees Mobile Experts Limited of 5 Charlotte + * Close, Caversham, Reading, Berkshire, United Kingdom RG4 7BY: + * European Patent Application No. 13192291.6; and + * United States Patent Application Nos. 14/085,223 and 14/085,301. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. + * + * If a copy of the MPL was not distributed with this file, You can obtain + * one at http://mozilla.org/MPL/2.0/. + * + * This Source Code Form is “Incompatible With Secondary Licenses”, as + * defined by the Mozilla Public License, v. 2.0. + * ********************************************************************* */ + +using System.Collections.Generic; +using System.IO; + +namespace FiftyOne.Foundation.Mobile.Detection.Entities +{ + internal static class Utils + { + #region Constants + + /// + /// List if powers used to determine numeric differences. + /// + private static readonly int[] Powers = new[] { 1, 10, 100, 1000, 10000 }; + + #endregion + + #region Static Methods + + /// + /// An enumerable that can be used to read through the entries. + /// + /// Reader set to the position at the start of the list + /// The number of integers to read to form the array + /// Iterator to read each integer entry. + internal static IEnumerable GetIntegerEnumerator(BinaryReader reader, int count) + { + for (int i = 0; i < count; i++) + { + yield return reader.ReadInt32(); + } + } + + /// + /// Reads an integer array where the first integer is the number of + /// following integers. + /// + /// Reader set to the position at the start of the list + /// The number of integers to read to form the array + /// An array of integers + internal static int[] ReadIntegerArray(BinaryReader reader, int count) + { + var array = new int[count]; + for (int i = 0; i < array.Length; i++) + array[i] = reader.ReadInt32(); + return array; + } + + /// + /// Returns an integer representation of the characters between start and end. + /// Assumes that all the characters are numeric characters. + /// + /// + /// Array of characters with numeric characters present between start and end + /// + /// + /// The first character to use to convert to a number + /// + /// + /// The number of characters to use in the conversion + /// + /// + internal static int GetNumber(byte[] array, int start, int length) + { + int value = 0; + for (int i = start + length - 1, p = 0; i >= start && p < Powers.Length; i--, p++) + { + value += Powers[p] * ((byte)array[i] - (byte)'0'); + } + return value; + } + + /// + /// Determines if the value is an ASCII numeric value. + /// + /// Byte value to be checked + /// True if the value is an ASCII numeric character + internal static bool GetIsNumeric(byte value) + { + return (value >= (byte)'0' && value <= (byte)'9'); + } + + #endregion + } +} diff --git a/FoundationV3/Mobile/Detection/Entities/Value.cs b/FoundationV3/Mobile/Detection/Entities/Value.cs index db114a6..7ea6bed 100644 --- a/FoundationV3/Mobile/Detection/Entities/Value.cs +++ b/FoundationV3/Mobile/Detection/Entities/Value.cs @@ -46,7 +46,7 @@ namespace FiftyOne.Foundation.Mobile.Detection.Entities /// For more information see /// https://51degrees.com/Support/Documentation/Net /// - public class Value : BaseEntity, + public class Value : BaseEntity, IComparable, IComparable, IEquatable, IEquatable { #region Static Fields diff --git a/FoundationV3/Mobile/Detection/Factories/EntityFactories.cs b/FoundationV3/Mobile/Detection/Factories/EntityFactories.cs index 4408199..09a240e 100644 --- a/FoundationV3/Mobile/Detection/Factories/EntityFactories.cs +++ b/FoundationV3/Mobile/Detection/Factories/EntityFactories.cs @@ -26,11 +26,23 @@ namespace FiftyOne.Foundation.Mobile.Detection.Factories { - internal abstract class BaseEntityFactory + /// + /// Used to create new entities. Required because .NET does not support + /// generic with constructors which take parameters. + /// + /// + /// Type of the entity that the factory creates. + /// + /// + /// Type of the data set the entity is associated with. + /// + /// Not intended to be used directly by 3rd parties. + public abstract class BaseEntityFactory { /// - /// Creates a new instance of + /// Creates a new instance of /// + /// Not intended to be used directly by 3rd parties. /// /// The data set whose entity list the index or offset is contained /// within @@ -43,7 +55,7 @@ internal abstract class BaseEntityFactory /// Binary reader positioned at the start of the entity /// /// A new instance of the entity - internal abstract T Create(DataSet dataSet, int index, Reader reader); + public abstract T Create(D dataSet, int index, Reader reader); /// /// Returns the length of the entity as stored in the data structure. @@ -52,9 +64,10 @@ internal abstract class BaseEntityFactory /// The method is implement on entities which are part of variable /// length lists. /// + /// Not intended to be used directly by 3rd parties. /// The Entity the length is required for /// The length of the entity in bytes - internal virtual int GetLength(T entity) + public virtual int GetLength(T entity) { throw new NotImplementedException(); } @@ -67,14 +80,15 @@ internal virtual int GetLength(T entity) /// The method is implement on entities which are part of fixed /// length lists. /// + /// Not intended to be used directly by 3rd parties. /// The length of the entity type in bytes - internal virtual int GetLength() + public virtual int GetLength() { throw new NotImplementedException(); } } - internal class ProfileOffsetFactory : BaseEntityFactory + internal class ProfileOffsetFactory : BaseEntityFactory { /// /// Creates a new instance of @@ -90,7 +104,7 @@ internal class ProfileOffsetFactory : BaseEntityFactory /// Binary reader positioned at the start of the profile offset /// /// A new instance of an profile offset - internal override ProfileOffset Create(DataSet dataSet, int index, Reader reader) + public override ProfileOffset Create(DataSet dataSet, int index, Reader reader) { return new ProfileOffset(dataSet, index, reader); } @@ -99,44 +113,25 @@ internal override ProfileOffset Create(DataSet dataSet, int index, Reader reader /// Returns the length of the entity /// /// Length in bytes of the ProfileOffset - internal override int GetLength() + public override int GetLength() { return sizeof(Int32) * 2; } } - internal class AsciiStringFactory : BaseEntityFactory + internal abstract class BaseAsciiStringFactory : BaseEntityFactory, D> { - /// - /// Creates a new instance of - /// - /// - /// The data set whose strings list the string is contained within - /// - /// - /// The offset to the start of the string within the string data - /// structure - /// - /// - /// Binary reader positioned at the start of the AsciiString - /// - /// A new instance of an - internal override AsciiString Create(DataSet dataSet, int offset, Reader reader) - { - return new AsciiString(dataSet, offset, reader); - } - /// /// Returns the length of the - /// entity including + /// entity including /// the null terminator and length indicator. /// /// Entity of type - /// + /// /// Length in bytes of the AsciiString - internal override int GetLength(AsciiString entity) + public override int GetLength(AsciiString entity) { - return entity.Value.Length + 3; ; + return entity.Value.Length + 3; } } @@ -155,7 +150,7 @@ internal class ComponentFactoryV31 : ComponentFactory /// start reading /// /// A new instance of an - internal override Component Create(DataSet dataSet, int index, Reader reader) + public override Component Create(DataSet dataSet, int index, Reader reader) { return new ComponentV31(dataSet, index, reader); } @@ -177,25 +172,25 @@ internal class ComponentFactoryV32 : ComponentFactory /// /// A new instance of an /// - internal override Component Create(DataSet dataSet, int index, Reader reader) + public override Component Create(DataSet dataSet, int index, Reader reader) { return new ComponentV32(dataSet, index, reader); } } - internal abstract class ComponentFactory : BaseEntityFactory + internal abstract class ComponentFactory : BaseEntityFactory { /// /// Returns the length of the entity /// /// Length in bytes of a Component - internal override int GetLength() + public override int GetLength() { return sizeof(int) * 2 + sizeof(byte); } } - internal class MapFactory : BaseEntityFactory + internal class MapFactory : BaseEntityFactory { /// /// Creates a new instance of @@ -209,7 +204,7 @@ internal class MapFactory : BaseEntityFactory /// start reading /// /// A new instance of an - internal override Map Create(DataSet dataSet, int index, Reader reader) + public override Map Create(DataSet dataSet, int index, Reader reader) { return new Map(dataSet, index, reader); } @@ -218,7 +213,7 @@ internal override Map Create(DataSet dataSet, int index, Reader reader) /// Returns the length of the entity /// /// Length in bytes of a Map - internal override int GetLength() + public override int GetLength() { return sizeof(int); } @@ -331,7 +326,7 @@ private static byte[] ReadValue(BinaryReader reader, bool isString) #endregion } - internal abstract class NodeFactory : BaseEntityFactory + internal abstract class NodeFactory : BaseEntityFactory { #region Constants @@ -348,7 +343,7 @@ internal abstract class NodeFactory : BaseEntityFactory #endregion - protected abstract Node Construct(DataSet dataSet, int offset, Reader reader); + protected abstract Node Construct(D dataSet, int offset, Reader reader); /// /// Creates a new instance of @@ -364,13 +359,13 @@ internal abstract class NodeFactory : BaseEntityFactory /// Binary reader positioned at the start of the Node /// /// A new instance of a - internal override Node Create(DataSet dataSet, int offset, Reader reader) + public override Node Create(D dataSet, int offset, Reader reader) { return Construct(dataSet, offset, reader); } } - internal class RootNodeFactory : BaseEntityFactory + internal class RootNodeFactory : BaseEntityFactory { /// /// An instance of based on the offset read @@ -387,7 +382,7 @@ internal class RootNodeFactory : BaseEntityFactory /// /// An instance of which is a root node /// - internal override Node Create(DataSet dataSet, int index, Reader reader) + public override Node Create(DataSet dataSet, int index, Reader reader) { return dataSet.Nodes[reader.ReadInt32()]; } @@ -396,13 +391,14 @@ internal override Node Create(DataSet dataSet, int index, Reader reader) /// Returns the length of the root node offset /// /// Length in bytes of a root node offset - internal override int GetLength() + public override int GetLength() { return sizeof(int); } } - internal abstract class ProfileFactory : BaseEntityFactory + internal abstract class ProfileFactory : BaseEntityFactory + where D : DataSet { #region Constants @@ -413,7 +409,7 @@ internal abstract class ProfileFactory : BaseEntityFactory #endregion - protected abstract Profile Construct(DataSet dataSet, int offset, Reader reader); + protected abstract Profile Construct(D dataSet, int offset, Reader reader); /// /// Creates a new instance of @@ -429,7 +425,7 @@ internal abstract class ProfileFactory : BaseEntityFactory /// Binary reader positioned at the start of the Profile /// /// A new instance of an - internal override Profile Create(DataSet dataSet, int offset, Reader reader) + public override Profile Create(D dataSet, int offset, Reader reader) { return Construct(dataSet, offset, reader); } @@ -439,7 +435,7 @@ internal override Profile Create(DataSet dataSet, int offset, Reader reader) /// /// Entity of type /// Length in bytes of the Profile - internal override int GetLength(Profile entity) + public override int GetLength(Profile entity) { return MinLength + (entity.ValueIndexes.Length * sizeof(int)) + @@ -447,7 +443,7 @@ internal override int GetLength(Profile entity) } } - internal class PropertyFactory : BaseEntityFactory + internal class PropertyFactory : BaseEntityFactory { #region Constants @@ -490,18 +486,19 @@ internal class PropertyFactory : BaseEntityFactory /// Binary reader positioned at the start of the Property /// /// A new instance of a - internal override Property Create(DataSet dataSet, int offset, Reader reader) + public override Property Create(DataSet dataSet, int offset, Reader reader) { return new Property(dataSet, offset, reader); } - internal override int GetLength() + public override int GetLength() { return RecordLength; } } - internal class ValueFactory : BaseEntityFactory + internal class ValueFactory : BaseEntityFactory + where D: DataSet { #region Constants @@ -532,12 +529,12 @@ internal class ValueFactory : BaseEntityFactory /// Binary reader positioned at the start of the Value /// /// A new instance of a - internal override Value Create(DataSet dataSet, int offset, Reader reader) + public override Value Create(D dataSet, int offset, Reader reader) { return new Value(dataSet, offset, reader); } - internal override int GetLength() + public override int GetLength() { return RecordLength; } @@ -545,7 +542,8 @@ internal override int GetLength() #endregion } - internal class SignatureFactoryV31 : BaseEntityFactory + internal class SignatureFactoryV31 : BaseEntityFactory + where D : DataSet { #region Fields @@ -556,10 +554,10 @@ internal class SignatureFactoryV31 : BaseEntityFactory #region Constructor /// - /// Constructs a new instance of + /// Constructs a new instance of /// /// The data set the factory will create signatures for - internal SignatureFactoryV31(DataSet dataSet) + internal SignatureFactoryV31(D dataSet) { _recordLength = (dataSet.SignatureProfilesCount * sizeof(int)) + @@ -583,7 +581,7 @@ internal SignatureFactoryV31(DataSet dataSet) /// Binary reader positioned at the start of the signature /// /// A new instance of a - internal override Signature Create(DataSet dataSet, int index, Reader reader) + public override Signature Create(D dataSet, int index, Reader reader) { return new SignatureV31(dataSet, index, reader); } @@ -592,7 +590,7 @@ internal override Signature Create(DataSet dataSet, int index, Reader reader) /// The length of the signature. /// /// Length of the signature in bytes - internal override int GetLength() + public override int GetLength() { return _recordLength; } @@ -600,7 +598,8 @@ internal override int GetLength() #endregion } - internal class SignatureFactoryV32 : BaseEntityFactory + internal class SignatureFactoryV32 : BaseEntityFactory + where D : DataSet { #region Constants @@ -624,9 +623,9 @@ internal class SignatureFactoryV32 : BaseEntityFactory #region Constructor /// - /// Constructs a new instance of + /// Constructs a new instance of . /// - internal SignatureFactoryV32(DataSet dataSet) + internal SignatureFactoryV32(D dataSet) { _recordLength = (dataSet.SignatureProfilesCount * sizeof(int)) + @@ -650,7 +649,7 @@ internal SignatureFactoryV32(DataSet dataSet) /// Binary reader positioned at the start of the signature /// /// A new instance of a - internal override Signature Create(DataSet dataSet, int index, Reader reader) + public override Signature Create(D dataSet, int index, Reader reader) { return new SignatureV32(dataSet, index, reader); } @@ -659,7 +658,7 @@ internal override Signature Create(DataSet dataSet, int index, Reader reader) /// The length of the signature. /// /// Length of the signature in bytes - internal override int GetLength() + public override int GetLength() { return _recordLength; } diff --git a/FoundationV3/Mobile/Detection/Factories/MemoryFactory.cs b/FoundationV3/Mobile/Detection/Factories/MemoryFactory.cs index a368b00..706c5ed 100644 --- a/FoundationV3/Mobile/Detection/Factories/MemoryFactory.cs +++ b/FoundationV3/Mobile/Detection/Factories/MemoryFactory.cs @@ -179,48 +179,48 @@ internal static void Load(DataSet dataSet, Reader reader, bool init) { CommonFactory.LoadHeader(dataSet, reader); - var strings = new MemoryVariableList(dataSet, reader, new AsciiStringFactory()); - MemoryFixedList components = null; + var strings = new MemoryVariableList, DataSet>(dataSet, reader, new MemoryAsciiStringFactory()); + MemoryFixedList components = null; switch(dataSet.VersionEnum) { case BinaryConstants.FormatVersions.PatternV31: - components = new MemoryFixedList(dataSet, reader, new ComponentFactoryV31()); + components = new MemoryFixedList(dataSet, reader, new ComponentFactoryV31()); break; case BinaryConstants.FormatVersions.PatternV32: - components = new MemoryFixedList(dataSet, reader, new ComponentFactoryV32()); + components = new MemoryFixedList(dataSet, reader, new ComponentFactoryV32()); break; } - var maps = new MemoryFixedList(dataSet, reader, new MapFactory()); + var maps = new MemoryFixedList(dataSet, reader, new MapFactory()); var properties = new PropertiesList(dataSet, reader, new PropertyFactory()); - var values = new MemoryFixedList(dataSet, reader, new ValueFactory()); - var profiles = new MemoryVariableList(dataSet, reader, new ProfileMemoryFactory()); - MemoryFixedList signatures = null; + var values = new MemoryFixedList(dataSet, reader, new ValueFactory()); + var profiles = new MemoryVariableList(dataSet, reader, new ProfileMemoryFactory()); + MemoryFixedList signatures = null; MemoryIntegerList signatureNodeOffsets = null; MemoryIntegerList nodeRankedSignatureIndexes = null; switch(dataSet.VersionEnum) { case BinaryConstants.FormatVersions.PatternV31: - signatures = new MemoryFixedList(dataSet, reader, new SignatureFactoryV31(dataSet)); + signatures = new MemoryFixedList(dataSet, reader, new SignatureFactoryV31(dataSet)); break; case BinaryConstants.FormatVersions.PatternV32: - signatures = new MemoryFixedList(dataSet, reader, new SignatureFactoryV32(dataSet)); + signatures = new MemoryFixedList(dataSet, reader, new SignatureFactoryV32(dataSet)); signatureNodeOffsets = new MemoryIntegerList(reader); nodeRankedSignatureIndexes = new MemoryIntegerList(reader); break; } var rankedSignatureIndexes = new MemoryIntegerList(reader); - MemoryVariableList nodes = null; + MemoryVariableList nodes = null; switch (dataSet.VersionEnum) { case BinaryConstants.FormatVersions.PatternV31: - nodes = new MemoryVariableList(dataSet, reader, new NodeMemoryFactoryV31()); + nodes = new MemoryVariableList(dataSet, reader, new NodeMemoryFactoryV31()); break; case BinaryConstants.FormatVersions.PatternV32: - nodes = new MemoryVariableList(dataSet, reader, new NodeMemoryFactoryV32()); + nodes = new MemoryVariableList(dataSet, reader, new NodeMemoryFactoryV32()); break; } - var rootNodes = new MemoryFixedList(dataSet, reader, new RootNodeFactory()); - var profileOffsets = new MemoryFixedList(dataSet, reader, new ProfileOffsetFactory()); + var rootNodes = new MemoryFixedList(dataSet, reader, new RootNodeFactory()); + var profileOffsets = new MemoryFixedList(dataSet, reader, new ProfileOffsetFactory()); dataSet.Strings = strings; dataSet._components = components; diff --git a/FoundationV3/Mobile/Detection/Factories/StreamFactory.cs b/FoundationV3/Mobile/Detection/Factories/StreamFactory.cs index 5263b2f..f8ffa47 100644 --- a/FoundationV3/Mobile/Detection/Factories/StreamFactory.cs +++ b/FoundationV3/Mobile/Detection/Factories/StreamFactory.cs @@ -180,31 +180,32 @@ private static void Load(DataSet dataSet) { reader.BaseStream.Position = 0; CommonFactory.LoadHeader(dataSet, reader); - dataSet.Strings = new VariableList(dataSet, reader, new AsciiStringFactory(), Constants.StringsCacheSize); - MemoryFixedList components = null; + dataSet.Strings = new VariableList, DataSet>( + dataSet, reader, new StreamAsciiStringFactory(), Constants.StringsCacheSize); + MemoryFixedList components = null; switch (dataSet.VersionEnum) { case BinaryConstants.FormatVersions.PatternV31: - components = new MemoryFixedList(dataSet, reader, new ComponentFactoryV31()); + components = new MemoryFixedList(dataSet, reader, new ComponentFactoryV31()); break; case BinaryConstants.FormatVersions.PatternV32: - components = new MemoryFixedList(dataSet, reader, new ComponentFactoryV32()); + components = new MemoryFixedList(dataSet, reader, new ComponentFactoryV32()); break; } dataSet._components = components; - var maps = new MemoryFixedList(dataSet, reader, new MapFactory()); + var maps = new MemoryFixedList(dataSet, reader, new MapFactory()); dataSet._maps = maps; var properties = new PropertiesList(dataSet, reader, new PropertyFactory()); dataSet._properties = properties; - dataSet._values = new FixedCacheList(dataSet, reader, new ValueFactory(), Constants.ValuesCacheSize); - dataSet.Profiles = new VariableList(dataSet, reader, new ProfileStreamFactory(dataSet.Pool), Constants.ProfilesCacheSize); + dataSet._values = new FixedCacheList(dataSet, reader, new ValueFactory(), Constants.ValuesCacheSize); + dataSet.Profiles = new VariableList(dataSet, reader, new ProfileStreamFactory(dataSet.Pool), Constants.ProfilesCacheSize); switch (dataSet.VersionEnum) { case BinaryConstants.FormatVersions.PatternV31: - dataSet._signatures = new FixedCacheList(dataSet, reader, new SignatureFactoryV31(dataSet), Constants.SignaturesCacheSize); + dataSet._signatures = new FixedCacheList(dataSet, reader, new SignatureFactoryV31(dataSet), Constants.SignaturesCacheSize); break; case BinaryConstants.FormatVersions.PatternV32: - dataSet._signatures = new FixedCacheList(dataSet, reader, new SignatureFactoryV32(dataSet), Constants.SignaturesCacheSize); + dataSet._signatures = new FixedCacheList(dataSet, reader, new SignatureFactoryV32(dataSet), Constants.SignaturesCacheSize); dataSet._signatureNodeOffsets = new IntegerList(dataSet, reader); dataSet._nodeRankedSignatureIndexes = new IntegerList(dataSet, reader); break; @@ -213,15 +214,15 @@ private static void Load(DataSet dataSet) switch (dataSet.VersionEnum) { case BinaryConstants.FormatVersions.PatternV31: - dataSet.Nodes = new VariableList(dataSet, reader, new NodeStreamFactoryV31(dataSet.Pool), Constants.NodesCacheSize); + dataSet.Nodes = new VariableList(dataSet, reader, new NodeStreamFactoryV31(dataSet.Pool), Constants.NodesCacheSize); break; case BinaryConstants.FormatVersions.PatternV32: - dataSet.Nodes = new VariableList(dataSet, reader, new NodeStreamFactoryV32(dataSet.Pool), Constants.NodesCacheSize); + dataSet.Nodes = new VariableList(dataSet, reader, new NodeStreamFactoryV32(dataSet.Pool), Constants.NodesCacheSize); break; } - var rootNodes = new MemoryFixedList(dataSet, reader, new RootNodeFactory()); + var rootNodes = new MemoryFixedList(dataSet, reader, new RootNodeFactory()); dataSet.RootNodes = rootNodes; - var profileOffsets = new MemoryFixedList(dataSet, reader, new ProfileOffsetFactory()); + var profileOffsets = new MemoryFixedList(dataSet, reader, new ProfileOffsetFactory()); dataSet._profileOffsets = profileOffsets; // Read into memory all the small lists which are frequently accessed. diff --git a/FoundationV3/Mobile/Detection/IReadonlyList.cs b/FoundationV3/Mobile/Detection/IReadonlyList.cs index e1920ee..f3d6576 100644 --- a/FoundationV3/Mobile/Detection/IReadonlyList.cs +++ b/FoundationV3/Mobile/Detection/IReadonlyList.cs @@ -29,8 +29,8 @@ namespace FiftyOne.Foundation.Mobile.Detection /// A list which only provides those features needed to read items from /// the list. /// - /// The type of the list will contain - public interface IReadonlyList : IDisposable, IEnumerable where T : BaseEntity + /// The type of item the list will contain + public interface IReadonlyList : IDisposable, IEnumerable { /// /// Accessor for the list. diff --git a/FoundationV3/Mobile/Detection/Readers/Reader.cs b/FoundationV3/Mobile/Detection/Readers/Reader.cs index bcee7e1..e8666ee 100644 --- a/FoundationV3/Mobile/Detection/Readers/Reader.cs +++ b/FoundationV3/Mobile/Detection/Readers/Reader.cs @@ -19,9 +19,7 @@ * defined by the Mozilla Public License, v. 2.0. * ********************************************************************* */ -using System; using System.Collections.Generic; -using System.Text; using System.IO; namespace FiftyOne.Foundation.Mobile.Detection.Readers @@ -31,7 +29,8 @@ namespace FiftyOne.Foundation.Mobile.Detection.Readers /// to reduce the number of objects created for garbage collection /// to handle. /// - internal class Reader : System.IO.BinaryReader + /// Not intended to be used directly by 3rd parties. + public class Reader : System.IO.BinaryReader { /// /// A list of integers used to create arrays when the number of elements @@ -43,6 +42,6 @@ internal class Reader : System.IO.BinaryReader /// Constructs a new instance of reader from the stream. /// /// - internal Reader(Stream stream) : base(stream) { } + public Reader(Stream stream) : base(stream) { } } } diff --git a/FoundationV3/Mobile/Detection/Readers/Source.cs b/FoundationV3/Mobile/Detection/Readers/Source.cs index 4d1cf76..efa8d99 100644 --- a/FoundationV3/Mobile/Detection/Readers/Source.cs +++ b/FoundationV3/Mobile/Detection/Readers/Source.cs @@ -33,7 +33,8 @@ namespace FiftyOne.Foundation.Mobile.Detection.Readers /// Must be disposed to ensure that the readers are closed and any resources /// free for other uses. /// - internal abstract class SourceBase : IDisposable + /// Not intended to be used directly by 3rd parties. + public abstract class SourceBase : IDisposable { #region Fields @@ -50,7 +51,7 @@ internal abstract class SourceBase : IDisposable /// Creates a new stream from the data source. /// /// A freshly opened stream to the data source - internal abstract System.IO.Stream CreateStream(); + protected abstract System.IO.Stream CreateStream(); #endregion @@ -91,7 +92,8 @@ public virtual void Dispose() /// /// Base class for file sources. /// - internal abstract class SourceFileBase : SourceBase + /// Not intended to be used directly by 3rd parties. + public abstract class SourceFileBase : SourceBase { #region Fields @@ -115,7 +117,7 @@ internal abstract class SourceFileBase : SourceBase /// /// File source of the data /// True if the file should be deleted when the source is disposed - internal SourceFileBase(string fileName, bool isTempFile) + protected SourceFileBase(string fileName, bool isTempFile) { _fileInfo = new FileInfo(fileName); _isTempFile = isTempFile; @@ -152,7 +154,8 @@ protected void DeleteFile() /// Encapsulates either a file containing the uncompressed /// data structures used by the data set. /// - internal class SourceFile : SourceFileBase + /// Not intended to be used directly by 3rd parties. + public class SourceFile : SourceFileBase { #region Constructors @@ -161,7 +164,7 @@ internal class SourceFile : SourceFileBase /// /// File source of the data /// True if the file should be deleted when the source is disposed - internal SourceFile(string fileName, bool isTempFile) + public SourceFile(string fileName, bool isTempFile) : base(fileName, isTempFile) { } @@ -174,7 +177,7 @@ internal SourceFile(string fileName, bool isTempFile) /// Creates a new stream from the data source. /// /// A freshly opened stream to the data source - internal override System.IO.Stream CreateStream() + protected override System.IO.Stream CreateStream() { return _fileInfo.OpenRead(); } @@ -196,7 +199,8 @@ public override void Dispose() /// Encapsulates a byte array containing the uncompressed /// data structures used by the data set. /// - internal class SourceMemory : SourceBase + /// Not intended to be used directly by 3rd parties. + public class SourceMemory : SourceBase { #region Fields @@ -213,7 +217,7 @@ internal class SourceMemory : SourceBase /// Creates the source from the byte array provided. /// /// Byte array source of the data - internal SourceMemory(byte[] buffer) + public SourceMemory(byte[] buffer) { _buffer = buffer; } @@ -226,7 +230,7 @@ internal SourceMemory(byte[] buffer) /// Creates a new stream from the data source. /// /// A freshly opened stream to the data source - internal override System.IO.Stream CreateStream() + protected override System.IO.Stream CreateStream() { return new MemoryStream(_buffer); } diff --git a/FoundationV3/Mobile/Detection/Search.cs b/FoundationV3/Mobile/Detection/Search.cs index a25c80e..d2b6655 100644 --- a/FoundationV3/Mobile/Detection/Search.cs +++ b/FoundationV3/Mobile/Detection/Search.cs @@ -19,37 +19,42 @@ * defined by the Mozilla Public License, v. 2.0. * ********************************************************************* */ -using FiftyOne.Foundation.Mobile.Detection.Entities; using System; using System.Collections.Generic; -using System.Linq; -using System.Text; namespace FiftyOne.Foundation.Mobile.Detection { - internal abstract class SearchBase + /// + /// Generic search class used to perform a binary search where the + /// type of items in the list and the key are different types. + /// + /// Not intended to be used directly by 3rd parties. + /// The type of items in the list + /// The type of the key field in the list + /// The type of the list + public abstract class SearchBase { /// - /// Returns the number of elements in the list. + /// Returns the number of items in the list provided. /// - /// - /// + /// List to be counted. + /// Number of items in the list. protected abstract int GetCount(L list); /// - /// Returns the value from the list at the index provided. + /// Returns the item at the index provided. /// - /// - /// - /// + /// List to get item from. + /// Index of the element to return. + /// The value at the index provided. protected abstract T GetValue(L list, int index); /// /// Compares the item to the key. /// - /// - /// - /// + /// Item to be compared. + /// Key to be compared to the item. + /// Difference between the item and the key. protected abstract int CompareTo(T item, K key); /// @@ -91,7 +96,9 @@ protected int BinarySearchBase(L list, K key) /// /// The list order by keys to be searched /// The key to be found - /// Number of iterations needed to find the key. + /// + /// Number of iterations needed to find the key. + /// /// /// Index of the item which matches the key, or the ones complement /// of the index to add the value at. @@ -124,24 +131,107 @@ protected int BinarySearchBase(L list, K key, out int iterations) } } - internal class SearchLists : SearchBase> where T : IComparable + /// + /// Used to search lists of order items using a key that this not the same + /// types as the items in the list. + /// + /// The type of items in the list + /// The type of the key field in the list + public class SearchLists : + SearchBase> where T : IComparable { + /// + /// Returns the number of items in the list provided. + /// + /// List to be counted. + /// Number of items in the list. protected override int GetCount(IList list) { return list.Count; } + /// + /// Returns the item at the index provided. + /// + /// List to get item from. + /// Index of the element to return. + /// The value at the index provided. protected override T GetValue(IList list, int index) { return list[index]; } + /// + /// Compares the item to the key. + /// + /// Item to be compared. + /// Key to be compared to the item. + /// Difference between the item and the key. protected override int CompareTo(T item, K key) { return item.CompareTo(key); } - internal int BinarySearch(IList list, K key) + /// + /// Searches the list provided for the key. + /// + /// List to search. + /// Key to find. + /// + /// Index of the item in the list, or the twos complement. + /// + public int BinarySearch(IList list, K key) + { + return base.BinarySearchBase(list, key); + } + } + + /// + /// The list of complex types referenced by the index integer used in + /// the search. i.e. the source list could be a list of values and + /// the list passed into the method a list of integer indexes to + /// values. This class avoids the need to create arrays of all complex + /// types when performing a search that will in practice only need to + /// retrieve a small subset improving memory efficiency. + /// + internal class SearchReadonlyList : + SearchBase> where T : IComparable + { + /// + /// The list of complex values to use with the index. This may be a + /// memory list, or a stream list where values are retrieved from the + /// data source or cache. Used with the GetValue implementation to + /// return the complex type associated with the integer index. + /// + private readonly IReadonlyList _source; + + /// + /// Constructs a new instance of . + /// + /// + /// The list of complex values to use with the index. + /// + internal SearchReadonlyList(IReadonlyList source) + { + _source = source; + } + + protected override int GetCount(IList list) + { + return list.Count; + } + + protected override T GetValue(IList list, int index) + { + return _source[list[index]]; + } + + protected override int CompareTo(T item, K key) + { + return item.CompareTo(key); + } + + internal int BinarySearch(IList list, K key) { return base.BinarySearchBase(list, key); } diff --git a/Integration Tests/Integration Tests.csproj b/Integration Tests/Integration Tests.csproj index 83331ee..c83049f 100644 --- a/Integration Tests/Integration Tests.csproj +++ b/Integration Tests/Integration Tests.csproj @@ -33,7 +33,26 @@ CODE_ANALYSIS;TRACE true pdbonly - x64 + AnyCPU + true + prompt + MinimumRecommendedRules.ruleset + + + true + bin\Debug\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + bin\Release\ + CODE_ANALYSIS;CODE_ANALYSIS;TRACE + true + pdbonly + AnyCPU true prompt MinimumRecommendedRules.ruleset diff --git a/README.md b/README.md index a3a01e6..d90f722 100644 --- a/README.md +++ b/README.md @@ -49,9 +49,9 @@ Data files which are updated weekly and daily, automatically, and with more prop ## Recent Changes -### Version 3.2.12 Highlights +### Version 3.2.11 Highlights -New Lite Data File released for September. +New Lite Data File released for August. ### Major Changes in Version 3.2 @@ -67,10 +67,16 @@ New Lite Data File released for September. * Version 3.2 data file formats are supported in parallel with version 3.1 data files. * 51Degrees unit tests are now part of the open source distribution. -### Changes from 3.2.11 +### Changes from 3.2.5 Summary of API changes: -* When the WebProvider is being used outside a web environment to make use of the update feature, it is useful to see the return code of the data file download. The codes are detailed in the LicenceKeyResults enumeration. Updating manually in this way may mean that the Download method is called when there is no bin directory (where the API searches for a licence key file). For this reason a check has been added to the Keys method in LicenceKeys which checks for the existance of the bin directory before searching it for a licence key file. -* Added all profiles example, and removed unnecessary configurations. -* Updated the Lite data files for September data. \ No newline at end of file +* Provider supports retrieving match results using device ids generated from previous matches. +* The classes to update device data files are now public and can be used to update device data files from non web environments. +* Licence keys are now verified against the 51Degrees public signature before being used to retrieve updates. +* The cache has been upgraded to use a least recently used (LRU) design. This removes the need to service the cache in a background thread, and results in a more predictable performance under load. +* Duplicate code has been consolidated with a focus on improving documentation and implementing recommendations from code analysis and peer reviews. Testing coverage has been included with initial unit tests for new features. +* Consistent examples have been added in parallel with APIs in other languages. The examples are designed to highlight specific use cases for the API. They relate to example specific documentation on the 51Degrees web site under Support -> Documentation -> .NET. +* The override to indicate if cookies are supported now defaults to True when the value is unknown. This prevents 3rd party components such as forms authentication from failing where an assumption that cookies are always supported has been made but not verified against the server side browser capabilities. +* The demo web site project no longer includes the 51Degrees.dat file in the project. It is instead copied from the repositories data folder when the project is built. +* The signed assembly is now compiled with "Optimise Code" option enabled. \ No newline at end of file