A device detection library that is used natively or by 51Degrees products

Hash/MatchMetrics.c

Match metrics example of using 51Degrees device detection.

Match metrics example of using 51Degrees device detection.The example shows how to:

  1. Specify the name of the data file and properties the data set should be initialised with.
    const char* fileName = argv[1];
    fiftyoneDegreesPropertiesDefault;
    properties.string = "IsMobile";
    Defines a set of properties which are required by a caller.
    Definition properties.h:240
    const char * string
    Separated list of required properties or NULL if all properties are required.
    Definition properties.h:245
  2. Instantiate the 51Degrees data set within a resource manager from the specified data file with the required properties and the specified configuration.
    &manager,
    &config,
    &properties,
    dataFilePath,
    exception);
    fiftyoneDegreesStatusCode fiftyoneDegreesHashInitManagerFromFile(fiftyoneDegreesResourceManager *manager, fiftyoneDegreesConfigHash *config, fiftyoneDegreesPropertiesRequired *properties, const char *fileName, fiftyoneDegreesException *exception)
    Initialises the resource manager with a Hash data set resource populated from the Hash data file refe...
    fiftyoneDegreesStatusCode
    Status returned from the initialisation of a resource.
    Definition status.h:81
  3. Create a results instance ready to be populated by the data set.
    &manager,
    1,
    0);
    fiftyoneDegreesResultHashArray fiftyoneDegreesResultsHash
    Array of Hash results used to easily access and track the size of the array.
    Definition hash.h:383
    fiftyoneDegreesResultsHash * fiftyoneDegreesResultsHashCreate(fiftyoneDegreesResourceManager *manager, uint32_t userAgentCapacity, uint32_t overridesCapacity)
    Allocates a results structure containing a reference to the Hash data set managed by the resource man...
  4. Process a single HTTP User-Agent string to retrieve the values associated with the User-Agent for the selected properties.
    results,
    mobileUserAgent,
    strlen(mobileUserAgent),
    exception);
    void fiftyoneDegreesResultsHashFromUserAgent(fiftyoneDegreesResultsHash *results, const char *userAgent, size_t userAgentLength, fiftyoneDegreesException *exception)
    Process a single User-Agent and populate the device offsets in the results structure.
  5. Obtain the match metrics. The results hold a result for each component, such as the hardware or the browser, and the metrics are taken across them. A walk of a component's graph sets the metrics of its result, so any graph not yet walked is walked first. A metric that is not needed can be passed as NULL.
    int32_t drift, difference, iterations;
    results,
    &method,
    &difference,
    &drift,
    &iterations,
    NULL,
    exception);
    void fiftyoneDegreesResultsHashGetMatchMetrics(fiftyoneDegreesResultsHash *results, fiftyoneDegreesHashMatchMethod *method, int32_t *difference, int32_t *drift, int32_t *iterations, int32_t *matchedNodes, fiftyoneDegreesException *exception)
    Gets the match metrics of the results, taken across every result.
    fiftyoneDegreesHashMatchMethod
    DATA STRUCTURES.
    Definition hash.h:130
  6. The drift is the largest number of characters a matched substring of a result was from where it was expected to be found, added up over the results. The maximum drift to allow when finding a match can be set through the configuration structure.
  7. The difference is the total difference in hash code values between the matched substrings and the actual substrings. The maximum difference to allow when finding a match can be set through the configuration structure.
  8. The iterations are the number of iterations required to get the device offset in the devices collection in the graph of nodes. This is indicative of the time taken to fetch the result.
  9. The method is the highest method any result used, which provides information about the algorithm that was used to perform detection for a particular User-Agent. For more information on what each method means please see: How device detection works.
  10. Obtain the matched User-Agent of the first result, which holds the matched substrings of the User-Agent separated with underscores.
    const char *matchedUserAgent =
    const char * fiftyoneDegreesResultsHashGetMatchedUserAgent(fiftyoneDegreesResultsHash *results, uint32_t resultIndex, fiftyoneDegreesException *exception)
    Gets the matched User-Agent of one result, being the evidence value its component was matched from,...
  11. Release the memory used by the results.
    void fiftyoneDegreesResultsHashFree(fiftyoneDegreesResultsHash *results)
    Frees the results structure created by the fiftyoneDegreesResultsHashCreate method.
  12. Finally release the memory used by the data set resource.
    fiftyoneDegreesResourceManagerFree(&manager);
/* *********************************************************************
* This Original Work is copyright of 51 Degrees Mobile Experts Limited.
* Copyright 2026 51 Degrees Mobile Experts Limited, Davidson House,
* Forbury Square, Reading, Berkshire, United Kingdom RG1 3EU.
*
* This Original Work is licensed under the European Union Public Licence
* (EUPL) v.1.2 and is subject to its terms as set out below.
*
* If a copy of the EUPL was not distributed with this file, You can obtain
* one at https://opensource.org/licenses/EUPL-1.2.
*
* The 'Compatible Licences' set out in the Appendix to the EUPL (as may be
* amended by the European Commission) shall be deemed incompatible for
* the purposes of the Work and the provisions of the compatibility
* clause in Article 5 of the EUPL shall not apply.
*
* If using the Work as, or as part of, a network application, by
* including the attribution notice(s) required under Article 5 of the EUPL
* in the end user terms of the application under an appropriate heading,
* such notice(s) shall fulfill the requirements of that article.
* ********************************************************************* */
#include <stdio.h>
// Include ExmapleBase.h before others as it includes Windows 'crtdbg.h'
// which requires to be included before 'malloc.h'.
#include "ExampleBase.h"
#include "../../../../src/dd/hash/hash.h"
#include "../../../../src/dd/hash/fiftyone.h"
static const char *dataDir = "data/device-detection";
static const char *dataFileName = "51Degrees-LiteV4.1.hash";
// Returned by main. Set to 1 when the data file cannot be used.
static int exitCode = 0;
static char valueBuffer[1024] = "";
static const char* getPropertyValueAsString(
ResultsHash *results,
const char *propertyName) {
results,
propertyName,
valueBuffer,
sizeof(valueBuffer),
(char* const)",",
exception);
return valueBuffer;
}
static void outputMatchMetrics(ResultsHash *results) {
char deviceId[40];
HashMatchMethod matchMethod;
int32_t drift, difference, iterations;
results,
deviceId,
sizeof(deviceId),
exception);
results,
&matchMethod,
&difference,
&drift,
&iterations,
NULL,
exception);
const char *method;
switch (matchMethod) {
case FIFTYONE_DEGREES_HASH_MATCH_METHOD_PERFORMANCE:
method = "PERFORMANCE";
break;
case FIFTYONE_DEGREES_HASH_MATCH_METHOD_COMBINED:
method = "COMBINED";
break;
case FIFTYONE_DEGREES_HASH_MATCH_METHOD_PREDICTIVE:
method = "PREDICTIVE";
break;
case FIFTYONE_DEGREES_HASH_MATCH_METHOD_NONE:
default:
method = "NONE";
break;
}
const char *matchedUserAgent = ResultsHashGetMatchedUserAgent(
results,
0,
exception);
printf(" IsMobile: %s\n",
getPropertyValueAsString(results, "IsMobile"));
printf(" Id: %s\n", deviceId);
printf(" Drift: %d\n", drift);
printf(" Difference: %d\n", difference);
printf(" Iterations: %d\n", iterations);
printf(" Method: %s\n", method);
printf(" Sub Strings: %s\n",
matchedUserAgent == NULL ? "" : matchedUserAgent);
return;
}
static void reportStatus(StatusCode status,
const char* fileName) {
const char *message = StatusGetMessage(status, fileName);
printf("%s\n", message);
Free((void*)message);
}
void fiftyoneDegreesHashMatchMetrics(
const char *dataFilePath,
ConfigHash *config) {
ResourceManager manager;
// Set the properties to be returned for each User-Agent.
properties.string = "ScreenPixelsWidth,HardwareModel,IsMobile,BrowserName,"
"Id,HardwareVendor";
// Initialise the manager for device detection.
&manager,
config,
&properties,
dataFilePath,
exception);
if (status != SUCCESS) {
reportStatus(status, dataFilePath);
exitCode = 1;
fgetc(stdin);
return;
}
// Create a results instance to store and process User-Agents.
ResultsHash *results = ResultsHashCreate(&manager, 0);
// User-Agent string of an iPhone mobile device.
const char* mobileUserAgent = ("Mozilla/5.0 (iPhone; CPU iPhone OS 7_1 "
"like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 "
"Mobile/11D167 Safari/9537.53");
// User-Agent string of Firefox Web browser version 41 on desktop.
const char* desktopUserAgent = (
"Mozilla/5.0 (Windows NT 6.3; WOW64; rv:41.0) "
"Gecko/20100101 Firefox/41.0");
// User-Agent string of a MediaHub device.
const char* mediaHubUserAgent = (
"Mozilla/5.0 (Linux; Android 4.4.2; X8 Quad Core "
"Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 "
"Chrome/30.0.0.0 Safari/537.36");
printf("Starting Match Metrics Example.\n");
// Carries out a match for a mobile User-Agent.
printf("\nMobile User-Agent: %s\n", mobileUserAgent);
results,
mobileUserAgent,
strlen(mobileUserAgent),
exception);
outputMatchMetrics(results);
// Carries out a match for a desktop User-Agent.
printf("\nDesktop User-Agent: %s\n", desktopUserAgent);
results,
desktopUserAgent,
strlen(desktopUserAgent),
exception);
outputMatchMetrics(results);
// Carries out a match for a MediaHub User-Agent.
printf("\nMedia hub User-Agent: %s\n", mediaHubUserAgent);
results,
mediaHubUserAgent,
strlen(mediaHubUserAgent),
exception);
outputMatchMetrics(results);
// Say what the Enterprise data file adds, on a free data file.
fiftyoneDegreesExampleOfferEnterprise(&manager);
// Ensure the results are freed to avoid memory leaks.
ResultsHashFree(results);
// Free the resources used by the manager.
}
void fiftyoneDegreesExampleCMatchMetricsRun(ExampleParameters *params) {
// Call the actual function.
fiftyoneDegreesHashMatchMetrics(
params->dataFilePath,
params->config);
}
#ifndef TEST
int main(int argc, char* argv[]) {
StatusCode status = SUCCESS;
char dataFilePath[FILE_MAX_PATH];
if (argc > 1) {
strcpy(dataFilePath, argv[1]);
}
else {
status = fiftyoneDegreesExampleGetFilePath(
dataDir,
dataFileName,
dataFilePath,
sizeof(dataFilePath));
}
if (status != SUCCESS) {
reportStatus(status, dataFileName);
fgetc(stdin);
return 1;
}
}
ExampleParameters params;
params.dataFilePath = dataFilePath;
params.config = &config;
// Run the example
fiftyoneDegreesExampleMemCheck(
&params,
fiftyoneDegreesExampleCMatchMetricsRun);
// Wait for a character to be pressed.
fgetc(stdin);
return exitCode;
}
#endif
#define ResultsHashGetValuesString
Synonym for fiftyoneDegreesResultsHashGetValuesString function.
Definition dd/hash/fiftyone.h:62
#define ResultsHashGetMatchedUserAgent
Synonym for fiftyoneDegreesResultsHashGetMatchedUserAgent function.
Definition dd/hash/fiftyone.h:68
fiftyoneDegreesConfigHash ConfigHash
Synonym for fiftyoneDegreesConfigHash type.
Definition dd/hash/fiftyone.h:51
fiftyoneDegreesResultsHash ResultsHash
Synonym for fiftyoneDegreesResultsHash type.
Definition dd/hash/fiftyone.h:50
fiftyoneDegreesHashMatchMethod HashMatchMethod
Synonym for fiftyoneDegreesHashMatchMethod type.
Definition dd/hash/fiftyone.h:55
#define HashInMemoryConfig
Synonym for fiftyoneDegreesHashInMemoryConfig config.
Definition dd/hash/fiftyone.h:99
#define ResultsHashFromUserAgent
Synonym for fiftyoneDegreesResultsHashFromUserAgent function.
Definition dd/hash/fiftyone.h:72
#define ResultsHashGetMatchMetrics
Synonym for fiftyoneDegreesResultsHashGetMatchMetrics function.
Definition dd/hash/fiftyone.h:66
#define ResultsHashCreate(manager, overridesCapacity)
Two argument convenience form of fiftyoneDegreesResultsHashCreate that injects the deprecated userAge...
Definition dd/hash/fiftyone.h:69
#define HashDefaultConfig
Synonym for fiftyoneDegreesHashDefaultConfig config.
Definition dd/hash/fiftyone.h:104
#define ResultsHashFree
Synonym for fiftyoneDegreesResultsHashFree function.
Definition dd/hash/fiftyone.h:70
#define HashGetDeviceIdFromResults
Synonym for fiftyoneDegreesHashGetDeviceIdFromResults function.
Definition dd/hash/fiftyone.h:65
#define HashInitManagerFromFile
Synonym for fiftyoneDegreesHashInitManagerFromFile function.
Definition dd/hash/fiftyone.h:81
#define EXCEPTION_THROW
Synonym for FIFTYONE_DEGREES_EXCEPTION_THROW macro.
Definition common/fiftyone.h:471
#define CollectionGetIsMemoryOnly
Synonym for fiftyoneDegreesCollectionGetIsMemoryOnly function.
Definition common/fiftyone.h:358
#define PropertiesDefault
Synonym for fiftyoneDegreesPropertiesDefault function.
Definition common/fiftyone.h:271
#define EXCEPTION_CREATE
Synonym for FIFTYONE_DEGREES_EXCEPTION_CREATE macro.
Definition common/fiftyone.h:468
#define StatusGetMessage
Synonym for fiftyoneDegreesStatusGetMessage function.
Definition common/fiftyone.h:296
fiftyoneDegreesStatusCode StatusCode
Synonym for fiftyoneDegreesStatusCode type.
Definition common/fiftyone.h:136
#define SUCCESS
Synonym for FIFTYONE_DEGREES_STATUS_SUCCESS status code.
Definition common/fiftyone.h:503
#define ResourceManagerFree
Synonym for fiftyoneDegreesResourceManagerFree function.
Definition common/fiftyone.h:313
fiftyoneDegreesResourceManager ResourceManager
Synonym for fiftyoneDegreesResourceManager type.
Definition common/fiftyone.h:139
fiftyoneDegreesPropertiesRequired PropertiesRequired
Synonym for fiftyoneDegreesPropertiesRequired type.
Definition common/fiftyone.h:137
#define Free
Synonym for fiftyoneDegreesFree function.
Definition common/fiftyone.h:268
#define FILE_MAX_PATH
Synonym for FIFTYONE_DEGREES_FILE_MAX_PATH macro.
Definition common/fiftyone.h:475