From 36ce07093b68b07513149577c209ae7a57ab356b Mon Sep 17 00:00:00 2001
From: Gabriele Contini <contini.mailing@gmail.com>
Date: 周日, 15 3月 2020 16:26:21 +0800
Subject: [PATCH] Merge branch 'feature/pc_identifiers' into develop issues #2 #3 #14 #49

---
 src/library/limits/license_verifier.cpp                  |   53 
 test/library/os_linux_test.cpp                           |   43 
 src/library/locate/ExternalDefinition.hpp                |    5 
 src/library/os/os.h                                      |   39 
 src/inspector/inspector.cpp                              |   91 +
 src/library/hw_identifier/CMakeLists.txt                 |   12 
 src/library/hw_identifier/hw_identifier.hpp              |   72 
 test/library/hw_identifier/ethernet_test.cpp             |   10 
 doc/analysis/Backoffice.md                               |    0 
 test/IdentificationStrategy_test.cpp                     |   10 
 test/library/os/execution_environment_test.cpp           |   48 
 CMakeLists.txt                                           |  102 
 doc/development/Build-the-library-windows.md             |    2 
 src/library/os/windows/isvm/Native.cpp                   |  438 +++++
 cmake/FindSphinx.cmake                                   |   53 
 src/templates/licensecc_properties.h.in                  |   67 
 CONTRIBUTING.md                                          |    3 
 doc/usage/License-retrieval.md                           |    3 
 doc/snippets.txt                                         |    7 
 src/library/os/windows/execution_environment.cpp         |   86 +
 src/library/hw_identifier/ethernet.hpp                   |   29 
 src/library/os/windows/isvm/Native.h                     |   18 
 src/library/os/linux/network.cpp                         |  125 +
 test/library/os/network_test.cpp                         |   50 
 doc/open-license-manager.vsdx                            |    0 
 src/library/licensecc.cpp                                |   59 
 src/library/locate/CMakeLists.txt                        |   22 
 src/library/os/linux/cpu_info.cpp                        |   76 
 test/functional/crack_test.cpp                           |   39 
 src/library/base/base64.cpp                              |  153 +
 src/library/locate/ExternalDefinition.cpp                |   63 
 doc/_static/googleae93b5a7f3766641.html                  |    0 
 doc/analysis/features.md                                 |   37 
 test/library/hw_identifier/hw_identifier_facade_test.cpp |  100 +
 src/library/os/windows/isvm/BIOSReader.cpp               |  121 +
 test/library/hw_identifier/hw_identifier_test.cpp        |   65 
 src/library/os/linux/os_linux.cpp                        |  100 -
 src/library/hw_identifier/hw_identifier.cpp              |   99 +
 test/library/CMakeLists.txt                              |   28 
 doc/development/Build-the-library.md                     |    2 
 .travis.yml                                              |   16 
 test/functional/standard-license_test.cpp                |   41 
 cmake/toolchain-ubuntu-mingw64.cmake                     |    4 
 src/library/os/windows/isvm/main.cpp                     |   51 
 doc/development/Development-Environment-Setup.md         |    2 
 src/library/os/windows/isvm/BIOSReader.h                 |   22 
 src/library/base/EventRegistry.cpp                       |    6 
 src/library/ini/ConvertUTF.cpp                           |    0 
 doc/usage/issue-licenses.md                              |    1 
 src/library/base/logger.cpp                              |    3 
 src/library/LicenseReader.hpp                            |    1 
 src/library/os/windows/signature_verifier.cpp            |   23 
 doc/other/CREDITS.md                                     |   33 
 src/library/hw_identifier/ethernet.cpp                   |   78 
 src/library/os/network.hpp                               |   32 
 src/library/hw_identifier/hw_identifier_facade.cpp       |   77 
 src/library/os/windows/network.cpp                       |  113 +
 src/library/hw_identifier/identification_strategy.hpp    |   43 
 src/library/locate/LocatorStrategy.cpp                   |    4 
 doc/conf.py                                              |  175 ++
 doc/development/Dependencies.md                          |    2 
 doc/api/public_api.rst                                   |    8 
 src/library/os/cpu_info.hpp                              |   39 
 doc/other/QA.md                                          |    2 
 doc/usage/integration.md                                 |    4 
 src/library/os/cpu_info_common.cpp                       |   45 
 test/functional/CMakeLists.txt                           |   40 
 src/library/os/openssl/signature_verifier.cpp            |   13 
 src/library/base/file_utils.hpp                          |    0 
 test/functional/hw_identifier_it_test.cpp                |   95 +
 src/library/locate/ApplicationFolder.cpp                 |    4 
 test/library/LicenseLocator_test.cpp                     |   25 
 doc/usage/Hardware-identifiers.md                        |   10 
 test/library/hw_identifier/CMakeLists.txt                |   16 
 README.md                                                |   23 
 src/library/os/signature_verifier.hpp                    |    4 
 test/library/os/CMakeLists.txt                           |   29 
 src/library/LicenseReader.cpp                            |    6 
 src/library/hw_identifier/disk_strategy.hpp              |   29 
 src/library/os/linux/execution_environment.cpp           |  115 +
 src/library/hw_identifier/hw_identifier_facade.hpp       |   38 
 src/library/hw_identifier/default_strategy.hpp           |   27 
 src/library/os/execution_environment_common.cpp          |   59 
 .gitignore                                               |    4 
 src/library/base/base64.h                                |   48 
 src/library/hw_identifier/identification_strategy.cpp    |   60 
 test/functional/generate-license.cpp                     |    2 
 doc/analysis/Development-And-Usage-Workflow.md           |   10 
 src/library/locate/EnvironmentVarData.cpp                |   19 
 src/inspector/CMakeLists.txt                             |    8 
 src/library/os/CMakeLists.txt                            |   44 
 doc/index.rst                                            |   50 
 src/library/base/CMakeLists.txt                          |   12 
 test/functional/signature_verifier_test.cpp              |    9 
 test/library/hw_identifier/disk_strategy_test.cpp        |   10 
 src/library/base/EventRegistry.h                         |    4 
 test/default_strategy_test.cpp                           |   10 
 src/library/os/execution_environment.hpp                 |   63 
 src/library/base/file_utils.cpp                          |    2 
 test/CMakeLists.txt                                      |    4 
 src/library/base/StringUtils.cpp                         |    2 
 test/library/os/cpu_info_test.cpp                        |   10 
 src/library/CMakeLists.txt                               |   28 
 test/functional/date_test.cpp                            |   17 
 doc/other/glossary.md                                    |    9 
 test/library/LicenseReader_test.cpp                      |   34 
 src/library/os/windows/cpu_info.cpp                      |   78 
 src/library/base/logger.h                                |    7 
 src/library/os/windows/os_win.cpp                        |  104 +
 /dev/null                                                |   85 -
 doc/snippets/hardware.cpp                                |  266 +++
 src/library/hw_identifier/disk_strategy.cpp              |   97 +
 src/library/locate/EnvironmentVarLocation.cpp            |    8 
 src/CMakeLists.txt                                       |    9 
 src/library/hw_identifier/default_strategy.cpp           |   77 
 doc/_static/pc-id-selection.png                          |    0 
 include/licensecc/datatypes.h                            |   93 
 include/licensecc/licensecc.h                            |   18 
 118 files changed, 4,321 insertions(+), 668 deletions(-)

diff --git a/.gitignore b/.gitignore
index 6f0748c..2d30086 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@
 
 #Visual studio files
 .vs
+/out
 
 # Compiled Static libraries
 *.lai
@@ -31,3 +32,6 @@
 projects/*
 !projects/.gitkeep
 
+**/CMakeCache.txt
+**/CMakeFiles
+/CMakeSettings.json
diff --git a/.travis.yml b/.travis.yml
index cac6349..eadfc70 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,6 +11,8 @@
    - os: linux
      dist: bionic
      name: "Ubuntu 18.04 - Travis CI VM"
+     env:
+     - VIRTUAL_ENV=VM
      addons:
         apt:
           packages:
@@ -51,6 +53,8 @@
    - os: linux
      dist: bionic
      name: "Ubuntu 18.04 - Travis CI VM - Debug build"
+     env:
+     - VIRTUAL_ENV=VM
      addons:
         apt:
           packages:
@@ -72,7 +76,6 @@
      script: 
          - cmake --build . --target install
          - ctest
-         - ctest -T memcheck
      after_success:
          # Create lcov report
          - lcov --capture --directory . --output-file coverage.info
@@ -80,7 +83,6 @@
          - lcov --list coverage.info # debug info
          # Uploading report to CodeCov
          - bash <(curl -s https://codecov.io/bash) -f coverage.info || echo "Codecov did not collect coverage reports"
-                  
    - os: linux
      dist: bionic
      name: "CentOS-7 Docker"
@@ -110,7 +112,7 @@
         - docker commit centos8_toconfigure centos8_configured
      script: 
         - docker run --name centos8_make -v `pwd`:/root/open-license-manager centos8_configured /bin/bash -c \
-            "cd /root/open-license-manager/build && make && make install && VIRT_ENV=CONTAINER make test"
+            "cd /root/open-license-manager/build && make && make install && VIRTUAL_ENV=DOCKER make test"
    - os: linux
      dist: bionic
      name: "Ubuntu 18.04 - MinGW cross-compile for Windows x64"
@@ -203,10 +205,12 @@
              - libboost-system-dev
              - libboost-thread-dev
              - libboost-date-time-dev
+             - python3-pip
              - doxygen
              - graphviz
      script: 
-        - make docs
+        - pip3 install sphinx sphinx_rtd_theme breathe sphinx-markdown-tables recommonmark sphinx-rtd-theme
+        - make documentation
      deploy:
         provider: pages
         skip_cleanup: true
@@ -214,11 +218,11 @@
         keep_history: false
         verbose: true
         target_branch: "gh-pages"
-        local_dir: "build/html"
+        local_dir: "build/docs/sphinx"
         on:
             branch: develop
 env:
-    - CTEST_OUTPUT_ON_FAILURE=1      
+    - CTEST_OUTPUT_ON_FAILURE=1
 before_script:
     - cd build && cmake -DCMAKE_INSTALL_PREFIX=../../install ..
 
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2b6812a..3c32f44 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -17,10 +17,11 @@
 ENDIF(NOT LCC_PROJECTS_BASE_DIR)
 
 cmake_policy(SET CMP0048 NEW)
+#cmake_policy(SET CMP0091 NEW)
 project (licensecc 
 			VERSION 2.0.0
 			DESCRIPTION "Copy protection and licensing library" 
-			LANGUAGES C CXX)
+			LANGUAGES CXX)
 
 set(CMAKE_CXX_STANDARD 11)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
@@ -34,22 +35,22 @@
 	SET(CMAKE_CROSSCOMPILING_EMULATOR "wine")	
 ENDIF()
 
-SET (OPENSSL_USE_STATIC_LIBS ON)
+SET (OPENSSL_USE_STATIC_LIBS TRUE)
+IF(${STATIC_RUNTIME})
+	SET(OPENSSL_MSVC_STATIC_RT TRUE)
+ENDIF(${STATIC_RUNTIME})
 find_package(OpenSSL COMPONENTS Crypto QUIET)
 IF(OPENSSL_FOUND)
-	MESSAGE(STATUS "Found openssl version ${OPENSSL_VERSION}")
+	MESSAGE(STATUS "Found openssl version ${OPENSSL_VERSION} -licensecc")
 ENDIF(OPENSSL_FOUND)
 
 if(UNIX) #this is true for all the linux systems but not for cross compiling "linux->windows"
+	IF(${STATIC_RUNTIME})
+		set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static")
+	ENDIF(${STATIC_RUNTIME})
 	IF(NOT OPENSSL_FOUND)
 		MESSAGE(SEND_ERROR "Openssl required in Linux, please install it or specify -DOPENSSL_ROOT")
 	ENDIF(NOT OPENSSL_FOUND)
-	
-	#Zlib required when openssl version < 1.0.1f (centos 7)
-	SET ( ZLIB_USE_STATIC_LIBS ON ) 
-	find_package(ZLIB REQUIRED)
-	list(APPEND EXTERNAL_LIBS ${ZLIB_LIBRARIES})
-	MESSAGE(STATUS "Found zlib version ${ZLIB_VERSION} ")
 	
     find_package(Threads)
 	if(THREADS_HAVE_PTHREAD_ARG)
@@ -59,17 +60,19 @@
   			 list(APPEND EXTERNAL_LIBS "${CMAKE_THREAD_LIBS_INIT}")
 		endif()
 	endif(THREADS_HAVE_PTHREAD_ARG)
+
+	#Zlib required with old openssl version < 1.0.1f in centos 7
+	IF(OPENSSL_VERSION VERSION_LESS_EQUAL 1.0.2)
+		SET ( ZLIB_USE_STATIC_LIBS ON ) 
+		find_package(ZLIB REQUIRED)
+		list(APPEND EXTERNAL_LIBS ${ZLIB_LIBRARIES})
+		MESSAGE(STATUS "Found zlib version ${ZLIB_VERSION_STRING} - licensecc")
+	ELSE(OPENSSL_VERSION VERSION_LESS_EQUAL 1.0.2)
+	    MESSAGE(STATUS "openssl ${OPENSSL_VERSION} zlib not required - licensecc")
+	ENDIF(OPENSSL_VERSION VERSION_LESS_EQUAL 1.0.2)
 	
 	find_program( MEMORYCHECK_COMMAND valgrind )
 	set( MEMORYCHECK_COMMAND_OPTIONS "--trace-children=yes --leak-check=full" )
-	
-	if(USE_DBUS_IDENTIFIER)
-	    FIND_PACKAGE(Dbus REQUIRED)
-	    add_definitions(-DUSE_DBUS)
-	    include_directories(${DBUS_INCLUDE_DIR})
-	    include_directories(${DBUS_ARCH_INCLUDE_DIR})
-	    list(APPEND EXTERNAL_LIBS ${DBUS_LIBRARIES})
-	endif(USE_DBUS_IDENTIFIER)  
 	set(main_lib_dest "lib/${PROJECT_NAME}")  
 else(UNIX)
 	IF(NOT OPENSSL_FOUND)
@@ -79,21 +82,20 @@
 		include(target_arch)
 		target_architecture( TARGET_ARCHITECTURE )
 		message(STATUS "architecture detected: ${TARGET_ARCHITECTURE}")
-		
 		#cmake > 3.15 handle the /MD flag more nicely than this
-		if(${STATIC_RUNTIME})
-			string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
+		if(STATIC_RUNTIME)
+		    message(STATUS "Static runtime ${STATIC_RUNTIME}")
 			string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
-			string(REPLACE "/MDd" "/MTd" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
 			string(REPLACE "/MDd" "/MTd" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
+			#list(APPEND CMAKE_CXX_FLAGS_DEBUG "/MTd")
 			SET(Boost_USE_STATIC_RUNTIME ON)
-		endif(${STATIC_RUNTIME})
-	
+		endif(STATIC_RUNTIME)
 		add_definitions("/D _CRT_SECURE_NO_WARNINGS")
+	    list(APPEND EXTERNAL_LIBS "bcrypt" "crypt32" "ws2_32" "iphlpapi")
 	else(MSVC)
-	    if(MINGW)
-	        list(APPEND EXTERNAL_LIBS "-lcrypt32 -lbcrypt -lws2_32 -liphlpapi")
-	        SET(CMAKE_EXE_LINKER_FLAGS "-static")
+	    if(MINGW)        
+            list(APPEND EXTERNAL_LIBS "-lbcrypt" "-lcrypt32" "-lws2_32" "-liphlpapi")
+	        SET(CMAKE_EXE_LINKER_FLAGS "-static -static-libstdc++")
 	    endif(MINGW)
 	endif(MSVC)
 	set(main_lib_dest "${PROJECT_NAME}")  
@@ -111,21 +113,19 @@
   COMMENT "generating ${LCC_PROJECT_PUBLIC_KEY}"
   USES_TERMINAL
 )
+include_directories( ${LCC_INCLUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/include" )
 add_custom_target(project_initialize DEPENDS "${LCC_PROJECT_PUBLIC_KEY}" "${LCC_PROJECT_PRIVATE_KEY}")
-include_directories( ${LCC_INCLUDE_DIR} ${CMAKE_BINARY_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/include")
 
-message( STATUS "C compiler        : " ${CMAKE_C_COMPILER})
-message( STATUS "C compiler flags  : " ${CMAKE_C_FLAGS})
-message( STATUS "CXX compiler      : " ${CMAKE_CXX_COMPILER})
-message( STATUS "CXX compiler flags: " ${CMAKE_CXX_FLAGS})
+message( STATUS "CXX compiler        : " ${CMAKE_CXX_COMPILER})
+message( STATUS "CXX compiler flags  : " ${CMAKE_CXX_FLAGS})
 message( STATUS "CXX compiler flags debug : " ${CMAKE_CXX_FLAGS_DEBUG})
 message( STATUS "CXX compiler flags release: " ${CMAKE_CXX_FLAGS_RELEASE})
 if(CMAKE_BUILD_TYPE)
-  message( STATUS "Build type        : " ${CMAKE_BUILD_TYPE})
+  message( STATUS "Build type          : " ${CMAKE_BUILD_TYPE})
 endif(CMAKE_BUILD_TYPE)
-message( STATUS "Install prefix    : " ${CMAKE_INSTALL_PREFIX})
-message( STATUS "Project name      : " ${LCC_PROJECT_NAME} )
-message( STATUS "Project base dir  : " ${LCC_PROJECTS_BASE_DIR}/${LCC_PROJECT_NAME} )
+message( STATUS "Install prefix      : " ${CMAKE_INSTALL_PREFIX})
+message( STATUS "Project name        : " ${LCC_PROJECT_NAME} )
+message( STATUS "Project base dir    : " ${LCC_PROJECTS_BASE_DIR}/${LCC_PROJECT_NAME} )
 
 add_subdirectory(src)
 
@@ -150,22 +150,44 @@
 		MARK_AS_ADVANCED(BUILDNAME)
 		add_subdirectory(test)
 	ENDIF(BUILD_TESTING)
+	add_subdirectory("src/inspector")
 ELSE(Boost_FOUND)
 	message(WARNING "Boost not found, disabling tests")
 ENDIF(Boost_FOUND)
 
+#################################
+# Documentation
+#################################
 find_package(Doxygen COMPONENTS dot)
-IF(Doxygen_FOUND)
+find_package(Sphinx)
+ 
+IF(Doxygen_FOUND AND Sphinx_FOUND)
     message(STATUS "Doxygen found, generating docs.")
     SET(DOXYGEN_EXCLUDE_PATTERNS "*/library/ini/*;*/doc/resources/*")
     SET(DOXYGEN_DISABLE_INDEX YES)
     SET(DOXYGEN_GENERATE_TREEVIEW YES)
+    SET(DOXYGEN_GENERATE_XML YES)
     SET(DOXYGEN_LAYOUT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/doc/DoxygenLayout.xml")
 	doxygen_add_docs(docs doc src include/licensecc COMMENT "doxygen docs")
-	file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/doc/resources/" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/html")
-ELSE(Doxygen_FOUND)
-	message(STATUS "Doxygen not found, not generating docs.")
-ENDIF(Doxygen_FOUND)
+	#file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/doc/resources/" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/html")
+	
+	#file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/doc/sphinx/" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
+	set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/doc)
+	set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/docs/sphinx)
+ 
+	add_custom_target(documentation
+                  COMMAND
+                  ${SPHINX_EXECUTABLE} -b html
+                  ${SPHINX_SOURCE} ${SPHINX_BUILD}
+                  -Dbreathe_projects.licensecc=${CMAKE_CURRENT_BINARY_DIR}/xml
+                  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+                  COMMENT "Generating documentation with Sphinx")
+    add_dependencies(documentation docs)
+    
+ELSE(Doxygen_FOUND AND Sphinx_FOUND)
+	message(STATUS "Doxygen or Sphynx not found, not generating docs.")
+ENDIF(Doxygen_FOUND AND Sphinx_FOUND)
+
 
 install(DIRECTORY ${LCC_INCLUDE_DIR} DESTINATION include/${PROJECT_NAME})
 install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ DESTINATION include)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ee6b617..636c98e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -4,7 +4,7 @@
 
 The following is a set of guidelines for contributing to Open License Manager and its packages, which are hosted in the [Open License Manager organization](https://github.com/open-license-manager) on GitHub. These are mostly guidelines, not rules. 
 
-## How to Contribute
+## How to contribute
 
 ### Interacting with the team 
 
@@ -90,3 +90,4 @@
 -   Very large pull requests with few comments, no corresponding issue explaining what's it about will probably be rejected.
     -  We understand that the project is still in beta stage, however we would like to discuss it with you before we take project changing decision. You can reach us on the [project forum](https://groups.google.com/forum/#!forum/licensecc). 
     -  Even it it's in beta stage it's used ( _by some really courageous people!_ ) in production. We can't break current functionality, user established habits without documenting the change.
+    
diff --git a/README.md b/README.md
index ced14cb..8124392 100644
--- a/README.md
+++ b/README.md
@@ -10,26 +10,25 @@
 [![codecov](https://codecov.io/gh/open-license-manager/open-license-manager/branch/develop/graph/badge.svg)](https://codecov.io/gh/open-license-manager/open-license-manager)
 [![Github Issues](https://img.shields.io/github/issues/open-license-manager/open-license-manager)](http://github.com/open-license-manager/open-license-manager/issues)
 
-Protect the software you develop from unauthorized copies,
-limit the usage in time, to a specific set of machines, or prevent the usage in 
-virtualized environments. It is an Open License Manager that helps to keep your 
-software closed :smirk: . A comprehensive [list of features](https://github.com/open-license-manager/open-license-manager/wiki/features), and their status is available in the project wiki.
+Protect the software you develop from unauthorized copies, limit the usage in time, to a specific set of 
+machines, or prevent the usage in  virtualized environments. It is an Open License Manager that helps to keep your 
+software closed :smirk: . Among other features if it runs on a "real hardware" it can generate a signature of that hardware and report if the signature doesn't match.
+
+A comprehensive [list of features](https://github.com/open-license-manager/open-license-manager/wiki/features), and their status is available in the project wiki. 
+
+If you plan to use this library or part of it remember to show us your appreciation giving it a 
+<a class="github-button" href="https://github.com/open-license-manager/open-license-manager" data-icon="octicon-star" aria-label="Star open-license-manager/open-license-manager on GitHub">star</a> here on GitHub.
 
 ## License
 The project is donated to the community. It comes with a very large freedom of use for everyone, and it will always be. 
 It uses a [BSD 3 clauses](https://opensource.org/licenses/BSD-3-Clause) licensing schema, that allows free modification and inclusion in commercial software. 
 
-If you plan to use the project or part of it consider showing us your appreciation placing a star here on github.
 ## Project Structure
-The software is made by 2 main sub-components:
+The software is made by 3 main sub-components:
 -   a C++ library with a nice C api, `licensecc` with minimal (or no) external dependencies (the part you have to integrate in your software) that is the project you're currently in.
--   a license generator lcc-license-generator `lcc` for customizing the library and generate the licenses.
+-   a license debugger `lcc-inspector` to be sent to the final customer when there are licensing problems or for calculating the pc hash before issuing the license.
+-   a license generator (github project [lcc-license-generator](https://github.com/open-license-manager/lcc-license-generator)) `lcc` for customizing the library and generate the licenses.
  
-The following modules are planned...
--   a license [backoffice](../../issues/7) in php (in order to handle multiple licenses).
--   a license debugger to be sent to the final customer when there are licensing problems.
--   a [log descriptor](../../issues/8) in order to decrypt logs generated by the license system.
-
 ## How to build
 Below an overview of the basic build procedure, you can find detailed instructions for [linux](https://github.com/open-license-manager/open-license-manager/wiki/Build-the-library) or [windows](https://github.com/open-license-manager/open-license-manager/wiki/Build-the-library-windows) in the wiki. 
 
diff --git a/cmake/FindSphinx.cmake b/cmake/FindSphinx.cmake
new file mode 100644
index 0000000..55c9f5a
--- /dev/null
+++ b/cmake/FindSphinx.cmake
@@ -0,0 +1,53 @@
+# - This module looks for Sphinx
+# Find the Sphinx documentation generator
+#
+# This modules defines
+# SPHINX_EXECUTABLE
+# SPHINX_FOUND
+find_program(SPHINX_EXECUTABLE
+  NAMES sphinx-build
+  PATHS
+    /usr/bin
+    /usr/local/bin
+    /opt/local/bin
+    ~/.local/bin
+  DOC "Sphinx documentation generator"
+)
+
+if( NOT SPHINX_EXECUTABLE )
+  set(_Python_VERSIONS
+    2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0 1.6 1.5
+  )
+  foreach( _version ${_Python_VERSIONS} )
+    set( _sphinx_NAMES sphinx-build-${_version} )
+    find_program( SPHINX_EXECUTABLE
+      NAMES ${_sphinx_NAMES}
+      PATHS
+        /usr/bin
+        /usr/local/bin
+        /opt/local/bin
+        ~/.local/bin
+      DOC "Sphinx documentation generator"
+    )
+  endforeach()
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Sphinx DEFAULT_MSG SPHINX_EXECUTABLE)
+mark_as_advanced(SPHINX_EXECUTABLE)
+
+function(Sphinx_add_target target_name builder conf source destination)
+
+  add_custom_target(${target_name} ALL
+    COMMAND ${SPHINX_EXECUTABLE} -b ${builder}
+    -c ${conf}
+    ${source}
+    ${destination}
+    COMMENT "Generating sphinx documentation: ${builder}"
+  )
+
+  set_property(DIRECTORY
+    APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${destination}
+  )
+
+endfunction()
diff --git a/cmake/toolchain-ubuntu-mingw64.cmake b/cmake/toolchain-ubuntu-mingw64.cmake
index ebac7f8..e257856 100644
--- a/cmake/toolchain-ubuntu-mingw64.cmake
+++ b/cmake/toolchain-ubuntu-mingw64.cmake
@@ -13,11 +13,15 @@
 set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
 set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
 set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
+set(CMAKE_CXX_LINK_EXECUTABLE ${TOOLCHAIN_PREFIX}-g++)
 
 # target environment on the build host system
 #   set 1st to dir with the cross compiler's C/C++ headers/libs
 set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
 
+#if(CMAKE_CROSSCOMPILING) #cross compiling for linux... a crazy bug on my system 
+#	link_directories(BEFORE /usr/lib/gcc/x86_64-w64-mingw32/7.3-win32)
+#endif(CMAKE_CROSSCOMPILING)
 # modify default behavior of FIND_XXX() commands to
 # search for headers/libs in the target environment and
 # search for programs in the build host environment
diff --git a/doc/Home.md b/doc/Home.md
deleted file mode 100644
index 54ddac4..0000000
--- a/doc/Home.md
+++ /dev/null
@@ -1 +0,0 @@
-Welcome to the open-license-manager wiki!
diff --git a/doc/resources/googleae93b5a7f3766641.html b/doc/_static/googleae93b5a7f3766641.html
similarity index 100%
rename from doc/resources/googleae93b5a7f3766641.html
rename to doc/_static/googleae93b5a7f3766641.html
diff --git a/doc/pc-id-selection.png b/doc/_static/pc-id-selection.png
similarity index 100%
rename from doc/pc-id-selection.png
rename to doc/_static/pc-id-selection.png
Binary files differ
diff --git a/doc/Backoffice.md b/doc/analysis/Backoffice.md
similarity index 100%
rename from doc/Backoffice.md
rename to doc/analysis/Backoffice.md
diff --git a/doc/Development-And-Usage-Workflow.md b/doc/analysis/Development-And-Usage-Workflow.md
similarity index 89%
rename from doc/Development-And-Usage-Workflow.md
rename to doc/analysis/Development-And-Usage-Workflow.md
index bd44e5f..6cd5528 100644
--- a/doc/Development-And-Usage-Workflow.md
+++ b/doc/analysis/Development-And-Usage-Workflow.md
@@ -1,3 +1,5 @@
+# Development and usage workflow
+
 Below a description of the planned development and usage process. Comments and progress are reported on [issue #42](https://github.com/open-license-manager/open-license-manager/issues/42)
 
 ![dev-build-process](https://user-images.githubusercontent.com/1121667/64474031-e5afff80-d1a0-11e9-9819-f3b7e4e2126d.png)
@@ -8,7 +10,7 @@
 
 ### Binary release contents
 Binary release contains: 
- * open-license-manager executable (merge of the actual `license_generator` executable and `bootstrap`).
+ * open-license-manager executable (`lcc`).
  * source code of the unconfigured library.
  * source code of (part of) the tests.
  
@@ -18,7 +20,7 @@
 In this phase the library is configured, compiled (only for the tests sake), linked with a mock executable and tested together with the license generator.
 
 ## Initialize library
-In this phase the signing keys are generated by open-license-manager executable (`olm`), and optionally the source code of the library may be modified or obfuscated.
+In this phase the signing keys are generated by open-license-manager executable (`lcc`), and optionally the source code of the library may be modified or obfuscated.
 
 ### Test (2)
 
@@ -30,6 +32,6 @@
  * If we want to link the execution to a specific hardware we need to send the product to the client without a license (or a demo executable, with the sole intent to generate the machine identifier). 
  * If we just want to send a demo product with an expiry date we prepare a license without the machine identifier.
  
-# Build process
-From the process described above, (strange to say) the license generator (`olm`) configures itself as a build 
+## Build process
+From the process described above, (strange to say) the license generator (`lcc`) configures itself as a build 
 dependency of the licensing library, thus it needs to be built first.
\ No newline at end of file
diff --git a/doc/features.md b/doc/analysis/features.md
similarity index 90%
rename from doc/features.md
rename to doc/analysis/features.md
index 06141ae..1872ce5 100644
--- a/doc/features.md
+++ b/doc/analysis/features.md
@@ -1,5 +1,6 @@
-# General features:
+# Features:
 
+## features and their status
 | Feature                              | Implementation status | 
 |--------------------------------------|:---------------------:|
 | Trial license with expiry date       | :heavy_check_mark:    |
@@ -11,38 +12,38 @@
 | Java/C# bindings                     | Planned               |
 | Floating/network licenses            | Planned               |
 
-## Issue a "demo" license with only expiry date.
+### Issue a "demo" license with only expiry date.
 Software editors often want to release a trial license that is not linked to a specified machine, but just limit the usage in time or to some other feature (number of cpu, process memory).
 See [execution limits](Implemented/Planned execution limits) section.
 
-## Licenses linked to "physical" hardware id
+### Licenses linked to "physical" hardware id
 Link the software to a physical hardware (a pc). In this scenario the software editor wants his software to be executed on a specific piece of hardware. We suppose the operating system is installed "bare to metal" and we're able to calculate an identifier of that hardware. This isn't always true for virtualized environments for which alternative strategies must be planned [eg. floating licenses (not yet implemented)]. See the section on [hardware identifiers](hardware-identifiers) for a detailed discussion of the use cases.
 
 Depending on the situation there are are different kinds of hardware id that can be used. See [execution limits](Implemented/Planned execution limits) section.
 
-## Virtual machine detection
+### Virtual machine detection
 Detect if the software is running in a virtualized environment and (optionally) forbid the execution. This is useful if software editors want to prevent the execution in virtual machines (lxc/dockers...) and be able to compute a meaningful hardware id. 
 Another use case is the software is to be used only in a specific class of virtualized environments. For instance it was initially packaged as a docker image, the software editor don't want it to be "extracted" and placed elsewhere.
 
-## License retrieval
+### License retrieval
 Open License Manager, when integrated into a licensed software will find its license file based on many different strategies.
 It can handle multiple licenses at the same time. See the wiki page about [license retrieval](license-retrieval) for details.
  
-## Licensed software features (partially implemented)
+### Licensed software features (partially implemented)
 A licensed software may be composed by many features (functions) each one activable independently. Licensing system tells the licensed software which features are enabled, and which features are disabled.
  
-## License Management (planned)
-It is necessary to keep track of the licenses that have been issued, of the clients, and their pc identifier. 
+### License Management (planned)
+It is necessary to keep track of the licenses that have been issued, of the clients, and their hardware identifier. 
 A web application is planned that will provide integration with payment systems to allow licensed software customers to buy licenses.
 
-## Customizable execution limits (planned)
+### Customizable execution limits (planned)
 It should be easy to add and implement your own "execution limit": that is require/forbid some feature in the application execution environment.
 
-## Java/C# bindings (planned)
+### Java/C# bindings (planned)
 The application should support bindings to java language. The library has to be compiled as a .dll for use with JNI or C# integration layer. This is especially challenging on the api side.
 Since the api is public, and the library is packaged as a separate .dll/.so everybody can compile a version of it always returning LICENSE_OK easily defeating the license schema. 
 
-## Floating licenses (planned)
+### Floating licenses (planned)
 Limit the execution of the licensed software to a certain number of instances per license. 
 This can be done in multiple ways:
 	* without a central server, using broadcast or scanning the local network to find peers.
@@ -51,7 +52,7 @@
 
 Status of this implementation is tracked in [issue #4](https://github.com/open-license-manager/open-license-manager/issues/4)
 
-# Implemented/Planned execution limits
+## Implemented/Planned execution limits
 Open License Manager can limit execution of licensed software based on some criteria, called "execution limits".
 Depending on the execution environment some criteria may not be applicable:
 
@@ -69,22 +70,20 @@
 | concurrent execution | Planned | Planned | Planned | Planned |
 | licensed sw version | Planned       | Planned            | Planned            | Planned            |
 
-## Date
+### Date
 This is the most common limit set on a license, allow the software to expire after the defined date.
 
-## Disk label/Disk id
+### Disk label/Disk id
 It is possible to limit the execution to a computer that has a certain disk connected.
 This kind of limitation doesn't make sense in linux containerized environments.
 
-## Cpu Number/Machine memory
+### Cpu Number/Machine memory
 Allow to restrict the execution only to a machine with the specified amount of cpu or memory or less. This is useful in virtualized environments, to create a licensed software demo version with limited performaces or with limited scalability.
 
 Status of this implementation is tracked in [issue #4](https://github.com/open-license-manager/open-license-manager/issues/4)
 
-## Virtualization type
+### Virtualization type
 Allow the execution of the licensed software only on some type of hardware or virtualized environment eg. only bare to metal, only in virtual machine, only in docker.
 
-## Licensed software version
+### Licensed software version
 A licensed software may declare a version (eg 1.0.0). A license may span multiple releases of the software e.g. allow version 1.1.1 but not 2.0.0.
-
-# 
\ No newline at end of file
diff --git a/doc/api/public_api.rst b/doc/api/public_api.rst
new file mode 100644
index 0000000..051e84f
--- /dev/null
+++ b/doc/api/public_api.rst
@@ -0,0 +1,8 @@
+
+
+
+Documentation
+==================
+.. doxygennamespace:: license
+   :project: licensecc
+   :members:
\ No newline at end of file
diff --git a/doc/conf.py b/doc/conf.py
new file mode 100644
index 0000000..13f61aa
--- /dev/null
+++ b/doc/conf.py
@@ -0,0 +1,175 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# licensecc documentation build configuration file, created by
+# sphinx-quickstart on Sat Mar 14 13:43:01 2020.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+# import os
+# import sys
+# sys.path.insert(0, os.path.abspath('.'))
+
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = ['sphinx.ext.todo',
+    'sphinx.ext.githubpages', 'breathe', 'recommonmark', 'sphinx_markdown_tables', 'sphinx_rtd_theme' ]
+
+# Breathe Configuration
+breathe_default_project = "licensecc"
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+#
+# source_suffix = ['.rst', '.md']
+source_suffix = ['.rst', '.md']
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = 'licensecc'
+copyright = '2020, Open License Manager'
+author = 'Open License Manager'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '2.0.0'
+# The full version, including alpha/beta/rc tags.
+release = '2.0.0'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This patterns also effect to html_static_path and html_extra_path
+exclude_patterns = []
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = True
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'sphinx_rtd_theme'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#
+html_theme_options = {
+  'titles_only': False
+}
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Custom sidebar templates, must be a dictionary that maps document names
+# to template names.
+#
+# This is required for the alabaster theme
+# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
+#html_sidebars = {
+#    '**': [
+#        'relations.html',  # needs 'show_related': True theme option to display
+#        'searchbox.html',
+#    ]
+#}
+
+
+# -- Options for HTMLHelp output ------------------------------------------
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'licenseccdoc'
+
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+    # The paper size ('letterpaper' or 'a4paper').
+    #
+    # 'papersize': 'letterpaper',
+
+    # The font size ('10pt', '11pt' or '12pt').
+    #
+    # 'pointsize': '10pt',
+
+    # Additional stuff for the LaTeX preamble.
+    #
+    # 'preamble': '',
+
+    # Latex figure (float) alignment
+    #
+    # 'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+#  author, documentclass [howto, manual, or own class]).
+latex_documents = [
+    (master_doc, 'licensecc.tex', 'licensecc Documentation',
+     'Open License Manager', 'manual'),
+]
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    (master_doc, 'licensecc', 'licensecc Documentation',
+     [author], 1)
+]
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+    (master_doc, 'licensecc', 'licensecc Documentation',
+     author, 'licensecc', 'One line description of project.',
+     'Miscellaneous'),
+]
+
+
+
diff --git a/doc/Build-the-library-windows.md b/doc/development/Build-the-library-windows.md
similarity index 98%
rename from doc/Build-the-library-windows.md
rename to doc/development/Build-the-library-windows.md
index 264bb02..e3e015f 100644
--- a/doc/Build-the-library-windows.md
+++ b/doc/development/Build-the-library-windows.md
@@ -1,4 +1,4 @@
-@ingroup  group_02
+# Windows
 
 This page describes how to build the library. It's a good starting point if you just downloaded it and you want to start explore.
 
diff --git a/doc/Build-the-library.md b/doc/development/Build-the-library.md
similarity index 99%
rename from doc/Build-the-library.md
rename to doc/development/Build-the-library.md
index 8241630..974a1d6 100644
--- a/doc/Build-the-library.md
+++ b/doc/development/Build-the-library.md
@@ -1,5 +1,3 @@
-@ingroup  group_01
-
 # Linux
 
 ## Install prerequisites
diff --git a/doc/Dependencies.md b/doc/development/Dependencies.md
similarity index 99%
rename from doc/Dependencies.md
rename to doc/development/Dependencies.md
index f004b19..3fd54e6 100644
--- a/doc/Dependencies.md
+++ b/doc/development/Dependencies.md
@@ -1,3 +1,5 @@
+# Dependencies
+
 This page describes the dependencies of open-license-manager and the supported build environments.
 
 Dependencies varies with the environment, if you're building the library for the first time we suggest you download or set up one of the supported environments to be sure not to incur in dependency/compiler errors (you can use virtual machines , docker or lxc/lxd technologies).
diff --git a/doc/Development-Environment-Setup.md b/doc/development/Development-Environment-Setup.md
similarity index 97%
rename from doc/Development-Environment-Setup.md
rename to doc/development/Development-Environment-Setup.md
index da8a265..9a71cd5 100644
--- a/doc/Development-Environment-Setup.md
+++ b/doc/development/Development-Environment-Setup.md
@@ -1,4 +1,4 @@
-
+# Developer's environment setup
 This guide is just an help in case you haven't decided your development environment or your development environment match ours. 
 We don't have any specific dependency on development tools, you can choose the one you prefer. Though if you want to contribute
 you're required to  format the code using `clang-format` before you submit the pull request.
diff --git a/doc/index.rst b/doc/index.rst
new file mode 100644
index 0000000..e26f190
--- /dev/null
+++ b/doc/index.rst
@@ -0,0 +1,50 @@
+
+Welcome to licensecc's documentation.
+=====================================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
+   
+.. toctree::
+   :glob:
+   :maxdepth: 2
+   :hidden:
+   :caption: Build the library:
+  
+   development/*
+
+.. toctree::
+   :glob:
+   :maxdepth: 2
+   :hidden:
+   :caption: Integrate and use:
+  
+   usage/*
+   
+
+.. toctree::
+   :glob:
+   :maxdepth: 2
+   :hidden:
+   :caption: API:
+  
+   api/*
+      
+.. toctree::
+   :glob:
+   :maxdepth: 2
+   :hidden:
+   :caption: Analysis:
+  
+   analysis/*
+
+.. toctree::
+   :glob:
+   :maxdepth: 2
+   :hidden:
+   :caption: Miscellaneous:
+  
+   other/*
+   
diff --git a/doc/open-license-manager.vsdx b/doc/open-license-manager.vsdx
new file mode 100644
index 0000000..fd83390
--- /dev/null
+++ b/doc/open-license-manager.vsdx
Binary files differ
diff --git a/doc/other/CREDITS.md b/doc/other/CREDITS.md
new file mode 100644
index 0000000..221ff1d
--- /dev/null
+++ b/doc/other/CREDITS.md
@@ -0,0 +1,33 @@
+# Credits 
+The following open source code has been used in OpenLicenseManager. 
+Thanks to every one of the authors of such projects. Without you open license manager would never have been completed.  
+
+
+## isVM
+Thanks for the great smbios parsing code. It saved me days.
+
+isvm : https://github.com/0of/isvm
+
+The MIT License (MIT)
+
+Copyright (c) 2015 Magnus
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
diff --git a/doc/QA.md b/doc/other/QA.md
similarity index 99%
rename from doc/QA.md
rename to doc/other/QA.md
index d993a81..d3093dd 100644
--- a/doc/QA.md
+++ b/doc/other/QA.md
@@ -1,3 +1,5 @@
+# Q&A
+
 ## Development
 Development related questions.
 
diff --git a/doc/Basic-concepts.md b/doc/other/glossary.md
similarity index 76%
rename from doc/Basic-concepts.md
rename to doc/other/glossary.md
index 0cde5da..9234d31 100644
--- a/doc/Basic-concepts.md
+++ b/doc/other/glossary.md
@@ -1,12 +1,13 @@
-#Basic concepts and terminology
+# Glossary
 
-##Project
+Some `common` word that recur into the documentation have a specific meaning. Below an explanation of the terms and concepts used.
+ 
+## Project
 A project corresponds to one application where the licensing system need to be integrated.
 Each project has its own private key and its own folder where `licensecc` is compiled. 
 Currently we support only one project per (build) machine. This is especially true in Windows, where the private key has the same name for all the projects.
 
-##Features
+## Features
 Features let licensed application to selectively enable or disable functions in the application, features are part of the original license, they do not have hardware identifications, they only have validity date. 
 
 
-#Customizing the build
diff --git a/doc/snippets.txt b/doc/snippets.txt
index b5ce841..537187c 100644
--- a/doc/snippets.txt
+++ b/doc/snippets.txt
@@ -18,4 +18,9 @@
 		echo "Boost installed"
 		cd C:/local/boost
 		dir
-) else echo "Boost already installed"
\ No newline at end of file
+) else echo "Boost already installed"
+
+linux cross compile for windows openssl
+
+ ./Configure no-zlib no-shared --prefix=$PWD/dist-win-64 --cross-compile-prefix=x86_64-w64-mingw32- mingw64
+ /usr/local/bin/cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchain-ubuntu-mingw64.cmake -DCMAKE_INSTALL_PREFIX=../../install -DBOOST_ROOT=$PWD/../../boost_1_69_0/dist-win-x64/ -DOPENSSL_ROOT_DIR=$PWD/../../openssl-OpenSSL_1_1_1d/dist-win-64/ -DBoost_ARCHITECTURE="-x64" -DCMAKE_CXX_COMPILER_ARCHITECTURE_ID="x64" -DCMAKE_SH="CMAKE_SH-NOTFOUND" -DCMAKE_VERBOSE_MAKEFILE=ON  -DLOGS_DISABLED=ON ..
\ No newline at end of file
diff --git a/doc/snippets/hardware.cpp b/doc/snippets/hardware.cpp
new file mode 100644
index 0000000..bf4e0be
--- /dev/null
+++ b/doc/snippets/hardware.cpp
@@ -0,0 +1,266 @@
+/*********************  physical_processors.cpp   *****************************
+* Author:        Agner Fog
+* Date created:  2019-10-29
+* Last modified: 2019-11-25
+* Version:       1.02 beta
+* Project:       vector class library
+* Description:   Detect number of physical and logical processors on CPU chip.
+*                Compile for C++11 or later
+*
+* (c) Copyright 2019 Agner Fog.
+* Apache License version 2.0 or later.
+*******************************************************************************
+Some modern CPUs can run two threads in each CPU core when simultaneous 
+multithreading (SMT, called hyperthreading by Intel) is enabled.
+
+The number of physical processors is the number of CPU cores.
+The number of logical processors is the same number multiplied by the number of
+threads that can run simultaneously in each CPU core.
+
+Simultaneous multithreading will slow down performance when two CPU-intensive 
+threads running in the same physical processor (CPU core) are competing for the
+same resources. Therefore, the optimal number of threads for CPU-intensive
+tasks is most likely to be the number of physical processors. 
+
+Tasks that are less CPU-intensive but limited by RAM access, disk access, 
+network, etc. may get an advantage by running as many threads as the number of
+logical processors. This will be double the number of physical processors when
+simultaneous multithreading is enabled.
+
+The physicalProcessors function detects the number of physical processors and
+logical processors on an x86 computer. This is useful for determining the 
+optimal number of threads.
+
+
+Note: There are several problems in detecting the number of physical processors:
+
+1. The CPUID instruction on Intel CPUs will return a wrong number of logical
+   processors when SMT (hyperthreading) is disabled. It may be necessary to 
+   compare the number of processors returned by the CPUID instruction with the
+   number of processors reported by the operating system to detect if SMT is 
+   enabled (AMD processors do not have this problem).
+
+2. It is necessary to rely on system functions to detect if there is more than 
+   one CPU chip installed. It is assumed that the status of SMT is the same on
+   all CPU chips in a system.
+
+3. The behavior of VIA processors is undocumented.
+   
+4. This function is not guaranteed to work on future CPUs. It may need updating
+   when new CPUs with different configurations or different CPUID functionality
+   appear.
+******************************************************************************/
+
+#include <thread>     // std::thread functions
+
+#ifdef _MSC_VER
+#include <intrin.h>   // __cpuidex intrinsic function available on microsoft compilers
+#endif
+
+// Define interface to CPUID instruction.
+// input:  leaf = eax, subleaf = ecx
+// output: output[0] = eax, output[1] = ebx, output[2] = ecx, output[3] = edx
+static inline void cpuid(int output[4], int leaf, int subleaf = 0) {
+#if defined(__GNUC__) || defined(__clang__)      // use inline assembly, Gnu/AT&T syntax
+    int a, b, c, d;
+    __asm("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "a"(leaf), "c"(subleaf) : );
+    output[0] = a;
+    output[1] = b;
+    output[2] = c;
+    output[3] = d;
+
+#elif defined (_MSC_VER)                         // Microsoft compiler, intrin.h included
+    __cpuidex(output, leaf, subleaf);            // intrinsic function for CPUID
+
+#else                                            // unknown platform. try inline assembly with masm/intel syntax
+    __asm {
+        mov eax, leaf
+        mov ecx, subleaf
+        cpuid;
+        mov esi, output
+        mov[esi], eax
+        mov[esi + 4], ebx
+        mov[esi + 8], ecx
+        mov[esi + 12], edx
+    }
+#endif
+}
+
+// Function prototype:
+int physicalProcessors(int * logical_processors = 0);
+
+
+// Find the number of physical and logical processors supported by CPU
+// Parameter: 
+// logical_processors: an optional pointer to an integer that will receive the number of logical processors.
+// Return value: number of physical processors
+int physicalProcessors(int * logical_processors) {
+    int vendor = 0;                              // CPU vendor: 1 = Intel, 2 = AMD, 3 = VIA, 0 = other
+    int logicalProc = 1;                         // number of logical processor cores
+    int physicalProc = 1;                        // number of physical processor cores
+    int procPerCore = 1;                         // logical cores per physical core
+    bool hyperthreadingSupported = false;        // CPU supports hyperthreading / simultaneous multithreading
+    int systemProcessors = std::thread::hardware_concurrency(); // number of processors reported by operating system
+
+    int abcd[4] = { 0,0,0,0 };                   // CPUID output
+    cpuid(abcd, 0);                              // CPUID function 0
+
+    int maxLeaf = abcd[0];                       // maximum eax input for CPUID
+    if (abcd[2] == 0x6C65746E) {                 // last 4 chars of "GenuineIntel"
+        vendor = 1;
+    }
+    else if (abcd[2] == 0x444D4163) {            // last 4 chars of "AuthenticAMD"
+        vendor = 2;
+    }
+    else if (abcd[2] == 0x736C7561) {            // last 4 chars of "CentaurHauls"
+        vendor = 3;
+    }
+
+    if (maxLeaf >= 1) {
+        cpuid(abcd, 1);
+        if (abcd[3] & (1 << 28)) {               // hyperthreading supported
+            hyperthreadingSupported = true;
+        }
+    }
+
+    if (vendor == 1) {
+        //////////////////
+        //    Intel     //
+        //////////////////
+
+        int hyper = 0;                           // hyperthreading status: 0 = unknown, 1 = disabled, 2 = enabled
+        if (maxLeaf >= 0xB) {                    // leaf 0xB or 0x1F: Extended Topology Enumeration
+            int num = 0xB;
+            // if (maxLeaf >= 0x1F) num = 0x1F;
+
+            for (int c = 0; c < 5; c++) {
+                cpuid(abcd, num, c);             // enumeration level c
+                int type = (abcd[2] >> 8) & 0xFF;// enumeration type at level c
+                if (type == 1) {                 // SMT level
+                    procPerCore = abcd[1] & 0xFFFF;
+                }
+                else if (type >= 2) {            // core level
+                    logicalProc = abcd[1] & 0xFFFF;
+                }
+                else if (type == 0) break;
+                // There are more types/levels to consider if we use num = 0x1F. We may need  
+                // to fix this in the future if CPUs with more complex configurations appear
+            }
+            physicalProc = logicalProc / procPerCore;
+
+            // The number of performance monitor registers depends on hyperthreading status
+            // on Intel CPUs with performance monitoring version 3 or 4
+            cpuid(abcd, 0xA, 0);                 // performance monitor counters information
+            int perfVersion = abcd[0] & 0xFF;    // performance monitoring version
+            int perfNum = (abcd[0] >> 8) & 0xFF; // number of performance monitoring registers
+            if (perfVersion == 3 || perfVersion == 4) {
+                if (perfNum == 4) {
+                    hyper = 2;                   // 4 performance registers when hyperthreading enabled
+                }
+                else if (perfNum == 8) {         // 8 performance registers when hyperthreading disabled
+                    hyper = 1;
+                    procPerCore = 1;
+                    logicalProc = physicalProc;  // reduce the number of logical processors when hyperthreading is disabled
+                }
+                // hyper remains 0 in all other cases, indicating unknown status
+            }
+        }
+        else if (maxLeaf >= 4) {                 // CPUID function 4: cache parameters and cores
+            cpuid(abcd, 4);
+            logicalProc = (abcd[0] >> 26) + 1;
+            if (hyperthreadingSupported) {
+                // number of logical processors per core is not known. Assume 2 if hyperthreading supported
+                procPerCore = 2;
+            }
+            physicalProc = logicalProc / procPerCore;
+        }
+        else {
+            // no information. Assume 1 processor
+        }
+        if (systemProcessors > logicalProc) {
+            // Multiple CPU chips. Assume that chips are identical with respect to hypethreading
+            physicalProc = systemProcessors * physicalProc / logicalProc;
+            logicalProc = systemProcessors;
+        }
+        else if (logicalProc > systemProcessors && systemProcessors > 0 && hyper == 0) {
+            // Hyperthreading is disabled
+            logicalProc = systemProcessors;
+            physicalProc = systemProcessors;        
+        }
+    }
+    else if (vendor == 2) {
+
+        //////////////////
+        //    AMD       //
+        //////////////////
+
+        cpuid(abcd, 0x80000000);                 // AMD specific CPUID functions
+        int maxLeaf8 = abcd[0] & 0xFFFF;         // maximum eax 0x8000.... input for CPUID
+
+        if (maxLeaf8 >= 8) {
+            cpuid(abcd, 0x80000008);
+            logicalProc = (abcd[2] & 0xFF) + 1;
+
+            if (maxLeaf8 >= 0x1E) {
+                cpuid(abcd, 0x8000001E);
+                procPerCore = ((abcd[1] >> 8) & 0x03) + 1;
+                // procPerCore = 2 if simultaneous multithreading is enabled, 1 if disabled
+            }
+            else {
+                if (hyperthreadingSupported) {
+                    procPerCore = 2;
+                }
+                else {
+                    procPerCore = 1;
+                }
+            }
+            physicalProc = logicalProc / procPerCore;
+        }
+        else if (hyperthreadingSupported) {
+            // number of logical processors per core is not known. Assume 2 if SMT supported
+            logicalProc = 2;
+            physicalProc = 1;
+        }
+        if (systemProcessors > logicalProc) {
+            // Multiple CPU chips. Assume that chips are identical with respect to SMT
+            physicalProc = systemProcessors * physicalProc / logicalProc;
+            logicalProc = systemProcessors;
+        }
+    }
+    else {
+    
+        //////////////////////////////
+        //    VIA or unknown CPU    //
+        //////////////////////////////
+
+        // The behavior of VIA processors is undocumented! It is not known how to detect threads on a VIA processor
+        physicalProc = logicalProc = systemProcessors;
+        if (hyperthreadingSupported && physicalProc > 1) {
+            physicalProc /= 2;
+        }
+    }
+    if (logical_processors) {
+        // return logical_processors if pointer is not null
+        *logical_processors = logicalProc;
+    }
+    return physicalProc;
+}
+
+/* Uncomment this for testing:
+
+#include <stdio.h>
+
+int main() {
+
+    int logicalProc = 0;
+    int physicalProc = physicalProcessors(&logicalProc); 
+
+    printf("\nlogical processors: %i",  logicalProc);
+    printf("\nphysical processors: %i", physicalProc);
+    printf("\nlogical processors per core: %i", logicalProc / physicalProc);
+    int sysproc = std::thread::hardware_concurrency();
+    printf("\nsystem processors: %i", sysproc); 
+
+    return 0;
+}
+*/
\ No newline at end of file
diff --git a/doc/Hardware-identifiers.md b/doc/usage/Hardware-identifiers.md
similarity index 82%
rename from doc/Hardware-identifiers.md
rename to doc/usage/Hardware-identifiers.md
index 1967f3f..1767c07 100644
--- a/doc/Hardware-identifiers.md
+++ b/doc/usage/Hardware-identifiers.md
@@ -1,5 +1,8 @@
+# Hardware Identifiers
+
 ## Use cases
-Linking the execution of a software to a. With the recent coming of virtualized environments the installation of software directly on the machine has been less and less.
+Linking the execution of a software to a physical hardware (a pc). With the recent coming of virtualized environments 
+the installation of software directly on the machine has been less and less.
 
 OpenLicenseManager guess the environment where the user is trying to launch the software, and reports it to the software publisher when he is generating a license in a way that he can decide how to limit the usage on per license basis.
 
@@ -7,7 +10,7 @@
 This is straightforward case. If the software is executing on a physical hardware it is possible to identify the hardware by various parameters (cpu type/memory/disk label/mac address)
 
 ### Execution in a virtual machine
-Generating a pc identifier on a virtual machine doesn't make much sense, since the vm can be copied as a whole elsewhere 
+Generating a hardware identifier on a virtual machine doesn't make much sense, since the vm can be copied as a whole elsewhere 
 and there are few ways to detect this without using an external license server.
 
 *   Usually when the machine is copied the MAC address is changed. But sometimes it changes on its own. Software publishers may want to use this as a last resort to prevent the vm for being cloned. It has to be verified case by case.
@@ -22,4 +25,5 @@
 
 
 If the licensed software specify the parameter
-If the licensed software uses `STRATEGY_DEFAULT` and the strategy generates an unstable identifier it is possible to ask the user to set t 
+If the licensed software uses `STRATEGY_DEFAULT` and the strategy generates an unstable identifier it is possible to ask the user to 
+set the environemnt variable.
diff --git a/doc/License-retrieval.md b/doc/usage/License-retrieval.md
similarity index 97%
rename from doc/License-retrieval.md
rename to doc/usage/License-retrieval.md
index 8f4605c..08110bb 100644
--- a/doc/License-retrieval.md
+++ b/doc/usage/License-retrieval.md
@@ -1,4 +1,5 @@
-# License retrieval
+# Place the license file
+
 Open License Manager, when integrated into a licensed software can automatically find its license file (or multiple license files) based on:
  
  * An environment variable: 
diff --git a/doc/Integration.md b/doc/usage/integration.md
similarity index 94%
rename from doc/Integration.md
rename to doc/usage/integration.md
index f721be3..4274185 100644
--- a/doc/Integration.md
+++ b/doc/usage/integration.md
@@ -1,3 +1,5 @@
+# Integrate license in your application
+
 This short guide explain how to integrate `open-license-manager` in your application.
 
 Working examples are provided in the [examples](https://github.com/open-license-manager/examples) project. 
@@ -6,7 +8,7 @@
 The file containing the public api is `include/licensecc/licensecc.h`. Functions in there are considered stable.
 
 
-### Print a pc identifier
+### Print a hardware identifier
 
 ```CPP
 bool identify_pc(IDENTIFICATION_STRATEGY pc_id_method, char* identifier_out, size_t bufSize);
diff --git a/doc/Issue-licenses.md b/doc/usage/issue-licenses.md
similarity index 98%
rename from doc/Issue-licenses.md
rename to doc/usage/issue-licenses.md
index 8a9e7cf..06bf828 100644
--- a/doc/Issue-licenses.md
+++ b/doc/usage/issue-licenses.md
@@ -1,3 +1,4 @@
+# Issue licenses
 
 The easiest way to issue licenses is to enter the project library and create the following project structure:
 The projects folder can be anyware. We created one in `open-license-manager/projects` for your convenience (and for testing purposes). A default project<sup>1</sup> named `DEFAULT` has been created for you when you configured the project with cmake.
diff --git a/include/licensecc/datatypes.h b/include/licensecc/datatypes.h
index c058630..f9da78a 100644
--- a/include/licensecc/datatypes.h
+++ b/include/licensecc/datatypes.h
@@ -25,16 +25,7 @@
 #define DllExport __declspec(dllexport)
 #endif
 
-// define api structure sizes
-#define PC_IDENTIFIER_SIZE 19
-#define PROPRIETARY_DATA_SIZE 16
-#define AUDIT_EVENT_NUM 5
-#define AUDIT_EVENT_PARAM2 255
-#define VERSION_SIZE 15
-#define PROJECT_NAME_SIZE 15
-#define EXPIRY_DATE_SIZE 10
-
-#define ERROR_BUFFER_SIZE 256
+#include <licensecc_properties.h>
 
 typedef enum {
 	LICENSE_OK = 0,  // OK
@@ -44,32 +35,48 @@
 	FILE_FORMAT_NOT_RECOGNIZED = 4,  // license file has invalid format (not .ini file)
 	LICENSE_MALFORMED = 5,  // some mandatory field are missing, or data can't be fully read.
 	PRODUCT_NOT_LICENSED = 6,  // this product was not licensed
-	PRODUCT_EXPIRED = 7,
+	PRODUCT_EXPIRED = 7,    //!< PRODUCT_EXPIRED
 	LICENSE_CORRUPTED = 8,  // License signature didn't match with current license
 	IDENTIFIERS_MISMATCH = 9,  // Calculated identifier and the one provided in license didn't match
 
 	LICENSE_SPECIFIED = 100,  // license location was specified
 	LICENSE_FOUND = 101,  // License file has been found or license data has been located
 	PRODUCT_FOUND = 102,  // License has been loaded and the declared product has been found
-	SIGNATURE_VERIFIED = 103
-} EVENT_TYPE;
+	SIGNATURE_VERIFIED = 103//!< SIGNATURE_VERIFIED
+} LCC_EVENT_TYPE;
 
 typedef enum {
-	LOCAL,
-	REMOTE  // remote licenses are not supported now.
-} LICENSE_TYPE;
+	LCC_LOCAL,
+	LCC_REMOTE  // remote licenses are not supported now.
+} LCC_LICENSE_TYPE;
 
-typedef enum { SVRT_INFO, SVRT_WARN, SVRT_ERROR } SEVERITY;
+typedef enum { SVRT_INFO, SVRT_WARN, SVRT_ERROR } LCC_SEVERITY;
 
 typedef struct {
-	SEVERITY severity;
-	EVENT_TYPE event_type;
+	LCC_SEVERITY severity;
+	LCC_EVENT_TYPE event_type;
 	/**
 	 * License file name or location where the license is stored.
 	 */
 	char license_reference[MAX_PATH];
-	char param2[AUDIT_EVENT_PARAM2 + 1];
+	char param2[LCC_API_AUDIT_EVENT_PARAM2 + 1];
 } AuditEvent;
+
+typedef enum {
+	/**
+	 * A list of absolute path separated by ';' containing the eventual location
+	 * of the license files. Can be NULL.
+	 */
+	LICENSE_PATH,
+	/**
+	 * The license is provided as plain data
+	 */
+	LICENSE_PLAIN_DATA,
+	/**
+	 * The license is encoded
+	 */
+	LICENSE_ENCODED
+} LCC_LICENSE_DATA_TYPE;
 
 /**
  * This structure contains informations on the raw license data. Software authors
@@ -79,61 +86,45 @@
  * license file location on its own.
  */
 typedef struct {
-	/**
-	 * A list of absolute path separated by ';' containing the eventual location
-	 * of the license files. Can be NULL.
-	 */
-	const char *licenseFileLocation;
-	/**
-	 * The application can provide the full license content through this string.
-	 * It can be both in encoded form (base64) or in plain. It's optional.
-	 */
-	const char *licenseData;
+	LCC_LICENSE_DATA_TYPE license_data_type;
+	char licenseData[LCC_API_MAX_LICENSE_DATA_LENGTH];
 } LicenseLocation;
+
 /**
  * Informations on the software requiring the license
  */
 typedef struct {
-	char version[VERSION_SIZE + 1];  // software version in format xxxx.xxxx.xxxx
-	char project_name[PROJECT_NAME_SIZE + 1];  // name of the project (must correspond to the name in the license)
-	uint32_t magic;  // reserved
+	char version[LCC_API_VERSION_LENGTH + 1];  // software version in format xxxx[.xxxx.xxxx] //TODO
+	char project_name[LCC_API_PROJECT_NAME_SIZE + 1];  // name of the project (must correspond to the name in the license)
+	/**
+	 * this number passed in by the application must correspond to the magic number used when compiling the library.
+	 * See cmake parameter -DLCC_PROJECT_MAGIC_NUM and licensecc_properties.h macro VERIFY_MAGIC
+	 */
+	unsigned int magic;
 } CallerInformations;
+
 typedef struct {
 	/**
 	 * Detailed reason of success/failure. Reasons for a failure can be
 	 * multiple (for instance, license expired and signature not verified).
 	 * Only the last AUDIT_EVENT_NUM are reported.
 	 */
-	AuditEvent status[AUDIT_EVENT_NUM];
+	AuditEvent status[LCC_API_AUDIT_EVENT_NUM];
 	/**
 	 * Eventual expiration date of the software,
 	 * can be '\0' if the software don't expire
 	 * */
-	char expiry_date[EXPIRY_DATE_SIZE + 1];
+	char expiry_date[LCC_API_EXPIRY_DATE_SIZE + 1];
 	unsigned int days_left;
 	bool has_expiry;
 	bool linked_to_pc;
-	LICENSE_TYPE license_type;  // Local or Remote
+	LCC_LICENSE_TYPE license_type;  // Local or Remote
 	/* A string of character inserted into the license understood
 	 * by the calling application.
 	 * '\0' if the application didn't specify one */
-	char proprietary_data[PROPRIETARY_DATA_SIZE + 1];
+	char proprietary_data[LCC_API_PROPRIETARY_DATA_SIZE + 1];
 	int license_version;  // license file version
 } LicenseInfo;
-
-/**
- * Enum to select a specific pc identification_strategy. DEFAULT Should be used
- * in most cases.
- */
-typedef enum {
-	STRATEGY_DEFAULT,
-	STRATEGY_ETHERNET,
-	STRATEGY_IP_ADDRESS,
-	STRATEGY_DISK_NUM,
-	STRATEGY_DISK_LABEL,
-	STRATEGY_PLATFORM_SPECIFIC,
-	STRATEGY_UNKNOWN
-} IDENTIFICATION_STRATEGY;
 
 #ifdef __cplusplus
 }
diff --git a/include/licensecc/licensecc.h b/include/licensecc/licensecc.h
index 950fe0f..0b0391c 100644
--- a/include/licensecc/licensecc.h
+++ b/include/licensecc/licensecc.h
@@ -11,20 +11,22 @@
 extern "C" {
 #endif
 
+#include <licensecc_properties.h>
+
 #include "datatypes.h"
 
-/*
+/**
  * Method used to convert the LicenseInfo into a human readable
- * representation. //not yet implemented
+ * representation.
  */
-void print_error(char out_buffer[ERROR_BUFFER_SIZE], LicenseInfo* licenseInfo);
+void print_error(char out_buffer[LCC_API_ERROR_BUFFER_SIZE], LicenseInfo* licenseInfo);
 
 /**
- * This method calculates the pc identifier. The string need to be shown to the user and given back to the software
+ * This method calculates the hardware identifier. The string need to be shown to the user and given back to the software
  * editor when issuing a license.
  *  pc_id_method = STRATEGY_DEFAULT usually works.
  */
-bool identify_pc(IDENTIFICATION_STRATEGY pc_id_method, char* identifier_out, size_t* bufSize);
+bool identify_pc(LCC_API_IDENTIFICATION_STRATEGY pc_id_method, char* identifier_out, size_t* bufSize);
 
 /**
  * This method is used to request the use of one license for a product.
@@ -39,7 +41,7 @@
  * @param license[out] optional, can be NULL, if set it will return extra informations about the license.
  */
 
-EVENT_TYPE acquire_license(const CallerInformations* callerInformation, const LicenseLocation* licenseLocation,
+LCC_EVENT_TYPE acquire_license(const CallerInformations* callerInformation, const LicenseLocation* licenseLocation,
 						   LicenseInfo* license_out);
 
 /**
@@ -47,11 +49,11 @@
  * Should be called from time to time to confirm we're still using the
  * license.
  */
-EVENT_TYPE confirm_license(char* featureName, LicenseLocation* licenseLocation);
+LCC_EVENT_TYPE confirm_license(char* featureName, LicenseLocation* licenseLocation);
 /**
  * Do nothing for now, useful for network licenses.
  */
-EVENT_TYPE release_license(char* featureName, LicenseLocation licenseLocation);
+LCC_EVENT_TYPE release_license(char* featureName, LicenseLocation licenseLocation);
 
 #ifdef __cplusplus
 }
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 02e47aa..6c4253f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,7 +1,10 @@
-add_subdirectory("library")
+IF (NOT LCC_PROJECT_MAGIC_NUM) 
+	set(LCC_PROJECT_MAGIC_NUM 0)  
+ENDIF (NOT LCC_PROJECT_MAGIC_NUM)
 
-#for no reason overwrite it (maybe it's manually customized)
 IF(NOT EXISTS "${LCC_INCLUDE_DIR}/licensecc_properties.h")
 	configure_file ("templates/licensecc_properties.h.in" 
 		"${LCC_INCLUDE_DIR}/licensecc_properties.h")
-ENDIF(NOT EXISTS "${LCC_INCLUDE_DIR}/licensecc_properties.h")
\ No newline at end of file
+ENDIF(NOT EXISTS "${LCC_INCLUDE_DIR}/licensecc_properties.h")
+
+add_subdirectory("library")
\ No newline at end of file
diff --git a/src/inspector/CMakeLists.txt b/src/inspector/CMakeLists.txt
new file mode 100644
index 0000000..c8ff618
--- /dev/null
+++ b/src/inspector/CMakeLists.txt
@@ -0,0 +1,8 @@
+
+ADD_EXECUTABLE(inspector inspector.cpp )
+
+target_link_libraries(inspector 
+     licensecc_static
+ 	 Boost::unit_test_framework 
+     Boost::filesystem
+     Boost::system)
\ No newline at end of file
diff --git a/src/inspector/inspector.cpp b/src/inspector/inspector.cpp
new file mode 100644
index 0000000..5608ebb
--- /dev/null
+++ b/src/inspector/inspector.cpp
@@ -0,0 +1,91 @@
+#include <iostream>
+#include <map>
+#include <unordered_map>
+#include <licensecc/licensecc.h>
+#include <fstream>
+#include "../library/os/cpu_info.hpp"
+#include "../library/os/execution_environment.hpp"
+
+using namespace std;
+using namespace license::os;
+
+const map<int, string> stringByStrategyId = {{STRATEGY_DEFAULT, "DEFAULT"},
+											 {STRATEGY_ETHERNET, "MAC"},
+											 {STRATEGY_IP_ADDRESS, "IP"},
+											 {STRATEGY_DISK_NUM, "Disk1"},
+											 {STRATEGY_DISK_LABEL, "Disk2"}};
+
+const unordered_map<int, string> descByVirtDetail = {{BARE_TO_METAL, "No virtualization"},
+													 {VMWARE, "Vmware"},
+													 {VIRTUALBOX, "Virtualbox"},
+													 {V_XEN, "XEN"},
+													 {KVM, "KVM"},
+													 {HV, "Microsoft Hypervisor"},
+													 {V_OTHER, "Other type of vm"}};
+
+const unordered_map<int, string> descByVirt = {
+	{VIRTUALIZATION::NONE, "No virtualization"}, {VIRTUALIZATION::VM, "VM"}, {VIRTUALIZATION::CONTAINER, "Container"}};
+
+const unordered_map<int, string> stringByEventType = {
+	{LICENSE_OK, "OK "},
+	{LICENSE_FILE_NOT_FOUND, "license file not found "},
+	{LICENSE_SERVER_NOT_FOUND, "license server can't be contacted "},
+	{ENVIRONMENT_VARIABLE_NOT_DEFINED, "environment variable not defined "},
+	{FILE_FORMAT_NOT_RECOGNIZED, "license file has invalid format (not .ini file) "},
+	{LICENSE_MALFORMED, "some mandatory field are missing, or data can't be fully read. "},
+	{PRODUCT_NOT_LICENSED, "this product was not licensed "},
+	{PRODUCT_EXPIRED, "license expired "},
+	{LICENSE_CORRUPTED, "license signature didn't match with current license "},
+	{IDENTIFIERS_MISMATCH, "Calculated identifier and the one provided in license didn't match"}};
+
+static LCC_EVENT_TYPE verifyLicense(const string& fname) {
+	LicenseInfo licenseInfo;
+	LicenseLocation licLocation = {LICENSE_PATH};
+	std::copy(fname.begin(), fname.end(), licLocation.licenseData);
+	LCC_EVENT_TYPE result = acquire_license(nullptr, &licLocation, &licenseInfo);
+	if (result == LICENSE_OK) {
+		cout << "license OK" << endl;
+	} else {
+		cerr << stringByEventType.find(result)->second << endl;
+	}
+
+	return result;
+}
+
+int main(int argc, char* argv[]) {
+	license::os::CpuInfo cpu;
+	cout << "Cpu Vendor      :" << cpu.vendor() << endl;
+	cout << "Cpu Brand       :" << cpu.brand() << endl;
+	cout << "Cpu is hypervis.:" << cpu.cpu_virtual() << endl;
+	cout << "Cpu model       :0x" << std::hex << ((long)cpu.model()) << std::dec << endl;
+	cout << "Virt. detail cpu:" << descByVirtDetail.find(cpu.virtualization_details())->second << endl <<endl;
+	ExecutionEnvironment execEnv;
+	cout << "Running in cloud:" << execEnv.is_cloud() << endl;
+	cout << "Docker          :" << execEnv.is_docker() << endl;
+	cout << "other container :" << execEnv.is_container() << endl;
+	cout << "Virtualiz. class:" << descByVirt.find(execEnv.getVirtualization())->second << endl;
+
+	cout << "Bios vendor     :" << execEnv.bios_vendor() << endl;
+	cout << "Bios description:" << execEnv.bios_description() << endl;
+	cout << "System vendor   :" << execEnv.sys_vendor() << endl <<endl;
+
+	char hw_identifier[LCC_API_PC_IDENTIFIER_SIZE + 1];
+	size_t bufSize = LCC_API_PC_IDENTIFIER_SIZE + 1;
+	for (const auto& x : stringByStrategyId) {
+		if (identify_pc(static_cast<LCC_API_IDENTIFICATION_STRATEGY>(x.first), hw_identifier, &bufSize)) {
+			std::cout << x.second << ':' << hw_identifier << std::endl;
+		} else {
+			std::cout << x.second << ": NA" << endl;
+		}
+	}
+
+	if (argc == 2) {
+		const string fname(argv[1]);
+		ifstream license_file(fname);
+		if (license_file.good()) {
+			verifyLicense(fname);
+		} else {
+			cerr << "license file :" << fname << " not found." << endl;
+		}
+	}
+}
diff --git a/src/library/CMakeLists.txt b/src/library/CMakeLists.txt
index a9f75d8..f174976 100644
--- a/src/library/CMakeLists.txt
+++ b/src/library/CMakeLists.txt
@@ -1,30 +1,44 @@
 add_subdirectory("base")
+add_subdirectory("os")
+add_subdirectory("locate")
+add_subdirectory("hw_identifier")
 
 ADD_LIBRARY(licensecc_static STATIC
     licensecc.cpp
     LicenseReader.cpp
-    pc-identifiers.c
     limits/license_verifier.cpp
-    ini/ConvertUTF.c
+    ini/ConvertUTF.cpp
+    $<TARGET_OBJECTS:hw_identifier>
+    $<TARGET_OBJECTS:locate>
+    $<TARGET_OBJECTS:os>
+    $<TARGET_OBJECTS:base>
 )
 
-add_subdirectory("locate")
-add_subdirectory("os")
+if(CODE_COVERAGE AND UNIX)
+	  if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
+	    target_link_options(licensecc_static PUBLIC --coverage)
+	  endif()
+	  list(APPEND EXTERNAL_LIBS gcov)
+endif(CODE_COVERAGE AND UNIX)
 
 define_property(TARGET PROPERTY WITH_OPENSSL BRIEF_DOCS "need openssl to compile" FULL_DOCS "ff")
 IF(UNIX OR OPENSSL_FOUND)
 	target_compile_definitions(licensecc_static PUBLIC HAS_OPENSSL)
 	set_target_properties(licensecc_static PROPERTIES WITH_OPENSSL 1)
-	target_link_libraries(licensecc_static PUBLIC base OpenSSL::Crypto ${EXTERNAL_LIBS} ${CMAKE_DL_LIBS})
+	target_link_libraries(licensecc_static PUBLIC OpenSSL::Crypto ${EXTERNAL_LIBS} ${CMAKE_DL_LIBS})
 ELSE(UNIX OR OPENSSL_FOUND)
 	set_target_properties(licensecc_static PROPERTIES WITH_OPENSSL 0)
-	target_link_libraries(licensecc_static PUBLIC base ${EXTERNAL_LIBS})
+	target_link_libraries(licensecc_static PUBLIC ${EXTERNAL_LIBS})
 ENDIF(UNIX OR OPENSSL_FOUND)
 
+#set_property(TARGET licensecc_static PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
+
 target_include_directories(licensecc_static
-    INTERFACE 
+    PUBLIC 
         $<INSTALL_INTERFACE:include>
+        $<INSTALL_INTERFACE:include/${PROJECT_NAME}/${LCC_PROJECT_NAME}>
         $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../include>
+        $<BUILD_INTERFACE:${LCC_INCLUDE_DIR}>
 )
 
 add_library(licensecc::licensecc_static ALIAS licensecc_static)
diff --git a/src/library/LicenseReader.cpp b/src/library/LicenseReader.cpp
index 7390f3c..673bb1d 100644
--- a/src/library/LicenseReader.cpp
+++ b/src/library/LicenseReader.cpp
@@ -22,12 +22,9 @@
 #include <stdlib.h>
 #include <math.h>
 
-#include <public_key.h>
-#include <licensecc_properties.h>
 #include <licensecc/licensecc.h>
 
 #include "base/base.h"
-#include "pc-identifiers.h"
 #include "LicenseReader.hpp"
 #include "base/StringUtils.h"
 #include "base/logger.h"
@@ -39,7 +36,8 @@
 FullLicenseInfo::FullLicenseInfo(const string &source, const string &product, const string &license_signature)
 	: source(source),
 	  m_project(product),  //
-	  license_signature(license_signature) {}
+	  license_signature(license_signature),
+	  m_magic(0) {}
 
 LicenseReader::LicenseReader(const LicenseLocation *licenseLocation) : licenseLocation(licenseLocation) {}
 
diff --git a/src/library/LicenseReader.hpp b/src/library/LicenseReader.hpp
index bad939e..854a0d6 100644
--- a/src/library/LicenseReader.hpp
+++ b/src/library/LicenseReader.hpp
@@ -24,6 +24,7 @@
 	const std::string license_signature;
 	const std::string source;
 	const std::string m_project;
+	unsigned int m_magic;
 	std::map<std::string, std::string> m_limits;
 
 	FullLicenseInfo(const std::string& source, const std::string& product, const std::string& license_signature);
diff --git a/src/library/base/CMakeLists.txt b/src/library/base/CMakeLists.txt
index 3582cae..c92b37f 100644
--- a/src/library/base/CMakeLists.txt
+++ b/src/library/base/CMakeLists.txt
@@ -1,9 +1,9 @@
-ADD_LIBRARY(base STATIC
+ADD_LIBRARY(base OBJECT
     EventRegistry.cpp
     StringUtils.cpp
-    FileUtils.cpp
-    logger.c
-    base64.c
+    file_utils.cpp
+    base64.cpp
+    logger.cpp
 )
 
 if(CODE_COVERAGE AND UNIX)
@@ -13,10 +13,6 @@
 	    -g         # generate debug info
 	    --coverage # sets all required flags
 	  )
-	  target_link_libraries(base PUBLIC gcov)
 endif(CODE_COVERAGE AND UNIX)
 
-add_dependencies( base project_initialize )
-
-install(TARGETS base EXPORT licensecc ARCHIVE DESTINATION lib/${PROJECT_NAME}/${LCC_PROJECT_NAME})
 
diff --git a/src/library/base/EventRegistry.cpp b/src/library/base/EventRegistry.cpp
index 920e735..ed0f074 100644
--- a/src/library/base/EventRegistry.cpp
+++ b/src/library/base/EventRegistry.cpp
@@ -17,7 +17,7 @@
 namespace license {
 using namespace std;
 
-const map<EVENT_TYPE, int> PROGRESS_BY_EVENT_TYPE = {
+const map<LCC_EVENT_TYPE, int> PROGRESS_BY_EVENT_TYPE = {
 	{LICENSE_SPECIFIED, 0}, {LICENSE_FOUND, 1}, {PRODUCT_FOUND, 2}, {SIGNATURE_VERIFIED, 3}, {LICENSE_OK, 4}};
 
 EventRegistry::EventRegistry() { current_validation_step = -1; }
@@ -73,11 +73,11 @@
 	return result;
 }
 
-void EventRegistry::addEvent(EVENT_TYPE event, const std::string &licenseLocationId) {
+void EventRegistry::addEvent(LCC_EVENT_TYPE event, const std::string &licenseLocationId) {
 	addEvent(event, licenseLocationId.c_str(), nullptr);
 }
 
-void EventRegistry::addEvent(EVENT_TYPE event, const char *licenseLocationId, const char *info) {
+void EventRegistry::addEvent(LCC_EVENT_TYPE event, const char *licenseLocationId, const char *info) {
 	AuditEvent audit;
 	auto eventIterator = PROGRESS_BY_EVENT_TYPE.find(event);
 	bool successEvent = (eventIterator != PROGRESS_BY_EVENT_TYPE.end());
diff --git a/src/library/base/EventRegistry.h b/src/library/base/EventRegistry.h
index 23a53a5..38b44d0 100644
--- a/src/library/base/EventRegistry.h
+++ b/src/library/base/EventRegistry.h
@@ -52,8 +52,8 @@
 	 * @return NULL if no failures are found.
 	 */
 	const AuditEvent *getLastFailure() const;
-	void addEvent(EVENT_TYPE event, const std::string &licenseLocationId);
-	void addEvent(EVENT_TYPE event, const char *licenseLocationId = nullptr, const char *info = nullptr);
+	void addEvent(LCC_EVENT_TYPE event, const std::string &licenseLocationId);
+	void addEvent(LCC_EVENT_TYPE event, const char *licenseLocationId = nullptr, const char *info = nullptr);
 	void exportLastEvents(AuditEvent *auditEvents, int nlogs);
 };
 }  // namespace license
diff --git a/src/library/base/StringUtils.cpp b/src/library/base/StringUtils.cpp
index b09cdfe..1d5d27b 100644
--- a/src/library/base/StringUtils.cpp
+++ b/src/library/base/StringUtils.cpp
@@ -28,7 +28,7 @@
 		++it;
 	}
 	std::string::const_reverse_iterator rit = string_to_trim.rbegin();
-	while (rit.base() != it && isspace(*rit)) {
+	while (rit.base() != it && (isspace(*rit) || *rit == 0)) {
 		++rit;
 	}
 	return std::string(it, rit.base());
diff --git a/src/library/base/base64.c b/src/library/base/base64.c
deleted file mode 100644
index 1e1ea5b..0000000
--- a/src/library/base/base64.c
+++ /dev/null
@@ -1,134 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-
-const static char* b64 =
-		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-// maps A=>0,B=>1..
-const static unsigned char unb64[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //10
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //30
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //40
-		0, 0, 0, 62, 0, 0, 0, 63, 52, 53, //50
-		54, 55, 56, 57, 58, 59, 60, 61, 0, 0, //60
-		0, 0, 0, 0, 0, 0, 1, 2, 3, 4, //70
-		5, 6, 7, 8, 9, 10, 11, 12, 13, 14, //80
-		15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //90
-		25, 0, 0, 0, 0, 0, 0, 26, 27, 28, //100
-		29, 30, 31, 32, 33, 34, 35, 36, 37, 38, //110
-		39, 40, 41, 42, 43, 44, 45, 46, 47, 48, //120
-		49, 50, 51, 0, 0, 0, 0, 0, 0, 0, //130
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //140
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //150
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //160
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //170
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //180
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //190
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //200
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //210
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //220
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //230
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //240
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //250
-		0, 0, 0, 0, 0, 0, }; // This array has 255 elements
-
-//review api
-char* base64(const void* binaryData, int len, int *flen) {
-	const unsigned char* bin = (const unsigned char*) binaryData;
-	char* res;
-
-	int rc = 0; // result counter
-	int byteNo; // I need this after the loop
-
-	int modulusLen = len % 3;
-	int pad = ((modulusLen & 1) << 1) + ((modulusLen & 2) >> 1); // 2 gives 1 and 1 gives 2, but 0 gives 0.
-
-	*flen = 4 * (len + pad) / 3;
-	res = (char*) malloc(*flen + 1); // and one for the null
-	if (!res) {
-		puts("ERROR: base64 could not allocate enough memory.");
-		puts("I must stop because I could not get enough");
-		return 0;
-	}
-
-	for (byteNo = 0; byteNo <= len - 3; byteNo += 3) {
-		unsigned char BYTE0 = bin[byteNo];
-		unsigned char BYTE1 = bin[byteNo + 1];
-		unsigned char BYTE2 = bin[byteNo + 2];
-		res[rc++] = b64[BYTE0 >> 2];
-		res[rc++] = b64[((0x3 & BYTE0) << 4) + (BYTE1 >> 4)];
-		res[rc++] = b64[((0x0f & BYTE1) << 2) + (BYTE2 >> 6)];
-		res[rc++] = b64[0x3f & BYTE2];
-	}
-
-	if (pad == 2) {
-		res[rc++] = b64[bin[byteNo] >> 2];
-		res[rc++] = b64[(0x3 & bin[byteNo]) << 4];
-		res[rc++] = '=';
-		res[rc++] = '=';
-	} else if (pad == 1) {
-		res[rc++] = b64[bin[byteNo] >> 2];
-		res[rc++] = b64[((0x3 & bin[byteNo]) << 4) + (bin[byteNo + 1] >> 4)];
-		res[rc++] = b64[(0x0f & bin[byteNo + 1]) << 2];
-		res[rc++] = '=';
-	}
-
-	res[rc] = 0; // NULL TERMINATOR! ;)
-	return res;
-}
-
-//FIXME! 
-unsigned char* unbase64(const char* ascii, int len, int *flen) {
-	const unsigned char *safeAsciiPtr = (const unsigned char*) ascii;
-	unsigned char *bin;
-	int cb = 0;
-	int charNo;
-	int pad = 0;
-
-	if (len < 2) { // 2 accesses below would be OOB.
-		// catch empty string, return NULL as result.
-		puts(
-				"ERROR: You passed an invalid base64 string (too short). You get NULL back.");
-		*flen = 0;
-		return 0;
-	}
-	if (safeAsciiPtr[len - 1] == '=')
-		++pad;
-	if (safeAsciiPtr[len - 2] == '=')
-		++pad;
-
-	*flen = 3 * len / 4 - pad;
-	bin = (unsigned char*) malloc(*flen);
-	if (!bin) {
-		puts("ERROR: unbase64 could not allocate enough memory.");
-		puts("I must stop because I could not get enough");
-		return 0;
-	}
-
-	for (charNo = 0; charNo <= len - 4 - pad; charNo += 4) {
-		int A = unb64[safeAsciiPtr[charNo]];
-		int B = unb64[safeAsciiPtr[charNo + 1]];
-		int C = unb64[safeAsciiPtr[charNo + 2]];
-		int D = unb64[safeAsciiPtr[charNo + 3]];
-
-		bin[cb++] = (A << 2) | (B >> 4);
-		bin[cb++] = (B << 4) | (C >> 2);
-		bin[cb++] = (C << 6) | (D);
-	}
-
-	if (pad == 1) {
-		int A = unb64[safeAsciiPtr[charNo]];
-		int B = unb64[safeAsciiPtr[charNo + 1]];
-		int C = unb64[safeAsciiPtr[charNo + 2]];
-
-		bin[cb++] = (A << 2) | (B >> 4);
-		bin[cb++] = (B << 4) | (C >> 2);
-	} else if (pad == 2) {
-		int A = unb64[safeAsciiPtr[charNo]];
-		int B = unb64[safeAsciiPtr[charNo + 1]];
-
-		bin[cb++] = (A << 2) | (B >> 4);
-	}
-
-	return bin;
-}
diff --git a/src/library/base/base64.cpp b/src/library/base/base64.cpp
new file mode 100644
index 0000000..f508d4a
--- /dev/null
+++ b/src/library/base/base64.cpp
@@ -0,0 +1,153 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <algorithm>
+
+#include "base64.h"
+namespace license {
+using namespace std;
+
+const static char* b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+// maps A=>0,B=>1..
+const static unsigned char unb64[] = {
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 10
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 20
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 30
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 40
+	0,  0,  0,  62, 0,  0,  0,  63, 52, 53,  // 50
+	54, 55, 56, 57, 58, 59, 60, 61, 0,  0,  // 60
+	0,  0,  0,  0,  0,  0,  1,  2,  3,  4,  // 70
+	5,  6,  7,  8,  9,  10, 11, 12, 13, 14,  // 80
+	15, 16, 17, 18, 19, 20, 21, 22, 23, 24,  // 90
+	25, 0,  0,  0,  0,  0,  0,  26, 27, 28,  // 100
+	29, 30, 31, 32, 33, 34, 35, 36, 37, 38,  // 110
+	39, 40, 41, 42, 43, 44, 45, 46, 47, 48,  // 120
+	49, 50, 51, 0,  0,  0,  0,  0,  0,  0,  // 130
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 140
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 150
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 160
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 170
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 180
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 190
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 200
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 210
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 220
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 230
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 240
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 250
+	0,  0,  0,  0,  0,  0,
+};  // This array has 255 elements
+
+// review api
+void add_CR_if_needed(string& encodeBuffer, int lineLenght) {
+	if (lineLenght > 0 && ((encodeBuffer.size() + 1) % lineLenght) == 0) {
+		encodeBuffer += '\n';
+	}
+}
+
+string base64(const void* binaryData, size_t len, int lineLenght) {
+	const unsigned char* bin = (const unsigned char*)binaryData;
+
+	int rc = 0;  // result counter
+	int byteNo;  // I need this after the loop
+
+	int modulusLen = len % 3;
+	int pad = ((modulusLen & 1) << 1) + ((modulusLen & 2) >> 1);  // 2 gives 1 and 1 gives 2, but 0 gives 0.
+
+	const size_t flen = 4 * (len + pad) / 3;
+	size_t totalLength = flen;
+	if (lineLenght > 0) {
+		totalLength += ((int)flen / lineLenght) + 3;
+	}
+
+	string encodeBuffer;
+	encodeBuffer.reserve(totalLength);
+
+	for (byteNo = 0; byteNo <= len - 3; byteNo += 3) {
+		unsigned char BYTE0 = bin[byteNo];
+		unsigned char BYTE1 = bin[byteNo + 1];
+		unsigned char BYTE2 = bin[byteNo + 2];
+
+		add_CR_if_needed(encodeBuffer, lineLenght);
+		encodeBuffer += b64[BYTE0 >> 2];
+		add_CR_if_needed(encodeBuffer, lineLenght);
+		encodeBuffer += b64[((0x3 & BYTE0) << 4) + (BYTE1 >> 4)];
+		add_CR_if_needed(encodeBuffer, lineLenght);
+		encodeBuffer += b64[((0x0f & BYTE1) << 2) + (BYTE2 >> 6)];
+		add_CR_if_needed(encodeBuffer, lineLenght);
+		encodeBuffer += b64[0x3f & BYTE2];
+	}
+
+	if (pad == 2) {
+		add_CR_if_needed(encodeBuffer, lineLenght);
+		encodeBuffer += b64[bin[byteNo] >> 2];
+		add_CR_if_needed(encodeBuffer, lineLenght);
+		encodeBuffer += b64[(0x3 & bin[byteNo]) << 4];
+		add_CR_if_needed(encodeBuffer, lineLenght);
+		encodeBuffer += '=';
+		add_CR_if_needed(encodeBuffer, lineLenght);
+		encodeBuffer += '=';
+	} else if (pad == 1) {
+		add_CR_if_needed(encodeBuffer, lineLenght);
+		encodeBuffer += b64[bin[byteNo] >> 2];
+		add_CR_if_needed(encodeBuffer, lineLenght);
+		encodeBuffer += b64[((0x3 & bin[byteNo]) << 4) + (bin[byteNo + 1] >> 4)];
+		add_CR_if_needed(encodeBuffer, lineLenght);
+		encodeBuffer += b64[(0x0f & bin[byteNo + 1]) << 2];
+		add_CR_if_needed(encodeBuffer, lineLenght);
+		encodeBuffer += '=';
+	}
+	if (lineLenght && encodeBuffer[encodeBuffer.length() - 1] != '\n') {
+		encodeBuffer += '\n';
+	}
+	return encodeBuffer;
+}
+
+std::vector<uint8_t> unbase64(const std::string& base64_data) {
+	string tmp_str(base64_data);
+	tmp_str.erase(std::remove(tmp_str.begin(), tmp_str.end(), '\n'), tmp_str.end());
+	const unsigned char* safeAsciiPtr = (const unsigned char*)tmp_str.c_str();
+	std::vector<uint8_t> bin;
+	int cb = 0;
+	int charNo;
+	int pad = 0;
+	size_t len = tmp_str.size();
+
+	if (len < 2) {  // 2 accesses below would be OOB.
+		// catch empty string, return NULL as result.
+		puts("ERROR: You passed an invalid base64 string (too short). You get NULL back.");
+		return bin;
+	}
+	if (safeAsciiPtr[len - 1] == '=') ++pad;
+	if (safeAsciiPtr[len - 2] == '=') ++pad;
+
+	size_t flen = 3 * len / 4 - pad;
+	bin.reserve(flen);
+
+	for (charNo = 0; charNo <= len - 4 - pad; charNo += 4) {
+		int A = unb64[safeAsciiPtr[charNo]];
+		int B = unb64[safeAsciiPtr[charNo + 1]];
+		int C = unb64[safeAsciiPtr[charNo + 2]];
+		int D = unb64[safeAsciiPtr[charNo + 3]];
+
+		bin.push_back((A << 2) | (B >> 4));
+		bin.push_back((B << 4) | (C >> 2));
+		bin.push_back((C << 6) | (D));
+	}
+
+	if (pad == 1) {
+		int A = unb64[safeAsciiPtr[charNo]];
+		int B = unb64[safeAsciiPtr[charNo + 1]];
+		int C = unb64[safeAsciiPtr[charNo + 2]];
+		bin.push_back((A << 2) | (B >> 4));
+		bin.push_back((B << 4) | (C >> 2));
+	} else if (pad == 2) {
+		int A = unb64[safeAsciiPtr[charNo]];
+		int B = unb64[safeAsciiPtr[charNo + 1]];
+		bin.push_back((A << 2) | (B >> 4));
+	}
+
+	return bin;
+}
+
+}  // namespace license
diff --git a/src/library/base/base64.h b/src/library/base/base64.h
index 9a353df..466a263 100644
--- a/src/library/base/base64.h
+++ b/src/library/base/base64.h
@@ -1,44 +1,18 @@
-/*
-
- https://github.com/superwills/NibbleAndAHalf
- base64.h -- Fast base64 encoding and decoding.
- version 1.0.0, April 17, 2013 143a
-
- Copyright (C) 2013 William Sherif
-
- This software is provided 'as-is', without any express or implied
- warranty.  In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-
- William Sherif
- will.sherif@gmail.com
-
- YWxsIHlvdXIgYmFzZSBhcmUgYmVsb25nIHRvIHVz
-
- */
 #ifndef BASE64_H
 #define BASE64_H
 
-#ifdef __cplusplus
-extern "C" {
+#include <string>
+#include <vector>
+
+#if _WIN32
+#include <wtypes.h>
 #endif
 
-unsigned char* unbase64(const char* ascii, int len, int *flen);
-char* base64(const void* binaryData, int len, int *flen);
+namespace license {
 
-#ifdef __cplusplus
-}
-#endif
+std::vector<uint8_t> unbase64(const std::string& base64_data);
+std::string base64(const void* binaryData, size_t len, int lineLenght = -1);
+
+}  // namespace license
+
 #endif
diff --git a/src/library/base/FileUtils.cpp b/src/library/base/file_utils.cpp
similarity index 98%
rename from src/library/base/FileUtils.cpp
rename to src/library/base/file_utils.cpp
index f8fcc20..221cd77 100644
--- a/src/library/base/FileUtils.cpp
+++ b/src/library/base/file_utils.cpp
@@ -11,7 +11,7 @@
 #include <iostream>
 #include <algorithm>
 
-#include "FileUtils.hpp"
+#include "file_utils.hpp"
 
 namespace license {
 using namespace std;
diff --git a/src/library/base/FileUtils.hpp b/src/library/base/file_utils.hpp
similarity index 100%
rename from src/library/base/FileUtils.hpp
rename to src/library/base/file_utils.hpp
diff --git a/src/library/base/logger.c b/src/library/base/logger.cpp
similarity index 97%
rename from src/library/base/logger.c
rename to src/library/base/logger.cpp
index 30db85d..580d1cf 100644
--- a/src/library/base/logger.c
+++ b/src/library/base/logger.cpp
@@ -5,6 +5,8 @@
 #include <stdarg.h>
 #include <time.h>
 
+#ifndef LOG_DISABLED
+
 #ifdef __unix__
 #include <unistd.h>
 #define MAX_PATH 255
@@ -69,3 +71,4 @@
 		logFile = NULL;
 	}
 }
+#endif
diff --git a/src/library/base/logger.h b/src/library/base/logger.h
index 4a516e4..9d9a128 100644
--- a/src/library/base/logger.h
+++ b/src/library/base/logger.h
@@ -1,12 +1,13 @@
 #ifndef logger_INCLUDED
 #define logger_INCLUDED
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define LOG_DISABLED 1
 
 #ifndef LOG_DISABLED
 #include <errno.h>
 #include <string.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
 
 #define clean_errno() (errno == 0 ? "None" : strerror(errno))
 
diff --git a/src/library/hw_identifier/CMakeLists.txt b/src/library/hw_identifier/CMakeLists.txt
new file mode 100644
index 0000000..09ba5e0
--- /dev/null
+++ b/src/library/hw_identifier/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_library(hw_identifier OBJECT
+	hw_identifier_facade.cpp
+	default_strategy.cpp
+	ethernet.cpp
+	disk_strategy.cpp
+	identification_strategy.cpp
+	hw_identifier.cpp
+)
+
+if(CODE_COVERAGE AND UNIX)
+	  target_compile_options(hw_identifier PUBLIC -O0 -g --coverage)
+endif(CODE_COVERAGE AND UNIX)
\ No newline at end of file
diff --git a/src/library/hw_identifier/default_strategy.cpp b/src/library/hw_identifier/default_strategy.cpp
new file mode 100644
index 0000000..da21f20
--- /dev/null
+++ b/src/library/hw_identifier/default_strategy.cpp
@@ -0,0 +1,77 @@
+/*
+ * default_strategy.cpp
+ *
+ *  Created on: Jan 1, 2020
+ *      Author: devel
+ */
+
+#include <vector>
+#include "../os/execution_environment.hpp"
+#include "default_strategy.hpp"
+
+using namespace std;
+namespace license {
+namespace hw_identifier {
+
+static vector<LCC_API_IDENTIFICATION_STRATEGY> available_strategies() {
+	os::ExecutionEnvironment exec;
+	os::VIRTUALIZATION virtualization = exec.getVirtualization();
+	vector<LCC_API_IDENTIFICATION_STRATEGY> strategy_to_try;
+	if (virtualization == os::CONTAINER) {
+		if (exec.is_docker()) {
+			strategy_to_try = LCC_DOCKER_STRATEGIES;
+		} else {
+			strategy_to_try = LCC_LXC_STRATEGIES;
+		}
+	} else if (virtualization == os::VM) {
+		if (exec.is_cloud()) {
+			strategy_to_try = LCC_CLOUD_STRATEGIES;
+		} else {
+			strategy_to_try = LCC_VM_STRATEGIES;
+		}
+	} else {
+		strategy_to_try = LCC_BARE_TO_METAL_STRATEGIES;
+	}
+	return strategy_to_try;
+}
+
+DefaultStrategy::DefaultStrategy() {}
+
+DefaultStrategy::~DefaultStrategy() {}
+
+LCC_API_IDENTIFICATION_STRATEGY DefaultStrategy::identification_strategy() const { return STRATEGY_DEFAULT; }
+
+FUNCTION_RETURN DefaultStrategy::identify_pc(HwIdentifier& pc_id) const {
+	vector<LCC_API_IDENTIFICATION_STRATEGY> strategy_to_try = available_strategies();
+	FUNCTION_RETURN ret = FUNC_RET_NOT_AVAIL;
+	for (auto it : strategy_to_try) {
+		LCC_API_IDENTIFICATION_STRATEGY strat_to_try = it;
+		unique_ptr<IdentificationStrategy> strategy_ptr = IdentificationStrategy::get_strategy(strat_to_try);
+		ret = strategy_ptr->identify_pc(pc_id);
+		if (ret == FUNC_RET_OK) {
+			break;
+		}
+	}
+	return ret;
+}
+
+std::vector<HwIdentifier> DefaultStrategy::alternative_ids() const {
+	vector<LCC_API_IDENTIFICATION_STRATEGY> strategy_to_try = available_strategies();
+	vector<HwIdentifier> identifiers;
+	FUNCTION_RETURN ret = FUNC_RET_NOT_AVAIL;
+	for (auto it : strategy_to_try) {
+		LCC_API_IDENTIFICATION_STRATEGY strat_to_try = it;
+		unique_ptr<IdentificationStrategy> strategy_ptr = IdentificationStrategy::get_strategy(strat_to_try);
+		vector<HwIdentifier> alt_ids = strategy_ptr->alternative_ids();
+		identifiers.insert(alt_ids.begin(), alt_ids.end(), identifiers.end());
+	}
+	return identifiers;
+}
+
+LCC_EVENT_TYPE DefaultStrategy::validate_identifier(const HwIdentifier& identifier) const {
+	// default strategy should always realize itself as a concrete strategy
+	return IDENTIFIERS_MISMATCH;
+}
+
+}  // namespace hw_identifier
+} /* namespace license */
diff --git a/src/library/hw_identifier/default_strategy.hpp b/src/library/hw_identifier/default_strategy.hpp
new file mode 100644
index 0000000..8f43827
--- /dev/null
+++ b/src/library/hw_identifier/default_strategy.hpp
@@ -0,0 +1,27 @@
+/*
+ * default_strategy.hpp
+ *
+ *  Created on: Jan 2, 2020
+ *      Author: devel
+ */
+
+#ifndef SRC_LIBRARY_PC_IDENTIFIER_DEFAULT_STRATEGY_HPP_
+#define SRC_LIBRARY_PC_IDENTIFIER_DEFAULT_STRATEGY_HPP_
+#include "identification_strategy.hpp"
+
+namespace license {
+namespace hw_identifier {
+
+class DefaultStrategy : public IdentificationStrategy {
+public:
+	DefaultStrategy();
+	virtual ~DefaultStrategy();
+	virtual LCC_API_IDENTIFICATION_STRATEGY identification_strategy() const;
+	virtual FUNCTION_RETURN identify_pc(HwIdentifier &pc_id) const;
+	virtual std::vector<HwIdentifier> alternative_ids() const;
+	virtual LCC_EVENT_TYPE validate_identifier(const HwIdentifier &identifier) const;
+};
+}  // namespace hw_identifier
+} /* namespace license */
+
+#endif /* SRC_LIBRARY_PC_IDENTIFIER_DEFAULT_STRATEGY_HPP_ */
diff --git a/src/library/hw_identifier/disk_strategy.cpp b/src/library/hw_identifier/disk_strategy.cpp
new file mode 100644
index 0000000..d9f6831
--- /dev/null
+++ b/src/library/hw_identifier/disk_strategy.cpp
@@ -0,0 +1,97 @@
+/*
+ * disk_strategy.cpp
+ *
+ *  Created on: Jan 14, 2020
+ *      Author: devel
+ */
+#include <string.h>
+#include "../os/os.h"
+#include "disk_strategy.hpp"
+
+using namespace std;
+namespace license {
+namespace hw_identifier {
+
+static FUNCTION_RETURN generate_disk_pc_id(vector<array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA>> &v_disk_id,
+										   bool use_id) {
+	size_t disk_num = 0;
+	size_t available_disk_info = 0;
+	FUNCTION_RETURN result_diskinfos;
+
+	result_diskinfos = getDiskInfos(nullptr, &disk_num);
+	if (result_diskinfos != FUNC_RET_OK && result_diskinfos != FUNC_RET_BUFFER_TOO_SMALL) {
+		return result_diskinfos;
+	}
+	if (disk_num == 0) {
+		return FUNC_RET_NOT_AVAIL;
+	}
+	size_t mem = disk_num * sizeof(DiskInfo);
+	DiskInfo *diskInfos = (DiskInfo *)malloc(mem);
+	if (diskInfos == nullptr) {
+		return FUNC_RET_NOT_AVAIL;
+	}
+	memset(diskInfos, 0, mem);
+	result_diskinfos = getDiskInfos(diskInfos, &disk_num);
+
+	if (result_diskinfos != FUNC_RET_OK) {
+		free(diskInfos);
+		return result_diskinfos;
+	}
+	for (unsigned int i = 0; i < disk_num; i++) {
+		char firstChar = use_id ? diskInfos[i].label[0] : diskInfos[i].disk_sn[0];
+		available_disk_info += firstChar == 0 ? 0 : 1;
+	}
+	if (available_disk_info == 0) {
+		free(diskInfos);
+		return FUNC_RET_NOT_AVAIL;
+	}
+	v_disk_id.reserve(available_disk_info);
+	for (int j = 0; j < 2; j++) {
+		int preferred = (j == 0 ? 1 : 0);
+		for (unsigned int i = 0; i < disk_num; i++) {
+			array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> a_disk_id;
+			a_disk_id.fill(0);
+			if (use_id) {
+				if (diskInfos[i].disk_sn[0] != 0 && diskInfos[i].preferred == preferred) {
+					size_t size = min(a_disk_id.size(), sizeof(&diskInfos[i].disk_sn));
+					memcpy(&a_disk_id[0], diskInfos[i].disk_sn, size);
+					v_disk_id.push_back(a_disk_id);
+				}
+			} else {
+				if (diskInfos[i].label[0] != 0 && diskInfos[i].preferred == preferred) {
+					strncpy((char *)&a_disk_id[0], diskInfos[i].label, a_disk_id.size() - 1);
+					v_disk_id.push_back(a_disk_id);
+				}
+			}
+		}
+	}
+	free(diskInfos);
+	return FUNC_RET_OK;
+}
+
+DiskStrategy::DiskStrategy(bool use_id) : m_use_id(use_id) {}
+
+DiskStrategy::~DiskStrategy() {}
+
+LCC_API_IDENTIFICATION_STRATEGY DiskStrategy::identification_strategy() const {
+	return m_use_id ? STRATEGY_DISK_NUM : STRATEGY_DISK_LABEL;
+}
+
+std::vector<HwIdentifier> DiskStrategy::alternative_ids() const {
+	vector<array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA>> data;
+	FUNCTION_RETURN result = generate_disk_pc_id(data, m_use_id);
+	vector<HwIdentifier> identifiers;
+	if (result == FUNC_RET_OK) {
+		identifiers.reserve(data.size());
+		for (auto &it : data) {
+			HwIdentifier pc_id;
+			pc_id.set_identification_strategy(identification_strategy());
+			pc_id.set_data(it);
+			identifiers.push_back(pc_id);
+		}
+	}
+	return identifiers;
+}
+
+}  // namespace hw_identifier
+} /* namespace license */
diff --git a/src/library/hw_identifier/disk_strategy.hpp b/src/library/hw_identifier/disk_strategy.hpp
new file mode 100644
index 0000000..67f5998
--- /dev/null
+++ b/src/library/hw_identifier/disk_strategy.hpp
@@ -0,0 +1,29 @@
+/*
+ * disk_strategy.hpp
+ *
+ *  Created on: Jan 14, 2020
+ *      Author: devel
+ */
+
+#ifndef SRC_LIBRARY_PC_IDENTIFIER_DISK_STRATEGY_HPP_
+#define SRC_LIBRARY_PC_IDENTIFIER_DISK_STRATEGY_HPP_
+
+#include "identification_strategy.hpp"
+
+namespace license {
+namespace hw_identifier {
+
+class DiskStrategy : public IdentificationStrategy {
+private:
+	bool m_use_id;
+public:
+	DiskStrategy(bool use_id);
+	virtual ~DiskStrategy();
+	virtual LCC_API_IDENTIFICATION_STRATEGY identification_strategy() const;
+	virtual std::vector<HwIdentifier> alternative_ids() const;
+};
+
+}  // namespace hw_identifier
+} /* namespace license */
+
+#endif /* SRC_LIBRARY_PC_IDENTIFIER_DISK_STRATEGY_HPP_ */
diff --git a/src/library/hw_identifier/ethernet.cpp b/src/library/hw_identifier/ethernet.cpp
new file mode 100644
index 0000000..bd21bc9
--- /dev/null
+++ b/src/library/hw_identifier/ethernet.cpp
@@ -0,0 +1,78 @@
+/*
+ * ethernet.cpp
+ *
+ *  Created on: Jan 11, 2020
+ *      Author: GC
+ */
+
+#include <array>
+#include <vector>
+
+#include <licensecc/datatypes.h>
+#include <licensecc_properties.h>
+#include "../base/base.h"
+#include "../os/network.hpp"
+#include "hw_identifier.hpp"
+#include "ethernet.hpp"
+
+namespace license {
+namespace hw_identifier {
+using namespace std;
+
+static FUNCTION_RETURN generate_ethernet_pc_id(vector<array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA>> &data,
+											   const bool use_ip) {
+	vector<os::OsAdapterInfo> adapters;
+
+	FUNCTION_RETURN result_adapterInfos = getAdapterInfos(adapters);
+	if (result_adapterInfos != FUNC_RET_OK) {
+		return result_adapterInfos;
+	}
+	if (adapters.size() == 0) {
+		return FUNC_RET_NOT_AVAIL;
+	}
+
+	for (auto &it : adapters) {
+		unsigned int k, data_len;
+		array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> identifier;
+		data_len = use_ip ? sizeof(os::OsAdapterInfo::ipv4_address) : sizeof(os::OsAdapterInfo::mac_address);
+
+		for (k = 0; k < HW_IDENTIFIER_PROPRIETARY_DATA; k++) {
+			if (k < data_len) {
+				identifier[k] = use_ip ? it.ipv4_address[k] : it.mac_address[k];
+			} else {
+				identifier[k] = 42;
+			}
+		}
+		identifier[0] = identifier[0] & 0x1F;
+		data.push_back(identifier);
+	}
+
+	return result_adapterInfos;
+}
+
+Ethernet::Ethernet(bool useIp) : use_ip(useIp) {}
+
+Ethernet::~Ethernet() {}
+
+LCC_API_IDENTIFICATION_STRATEGY Ethernet::identification_strategy() const {
+	return use_ip ? STRATEGY_IP_ADDRESS : STRATEGY_ETHERNET;
+}
+
+std::vector<HwIdentifier> Ethernet::alternative_ids() const {
+	vector<array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA>> data;
+	FUNCTION_RETURN result = generate_ethernet_pc_id(data, use_ip);
+	vector<HwIdentifier> identifiers;
+	if (result == FUNC_RET_OK) {
+		identifiers.reserve(data.size());
+		for (auto &it : data) {
+			HwIdentifier pc_id;
+			pc_id.set_identification_strategy(identification_strategy());
+			pc_id.set_data(it);
+			identifiers.push_back(pc_id);
+		}
+	}
+	return identifiers;
+}
+
+}  // namespace hw_identifier
+} /* namespace license */
diff --git a/src/library/hw_identifier/ethernet.hpp b/src/library/hw_identifier/ethernet.hpp
new file mode 100644
index 0000000..e02d2c1
--- /dev/null
+++ b/src/library/hw_identifier/ethernet.hpp
@@ -0,0 +1,29 @@
+/*
+ * ethernet.hpp
+ *
+ *  Created on: Jan 11, 2020
+ *      Author: devel
+ */
+
+#ifndef SRC_LIBRARY_PC_IDENTIFIER_ETHERNET_HPP_
+#define SRC_LIBRARY_PC_IDENTIFIER_ETHERNET_HPP_
+
+#include "identification_strategy.hpp"
+
+namespace license {
+namespace hw_identifier {
+
+class Ethernet : public IdentificationStrategy {
+private:
+	const bool use_ip;
+public:
+	Ethernet(bool use_ip);
+	virtual ~Ethernet();
+	virtual LCC_API_IDENTIFICATION_STRATEGY identification_strategy() const;
+	virtual std::vector<HwIdentifier> alternative_ids() const;
+};
+
+}  // namespace hw_identifier
+} /* namespace license */
+
+#endif /* SRC_LIBRARY_PC_IDENTIFIER_ETHERNET_HPP_ */
diff --git a/src/library/hw_identifier/hw_identifier.cpp b/src/library/hw_identifier/hw_identifier.cpp
new file mode 100644
index 0000000..5c163e7
--- /dev/null
+++ b/src/library/hw_identifier/hw_identifier.cpp
@@ -0,0 +1,99 @@
+/*
+ * hw_identifier.cpp
+ *
+ *  Created on: Dec 22, 2019
+ *      Author: GC
+ */
+
+#include <algorithm>
+#include "hw_identifier.hpp"
+#include "../base/base64.h"
+
+namespace license {
+namespace hw_identifier {
+
+using namespace std;
+
+HwIdentifier::HwIdentifier() {}
+
+HwIdentifier::HwIdentifier(const std::string& param) {
+	string tmp_str(param);  // throw away const
+	std::replace(tmp_str.begin(), tmp_str.end(), '-', '\n');
+	vector<uint8_t> decoded = unbase64(tmp_str);
+	if (decoded.size() != HW_IDENTIFIER_PROPRIETARY_DATA + 1) {
+		cerr << decoded.size();
+		throw logic_error("wrong identifier size " + param);
+	}
+	std::copy_n(decoded.begin(), HW_IDENTIFIER_PROPRIETARY_DATA + 1, m_data.begin());
+}
+
+HwIdentifier::~HwIdentifier() {}
+
+HwIdentifier::HwIdentifier(const HwIdentifier& other) : m_data(other.m_data) {}
+
+void HwIdentifier::set_identification_strategy(LCC_API_IDENTIFICATION_STRATEGY strategy) {
+	if (strategy == STRATEGY_NONE || strategy == STRATEGY_DEFAULT) {
+		throw logic_error("Only known strategies are permitted");
+	}
+	uint8_t stratMov = (strategy << 5);
+	m_data[1] = (m_data[1] & 0x1F) | stratMov;
+}
+
+void HwIdentifier::set_use_environment_var(bool use_env_var) {
+	if (use_env_var) {
+		m_data[0] = m_data[0] | 0x40;
+	} else {
+		m_data[0] = m_data[0] & ~0x40;
+	}
+}
+
+void HwIdentifier::set_virtual_environment(os::VIRTUALIZATION virt) {
+	// 110000 0x30
+	m_data[0] = (m_data[0] & ~0x30) | virt << 4;
+}
+
+void HwIdentifier::set_virtualization(os::VIRTUALIZATION_DETAIL virtualization_detail) {
+	m_data[0] = (m_data[0] & ~0x0F) | virtualization_detail;
+}
+
+void HwIdentifier::set_cloud_provider(os::CLOUD_PROVIDER cloud_provider) {
+	m_data[0] = (m_data[0] & ~0x0F) | cloud_provider | 0x08;
+}
+
+void HwIdentifier::set_data(const std::array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA>& data) {
+	m_data[1] = (m_data[1] & (~0x1f)) | (data[0] & 0x1f);
+	for (int i = 1; i < HW_IDENTIFIER_PROPRIETARY_DATA; i++) {
+		m_data[i + 1] = data[i];
+	}
+}
+
+std::string HwIdentifier::print() const {
+	string result = base64(m_data.data(), m_data.size(), 5);
+	std::replace(result.begin(), result.end(), '\n', '-');
+	return result.substr(0, result.size() - 1);
+}
+
+LCC_API_IDENTIFICATION_STRATEGY HwIdentifier::get_identification_strategy() const {
+	uint8_t stratMov = m_data[1] >> 5;
+	return static_cast<LCC_API_IDENTIFICATION_STRATEGY>(stratMov);
+}
+
+bool HwIdentifier::data_match(const std::array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA>& data) const {
+	bool equals = true;
+	for (int i = 0; i < HW_IDENTIFIER_PROPRIETARY_DATA && equals; i++) {
+		equals = (i == 0) ? ((data[i] & 0x1f) == (m_data[i + 1] & 0x1f)) : (data[i] == m_data[i + 1]);
+	}
+	return equals;
+}
+
+bool operator==(const HwIdentifier& lhs, const HwIdentifier& rhs) {
+	bool equals = lhs.get_identification_strategy() == rhs.get_identification_strategy();
+	for (int i = 0; i < HW_IDENTIFIER_PROPRIETARY_DATA && equals; i++) {
+		equals = (i == 0) ? ((rhs.m_data[i + 1] & 0x1f) == (lhs.m_data[i + 1] & 0x1f))
+						  : (lhs.m_data[i + 1] == rhs.m_data[i + 1]);
+	}
+	return equals;
+}
+
+}  // namespace hw_identifier
+} /* namespace license */
diff --git a/src/library/hw_identifier/hw_identifier.hpp b/src/library/hw_identifier/hw_identifier.hpp
new file mode 100644
index 0000000..56d3716
--- /dev/null
+++ b/src/library/hw_identifier/hw_identifier.hpp
@@ -0,0 +1,72 @@
+/*
+ * hw_identifier.h
+ *
+ *  Created on: Dec 22, 2019
+ *      Author: GC
+ */
+
+#ifndef SRC_LIBRARY_PC_IDENTIFIER_PC_IDENTIFIER_HPP_
+#define SRC_LIBRARY_PC_IDENTIFIER_PC_IDENTIFIER_HPP_
+
+#include <array>
+#include <iostream>
+#include <string>
+
+#include <licensecc_properties.h>
+#include "../../../include/licensecc/datatypes.h"
+#include "../os/execution_environment.hpp"
+#include "../os/cpu_info.hpp"
+
+namespace license {
+namespace hw_identifier {
+
+#define HW_IDENTIFIER_PROPRIETARY_DATA 8
+
+/**
+ * data[0]
+ * bit 7 = 0 if pc id is being generated 1 if it is coming from an issued license.
+ *
+ * if bit 7 = 0
+ * bit 6 = environment variable was used to generate pc_id
+ * bit 5-4 = execution environment information (0=BARE_TO_METAL,1=VM,2=CONTAINER)
+ * bit 3 = 0 on premise vm 1 = cloud
+ * if on premise vm bits 2-1-0 are virtualization technology
+ * if cloud vm bits 2-1-0 identify cloud provider
+ *
+ * if bit 7 = 1 hardware identifier is used to enable some flag that we don't want to show openly in the license
+ * bit 6 = 1 enable magic file/registry key
+ * ----
+ * data[1] bit 7-6-5 define identification strategy.
+ * data[1] bits 4-0, data[2-8] are hardware identifier proprietary strategy data.
+ */
+
+class HwIdentifier {
+private:
+	std::array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA + 1> m_data = {};
+	friend bool operator==(const HwIdentifier &lhs, const HwIdentifier &rhs);
+
+public:
+	HwIdentifier();
+	HwIdentifier(const std::string &param);
+	virtual ~HwIdentifier();
+	HwIdentifier(const HwIdentifier &other);
+	void set_identification_strategy(LCC_API_IDENTIFICATION_STRATEGY strategy);
+	LCC_API_IDENTIFICATION_STRATEGY get_identification_strategy() const;
+	void set_use_environment_var(bool use_env_var);
+	void set_virtual_environment(os::VIRTUALIZATION virtualization);
+	void set_virtualization(os::VIRTUALIZATION_DETAIL virtualization_detail);
+	void set_cloud_provider(os::CLOUD_PROVIDER cloud_provider);
+	void set_data(const std::array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> &data);
+	bool data_match(const std::array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> &data) const;
+	std::string print() const;
+	friend std::ostream &operator<<(std::ostream &output, const HwIdentifier &d) {
+		output << d.print();
+		return output;
+	};
+};
+
+
+}  // namespace hw_identifier
+} /* namespace license */
+
+#endif /* SRC_LIBRARY_PC_IDENTIFIER_PC_IDENTIFIER_HPP_ */
diff --git a/src/library/hw_identifier/hw_identifier_facade.cpp b/src/library/hw_identifier/hw_identifier_facade.cpp
new file mode 100644
index 0000000..07808f6
--- /dev/null
+++ b/src/library/hw_identifier/hw_identifier_facade.cpp
@@ -0,0 +1,77 @@
+/*
+ * hw_identifier_facade.cpp
+ *
+ *  Created on: Dec 26, 2019
+ *      Author: devel
+ */
+
+#include "hw_identifier_facade.hpp"
+
+#include <cstdlib>
+#include <stdexcept>
+
+#include "../base/base.h"
+#include "../base/logger.h"
+#include "../os/cpu_info.hpp"
+#include "../os/execution_environment.hpp"
+#include "identification_strategy.hpp"
+#include "hw_identifier.hpp"
+
+namespace license {
+namespace hw_identifier {
+
+using namespace std;
+
+LCC_EVENT_TYPE HwIdentifierFacade::validate_pc_signature(const std::string& str_code) {
+	HwIdentifier pc_id(str_code);
+	LCC_API_IDENTIFICATION_STRATEGY id_strategy = pc_id.get_identification_strategy();
+	LCC_EVENT_TYPE result = IDENTIFIERS_MISMATCH;
+	try {
+		unique_ptr<IdentificationStrategy> strategy = IdentificationStrategy::get_strategy(id_strategy);
+		result = strategy->validate_identifier(pc_id);
+	} catch (logic_error& e) {
+		LOG_ERROR("Error validating identifier %s: %s", str_code.c_str(), e.what());
+	}
+	return result;
+}
+
+std::string HwIdentifierFacade::generate_user_pc_signature(LCC_API_IDENTIFICATION_STRATEGY strategy) {
+	bool use_env_var = false;
+	vector<LCC_API_IDENTIFICATION_STRATEGY> strategies_to_try;
+	if (strategy == STRATEGY_DEFAULT) {
+		char* env_var_value = getenv(LCC_IDENTIFICATION_STRATEGY_ENV_VAR);
+		if (env_var_value != nullptr && env_var_value[0] != '\0') {
+			int strategy_int = atoi(env_var_value);
+			if (strategy_int < 0 || strategy_int > 3) {
+				LOG_WARN("unknown " LCC_IDENTIFICATION_STRATEGY_ENV_VAR " %s", env_var_value);
+			} else {
+				strategy = (LCC_API_IDENTIFICATION_STRATEGY)strategy_int;
+				use_env_var = true;
+			}
+		}
+	}
+
+	unique_ptr<IdentificationStrategy> strategy_ptr = IdentificationStrategy::get_strategy(strategy);
+	HwIdentifier pc_id;
+	FUNCTION_RETURN result = strategy_ptr->identify_pc(pc_id);
+	if (result != FUNC_RET_OK) {
+		throw logic_error("strategy " + to_string(strategy_ptr->identification_strategy()) + " failed");
+	}
+	os::ExecutionEnvironment exec;
+	os::VIRTUALIZATION virtualization = exec.getVirtualization();
+	pc_id.set_virtual_environment(virtualization);
+	pc_id.set_use_environment_var(use_env_var);
+	if (virtualization != os::NONE) {
+		bool isCloud = exec.is_cloud();
+		if (isCloud) {
+			pc_id.set_cloud_provider(exec.getCloudProvider());
+		} else {
+			os::CpuInfo cpu;
+			pc_id.set_virtualization(cpu.virtualization_details());
+		}
+	}
+	return pc_id.print();
+}
+
+}  // namespace hw_identifier
+} /* namespace license */
diff --git a/src/library/hw_identifier/hw_identifier_facade.hpp b/src/library/hw_identifier/hw_identifier_facade.hpp
new file mode 100644
index 0000000..c587c53
--- /dev/null
+++ b/src/library/hw_identifier/hw_identifier_facade.hpp
@@ -0,0 +1,38 @@
+/*
+ * hw_identifier_facade.hpp
+ *
+ *  Created on: Dec 26, 2019
+ *      Author: devel
+ */
+
+#ifndef SRC_LIBRARY_PC_IDENTIFIER_HW_IDENTIFIER_FACADE_HPP_
+#define SRC_LIBRARY_PC_IDENTIFIER_HW_IDENTIFIER_FACADE_HPP_
+#include "hw_identifier_facade.hpp"
+
+#include <string>
+#include <unordered_map>
+#include <licensecc/datatypes.h>
+#include "identification_strategy.hpp"
+
+namespace license {
+namespace hw_identifier {
+
+class HwIdentifierFacade {
+private:
+	HwIdentifierFacade(){};
+	virtual ~HwIdentifierFacade(){};
+public:
+	static LCC_EVENT_TYPE validate_pc_signature(const std::string& str_code);
+	/**
+	 *
+	 * @throws logic_error if pc_identifier can't be generated.
+	 * @param strategy
+	 * @return
+	 */
+	static std::string generate_user_pc_signature(LCC_API_IDENTIFICATION_STRATEGY strategy);
+};
+
+}  // namespace hw_identifier
+} /* namespace license */
+
+#endif /* SRC_LIBRARY_PC_IDENTIFIER_HW_IDENTIFIER_FACADE_HPP_ */
diff --git a/src/library/hw_identifier/identification_strategy.cpp b/src/library/hw_identifier/identification_strategy.cpp
new file mode 100644
index 0000000..273c670
--- /dev/null
+++ b/src/library/hw_identifier/identification_strategy.cpp
@@ -0,0 +1,60 @@
+#include <array>
+#include "identification_strategy.hpp"
+#include "default_strategy.hpp"
+#include "ethernet.hpp"
+#include "disk_strategy.hpp"
+namespace license {
+namespace hw_identifier {
+
+using namespace std;
+LCC_EVENT_TYPE IdentificationStrategy::validate_identifier(const HwIdentifier& identifier) const {
+	LCC_EVENT_TYPE result = IDENTIFIERS_MISMATCH;
+
+	if (identifier.get_identification_strategy() == identification_strategy()) {
+		const vector<HwIdentifier> available_ids = alternative_ids();
+		for (const auto& it : available_ids) {
+			if (it == identifier) {
+				result = LICENSE_OK;
+				break;
+			}
+		}
+	}
+	return result;
+}
+
+FUNCTION_RETURN IdentificationStrategy::identify_pc(HwIdentifier& pc_id) const {
+	vector<array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA>> data;
+	const vector<HwIdentifier> available_ids = alternative_ids();
+	FUNCTION_RETURN result = FUNC_RET_NOT_AVAIL;
+	if (available_ids.size() > 0) {
+		pc_id = available_ids[0];
+		result = FUNC_RET_OK;
+	}
+	return result;
+}
+
+std::unique_ptr<IdentificationStrategy> IdentificationStrategy::get_strategy(LCC_API_IDENTIFICATION_STRATEGY strategy) {
+	unique_ptr<IdentificationStrategy> result;
+	switch (strategy) {
+		case STRATEGY_DEFAULT:
+			result = unique_ptr<IdentificationStrategy>(dynamic_cast<IdentificationStrategy*>(new DefaultStrategy()));
+			break;
+		case STRATEGY_ETHERNET:
+			result = unique_ptr<IdentificationStrategy>(dynamic_cast<IdentificationStrategy*>(new Ethernet(false)));
+			break;
+		case STRATEGY_IP_ADDRESS:
+			result = unique_ptr<IdentificationStrategy>(dynamic_cast<IdentificationStrategy*>(new Ethernet(true)));
+			break;
+		case STRATEGY_DISK_NUM:
+			result = unique_ptr<IdentificationStrategy>(dynamic_cast<IdentificationStrategy*>(new DiskStrategy(true)));
+			break;
+		case STRATEGY_DISK_LABEL:
+			result = unique_ptr<IdentificationStrategy>(dynamic_cast<IdentificationStrategy*>(new DiskStrategy(false)));
+			break;
+		default:
+			throw logic_error("strategy not supported");
+	}
+	return result;
+}
+}  // namespace hw_identifier
+}  // namespace license
diff --git a/src/library/hw_identifier/identification_strategy.hpp b/src/library/hw_identifier/identification_strategy.hpp
new file mode 100644
index 0000000..22ded81
--- /dev/null
+++ b/src/library/hw_identifier/identification_strategy.hpp
@@ -0,0 +1,43 @@
+/*
+ * identification_strategy.hpp
+ *
+ *  Created on: Jan 1, 2020
+ *      Author: devel
+ */
+
+#ifndef SRC_LIBRARY_PC_IDENTIFIER_IDENTIFICATION_STRATEGY_HPP_
+#define SRC_LIBRARY_PC_IDENTIFIER_IDENTIFICATION_STRATEGY_HPP_
+
+#include <licensecc/datatypes.h>
+#include <licensecc_properties.h>
+#include <vector>
+#include <memory>
+#include "../base/base.h"
+#include "hw_identifier.hpp"
+
+namespace license {
+namespace hw_identifier {
+
+class IdentificationStrategy {
+protected:
+	IdentificationStrategy(){};
+
+public:
+	virtual ~IdentificationStrategy(){};
+	virtual LCC_API_IDENTIFICATION_STRATEGY identification_strategy() const = 0;
+	virtual FUNCTION_RETURN identify_pc(HwIdentifier& identifier_out) const;
+	virtual std::vector<HwIdentifier> alternative_ids() const = 0;
+	virtual LCC_EVENT_TYPE validate_identifier(const HwIdentifier& identifier_in) const;
+
+	/**
+	 * Factory method to create an instance of IdentificationStrategy
+	 * @param strategy
+	 * @return
+	 */
+	static std::unique_ptr<IdentificationStrategy> get_strategy(LCC_API_IDENTIFICATION_STRATEGY strategy);
+};
+
+}  // namespace hw_identifier
+} /* namespace license */
+
+#endif /* SRC_LIBRARY_PC_IDENTIFIER_IDENTIFICATION_STRATEGY_HPP_ */
diff --git a/src/library/ini/ConvertUTF.c b/src/library/ini/ConvertUTF.cpp
similarity index 100%
rename from src/library/ini/ConvertUTF.c
rename to src/library/ini/ConvertUTF.cpp
diff --git a/src/library/licensecc.cpp b/src/library/licensecc.cpp
index 63330cb..5378638 100644
--- a/src/library/licensecc.cpp
+++ b/src/library/licensecc.cpp
@@ -17,25 +17,35 @@
 #include <licensecc/licensecc.h>
 #include <licensecc_properties.h>
 
+#include "base/logger.h"
+#include "hw_identifier/hw_identifier_facade.hpp"
 #include "limits/license_verifier.hpp"
 #include "base/StringUtils.h"
 #include "LicenseReader.hpp"
-#include "pc-identifiers.h"
 
 using namespace std;
 
-void print_error(char out_buffer[ERROR_BUFFER_SIZE], LicenseInfo* licenseInfo) {}
 
-bool identify_pc(IDENTIFICATION_STRATEGY pc_id_method, char* chbuffer, size_t* bufSize) {
-	FUNCTION_RETURN result = FUNC_RET_BUFFER_TOO_SMALL;
-	if (*bufSize > sizeof(PcSignature)) {
-		PcSignature identifier_out;
-		result = generate_user_pc_signature(identifier_out, pc_id_method);
-		strncpy(chbuffer, identifier_out, *bufSize);
+void print_error(char out_buffer[LCC_API_ERROR_BUFFER_SIZE], LicenseInfo* licenseInfo) {}
+
+bool identify_pc(LCC_API_IDENTIFICATION_STRATEGY pc_id_method, char* chbuffer, size_t* bufSize) {
+	bool result = false;
+	if (*bufSize > LCC_API_PC_IDENTIFIER_SIZE && chbuffer != nullptr) {
+		try {
+			string pc_id = license::hw_identifier::HwIdentifierFacade::generate_user_pc_signature(pc_id_method);
+			strncpy(chbuffer, pc_id.c_str(), *bufSize);
+			result = true;
+		} catch (const std::exception& ex) {
+			LOG_ERROR("Error calculating hw_identifier: %s", ex.what());
+#ifdef _DEBUG
+				cout
+				<< "Error occurred: " << ex.what() << std::endl;
+#endif
+		}
 	} else {
-		*bufSize = sizeof(PcSignature) + 1;
+		*bufSize = LCC_API_PC_IDENTIFIER_SIZE + 1;
 	}
-	return result == FUNC_RET_OK;
+	return result;
 }
 
 static void mergeLicenses(const vector<LicenseInfo>& licenses, LicenseInfo* license_out) {
@@ -54,8 +64,8 @@
 	}
 }
 
-EVENT_TYPE acquire_license(const CallerInformations* callerInformation, const LicenseLocation* licenseLocation,
-						   LicenseInfo* license_out) {
+LCC_EVENT_TYPE acquire_license(const CallerInformations* callerInformation,
+									 const LicenseLocation* licenseLocation, LicenseInfo* license_out) {
 	const license::LicenseReader lr = license::LicenseReader(licenseLocation);
 	vector<license::FullLicenseInfo> licenses;
 	string project;
@@ -67,21 +77,25 @@
 		project = string(LCC_PROJECT_NAME);
 	}
 	license::EventRegistry er = lr.readLicenses(string(project), licenses);
-	EVENT_TYPE result;
+	LCC_EVENT_TYPE result;
 	if (licenses.size() > 0) {
 		vector<LicenseInfo> licenses_with_errors;
 		vector<LicenseInfo> licenses_ok;
 		license::LicenseVerifier verifier(er);
-		for (auto it = licenses.begin(); it != licenses.end(); it++) {
-			FUNCTION_RETURN signatureValid = verifier.verify_signature(*it);
+		for (auto full_lic_info_it = licenses.begin(); full_lic_info_it != licenses.end(); full_lic_info_it++) {
+			if (callerInformation != nullptr) {
+				full_lic_info_it->m_magic = callerInformation->magic;
+			}
+			const FUNCTION_RETURN signatureValid = verifier.verify_signature(*full_lic_info_it);
+			LicenseInfo licInfo = verifier.toLicenseInfo(*full_lic_info_it);
 			if (signatureValid == FUNC_RET_OK) {
-				if (verifier.verify_limits(*it) == FUNC_RET_OK) {
-					licenses_ok.push_back(verifier.toLicenseInfo(*it));
+				if (verifier.verify_limits(*full_lic_info_it) == FUNC_RET_OK) {
+					licenses_ok.push_back(licInfo);
 				} else {
-					licenses_with_errors.push_back(verifier.toLicenseInfo(*it));
+					licenses_with_errors.push_back(licInfo);
 				}
 			} else {
-				licenses_with_errors.push_back(verifier.toLicenseInfo(*it));
+				licenses_with_errors.push_back(licInfo);
 			}
 		}
 		if (licenses_ok.size() > 0) {
@@ -107,11 +121,12 @@
 #endif
 
 	if (license_out != nullptr) {
-		er.exportLastEvents(license_out->status, AUDIT_EVENT_NUM);
+		er.exportLastEvents(license_out->status, LCC_API_AUDIT_EVENT_NUM);
 	}
 	return result;
 }
 
-EVENT_TYPE confirm_license(char* product, LicenseLocation licenseLocation) { return LICENSE_OK; }
+LCC_EVENT_TYPE confirm_license(char* product, LicenseLocation licenseLocation) { return LICENSE_OK; }
 
-EVENT_TYPE release_license(char* product, LicenseLocation licenseLocation) { return LICENSE_OK; }
+LCC_EVENT_TYPE release_license(char* product, LicenseLocation licenseLocation) { return LICENSE_OK; }
+
diff --git a/src/library/limits/license_verifier.cpp b/src/library/limits/license_verifier.cpp
index 38abbeb..71c2cc8 100644
--- a/src/library/limits/license_verifier.cpp
+++ b/src/library/limits/license_verifier.cpp
@@ -6,11 +6,12 @@
  */
 #include <cmath>
 #include <algorithm>
+#include <licensecc_properties.h>
 
 #include "license_verifier.hpp"
-#include "../os/signature_verifier.h"
 #include "../base/StringUtils.h"
-#include "../pc-identifiers.h"
+#include "../os/signature_verifier.hpp"
+#include "../hw_identifier/hw_identifier_facade.hpp"
 
 namespace license {
 using namespace std;
@@ -22,7 +23,7 @@
 FUNCTION_RETURN LicenseVerifier::verify_signature(const FullLicenseInfo& licInfo) {
 	const string licInfoData(licInfo.printForSign());
 
-	FUNCTION_RETURN ret = license::verify_signature(licInfoData, licInfo.license_signature);
+	FUNCTION_RETURN ret = license::os::verify_signature(licInfoData, licInfo.license_signature);
 
 	if (ret == FUNC_RET_OK) {
 		m_event_registry.addEvent(SIGNATURE_VERIFIED, licInfo.source);
@@ -33,35 +34,31 @@
 }
 
 // TODO: split in different classes
-FUNCTION_RETURN LicenseVerifier::verify_limits(const FullLicenseInfo& licInfo) {
-	bool is_valid = true;
+FUNCTION_RETURN LicenseVerifier::verify_limits(const FullLicenseInfo& lic_info) {
+	bool is_valid = LCC_VERIFY_MAGIC;
+	if (!is_valid) {
+		m_event_registry.addEvent(LICENSE_CORRUPTED, lic_info.source.c_str());
+	}
 	const time_t now = time(nullptr);
-	auto expiry = licInfo.m_limits.find(PARAM_EXPIRY_DATE);
-	if (expiry != licInfo.m_limits.end()) {
+	auto expiry = lic_info.m_limits.find(PARAM_EXPIRY_DATE);
+	if (is_valid && expiry != lic_info.m_limits.end()) {
 		if (seconds_from_epoch(expiry->second) < now) {
-			/*
-						eventRegistryOut.addEvent(PRODUCT_EXPIRED, source.c_str(),
-								string("Expired on: " + this->to_date).c_str());*/
-			m_event_registry.addEvent(PRODUCT_EXPIRED, licInfo.source.c_str(), ("Expired " + expiry->second).c_str());
+			m_event_registry.addEvent(PRODUCT_EXPIRED, lic_info.source.c_str(), ("Expired " + expiry->second).c_str());
 			is_valid = false;
 		}
 	}
-	auto start_date = licInfo.m_limits.find(PARAM_BEGIN_DATE);
-	if (is_valid && start_date != licInfo.m_limits.end()) {
+	const auto start_date = lic_info.m_limits.find(PARAM_BEGIN_DATE);
+	if (is_valid && start_date != lic_info.m_limits.end()) {
 		if (seconds_from_epoch(start_date->second) > now) {
-			/*eventRegistryOut.addEvent(PRODUCT_EXPIRED, source.c_str(),
-					string("Valid from " + this->from_date).c_str());*/
-			m_event_registry.addEvent(PRODUCT_EXPIRED, licInfo.source.c_str(),
+			m_event_registry.addEvent(PRODUCT_EXPIRED, lic_info.source.c_str(),
 									  ("Valid from " + start_date->second).c_str());
 			is_valid = false;
 		}
 	}
-	auto client_sig = licInfo.m_limits.find(PARAM_CLIENT_SIGNATURE);
-	if (is_valid && client_sig != licInfo.m_limits.end()) {
-		PcSignature str_code;
-		strncpy(str_code, client_sig->second.c_str(), sizeof(str_code) - 1);
-		const EVENT_TYPE event = validate_pc_signature(str_code);
-		m_event_registry.addEvent(event, licInfo.source);
+	const auto client_sig = lic_info.m_limits.find(PARAM_CLIENT_SIGNATURE);
+	if (is_valid && client_sig != lic_info.m_limits.end()) {
+		const LCC_EVENT_TYPE event = hw_identifier::HwIdentifierFacade::validate_pc_signature(client_sig->second);
+		m_event_registry.addEvent(event, lic_info.source);
 		is_valid = is_valid && (event == LICENSE_OK);
 	}
 	return is_valid ? FUNC_RET_OK : FUNC_RET_ERROR;
@@ -69,9 +66,9 @@
 
 LicenseInfo LicenseVerifier::toLicenseInfo(const FullLicenseInfo& fullLicInfo) const {
 	LicenseInfo info;
-	info.license_type = LOCAL;
+	info.license_type = LCC_LOCAL;
 
-	auto expiry = fullLicInfo.m_limits.find(PARAM_EXPIRY_DATE);
+	const auto expiry = fullLicInfo.m_limits.find(PARAM_EXPIRY_DATE);
 	if (expiry != fullLicInfo.m_limits.end()) {
 		strncpy(info.expiry_date, expiry->second.c_str(), sizeof(info.expiry_date));
 		info.has_expiry = true;
@@ -83,16 +80,16 @@
 		info.expiry_date[0] = '\0';
 	}
 
-	auto start_date = fullLicInfo.m_limits.find(PARAM_BEGIN_DATE);
+	const auto start_date = fullLicInfo.m_limits.find(PARAM_BEGIN_DATE);
 	if (start_date != fullLicInfo.m_limits.end()) {
 	}
 
-	auto client_sig = fullLicInfo.m_limits.find(PARAM_CLIENT_SIGNATURE);
+	const auto client_sig = fullLicInfo.m_limits.find(PARAM_CLIENT_SIGNATURE);
 	info.linked_to_pc = (client_sig != fullLicInfo.m_limits.end());
 
-	auto proprietary_data = fullLicInfo.m_limits.find(PARAM_EXTRA_DATA);
+	const auto proprietary_data = fullLicInfo.m_limits.find(PARAM_EXTRA_DATA);
 	if (proprietary_data != fullLicInfo.m_limits.end()) {
-		strncpy(info.proprietary_data, proprietary_data->second.c_str(), PROPRIETARY_DATA_SIZE);
+		strncpy(info.proprietary_data, proprietary_data->second.c_str(), LCC_API_PROPRIETARY_DATA_SIZE);
 	}
 	return info;
 }
diff --git a/src/library/locate/ApplicationFolder.cpp b/src/library/locate/ApplicationFolder.cpp
index 8741988..8bc7f5a 100644
--- a/src/library/locate/ApplicationFolder.cpp
+++ b/src/library/locate/ApplicationFolder.cpp
@@ -15,9 +15,9 @@
 #include "../base/logger.h"
 #include "../base/base.h"
 #include "../base/EventRegistry.h"
-#include "../base/FileUtils.hpp"
 #include "../os/os.h"
 #include "ApplicationFolder.hpp"
+#include "../base/file_utils.hpp"
 
 namespace license {
 namespace locate {
@@ -33,7 +33,7 @@
 	const FUNCTION_RETURN fret = getModuleName(fname);
 	if (fret == FUNC_RET_OK) {
 		const string module_name = remove_extension(fname);
-		const string temptativeLicense = string(module_name) + LICENSE_FILE_EXTENSION;
+		const string temptativeLicense = string(module_name) + LCC_LICENSE_FILE_EXTENSION;
 		ifstream f(temptativeLicense.c_str());
 		if (f.good()) {
 			diskFiles.push_back(temptativeLicense);
diff --git a/src/library/locate/CMakeLists.txt b/src/library/locate/CMakeLists.txt
index 4382448..22d78b8 100644
--- a/src/library/locate/CMakeLists.txt
+++ b/src/library/locate/CMakeLists.txt
@@ -1,9 +1,17 @@
-target_sources(licensecc_static PRIVATE
-    ${CMAKE_CURRENT_SOURCE_DIR}/ApplicationFolder.cpp
-    ${CMAKE_CURRENT_SOURCE_DIR}/EnvironmentVarLocation.cpp
-    ${CMAKE_CURRENT_SOURCE_DIR}/EnvironmentVarData.cpp
-    ${CMAKE_CURRENT_SOURCE_DIR}/ExternalDefinition.cpp
-    ${CMAKE_CURRENT_SOURCE_DIR}/LocatorStrategy.cpp
-    ${CMAKE_CURRENT_SOURCE_DIR}/LocatorFactory.cpp
+add_library(locate OBJECT
+    ApplicationFolder.cpp
+    EnvironmentVarLocation.cpp
+    EnvironmentVarData.cpp
+    ExternalDefinition.cpp
+    LocatorStrategy.cpp
+    LocatorFactory.cpp
 )
 
+target_include_directories(locate PRIVATE
+        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../include>
+        $<BUILD_INTERFACE:${LCC_INCLUDE_DIR}>
+)
+
+if(CODE_COVERAGE AND UNIX)
+	  target_compile_options(locate PUBLIC -O0 -g --coverage)
+endif(CODE_COVERAGE AND UNIX)
\ No newline at end of file
diff --git a/src/library/locate/EnvironmentVarData.cpp b/src/library/locate/EnvironmentVarData.cpp
index 6e47d21..707d6a5 100644
--- a/src/library/locate/EnvironmentVarData.cpp
+++ b/src/library/locate/EnvironmentVarData.cpp
@@ -29,32 +29,31 @@
 
 const vector<string> EnvironmentVarData::license_locations(EventRegistry &eventRegistry) {
 	vector<string> diskFiles;
-	char *env_var_value = getenv(LICENSE_DATA_ENV_VAR);
+	char *env_var_value = getenv(LCC_LICENSE_DATA_ENV_VAR);
 	if (env_var_value != nullptr && env_var_value[0] != '\0') {
-		eventRegistry.addEvent(LICENSE_SPECIFIED, LICENSE_LOCATION_ENV_VAR);
+		eventRegistry.addEvent(LICENSE_SPECIFIED, LCC_LICENSE_LOCATION_ENV_VAR);
 		FILE_FORMAT licenseFormat = identify_format(env_var_value);
 		if (licenseFormat == UNKNOWN) {
-			eventRegistry.addEvent(LICENSE_MALFORMED, LICENSE_LOCATION_ENV_VAR);
+			eventRegistry.addEvent(LICENSE_MALFORMED, LCC_LICENSE_LOCATION_ENV_VAR);
 		} else {
-			diskFiles.push_back(LICENSE_LOCATION_ENV_VAR);
+			diskFiles.push_back(LCC_LICENSE_LOCATION_ENV_VAR);
 			isBase64 = (licenseFormat == BASE64);
 		}
 	} else {
-		eventRegistry.addEvent(ENVIRONMENT_VARIABLE_NOT_DEFINED, LICENSE_LOCATION_ENV_VAR);
+		eventRegistry.addEvent(ENVIRONMENT_VARIABLE_NOT_DEFINED, LCC_LICENSE_LOCATION_ENV_VAR);
 	}
 	return diskFiles;
 }
 
 const std::string EnvironmentVarData::retrieve_license_content(const std::string &licenseLocation) const {
-	string tmpVal = getenv(LICENSE_LOCATION_ENV_VAR);
+	string env_val = getenv(LCC_LICENSE_LOCATION_ENV_VAR);
 	if (isBase64) {
 		int flen = 0;
-		unsigned char *raw = unbase64(tmpVal.c_str(), tmpVal.length(), &flen);
-		string str = string(reinterpret_cast<char *>(raw));
-		free(raw);
+		vector<uint8_t> data = unbase64(env_val);
+		string str = string(reinterpret_cast<char *>(data.data()));
 		return str;
 	}
-	return tmpVal;
+	return env_val;
 }
 
 }  // namespace locate
diff --git a/src/library/locate/EnvironmentVarLocation.cpp b/src/library/locate/EnvironmentVarLocation.cpp
index 5615482..e74228a 100644
--- a/src/library/locate/EnvironmentVarLocation.cpp
+++ b/src/library/locate/EnvironmentVarLocation.cpp
@@ -7,9 +7,9 @@
 
 #include <licensecc_properties.h>
 
-#include "../base/FileUtils.hpp"
 #include "../base/StringUtils.h"
 #include "EnvironmentVarLocation.hpp"
+#include "../base/file_utils.hpp"
 
 namespace license {
 namespace locate {
@@ -22,14 +22,14 @@
 const vector<string> EnvironmentVarLocation::license_locations(EventRegistry &eventRegistry) {
 	vector<string> licenseFileFoundWithEnvVariable;
 
-	const string varName(LICENSE_LOCATION_ENV_VAR);
+	const string varName(LCC_LICENSE_LOCATION_ENV_VAR);
 	if (varName.length() > 0) {
 		// var name is defined in header files.
-		char *env_var_value = getenv(LICENSE_LOCATION_ENV_VAR);
+		char *env_var_value = getenv(LCC_LICENSE_LOCATION_ENV_VAR);
 		if (env_var_value != nullptr && env_var_value[0] != '\0') {
 			const vector<string> declared_positions = license::split_string(string(env_var_value), ';');
 			licenseFileFoundWithEnvVariable =
-				license::filter_existing_files(declared_positions, eventRegistry, LICENSE_LOCATION_ENV_VAR);
+				license::filter_existing_files(declared_positions, eventRegistry, LCC_LICENSE_LOCATION_ENV_VAR);
 		} else {
 			eventRegistry.addEvent(ENVIRONMENT_VARIABLE_NOT_DEFINED);
 		}
diff --git a/src/library/locate/ExternalDefinition.cpp b/src/library/locate/ExternalDefinition.cpp
index 78b9825..a5309de 100644
--- a/src/library/locate/ExternalDefinition.cpp
+++ b/src/library/locate/ExternalDefinition.cpp
@@ -9,64 +9,57 @@
 #include <cstring>
 #include <string>
 #include <vector>
-
+#include <stdexcept>
 #include <licensecc/datatypes.h>
 
 #include "../base/base64.h"
 #include "../base/EventRegistry.h"
-#include "../base/FileUtils.hpp"
 #include "../base/StringUtils.h"
 
 #include "ExternalDefinition.hpp"
+#include "../base/file_utils.hpp"
 
 namespace license {
 namespace locate {
-using namespace std;
+	using namespace std;
 
-ExternalDefinition::ExternalDefinition(const LicenseLocation *location) :
-		LocatorStrategy("ExternalDefinition"), m_location(location) {
-}
+ExternalDefinition::ExternalDefinition(const LicenseLocation *location)
+	: LocatorStrategy("ExternalDefinition"), m_location(location) {}
 
-ExternalDefinition::~ExternalDefinition() {
-}
+ExternalDefinition::~ExternalDefinition() {}
 
-const std::vector<std::string> ExternalDefinition::license_locations(
-		EventRegistry &eventRegistry) {
+const std::vector<std::string> ExternalDefinition::license_locations(EventRegistry &eventRegistry) {
 	vector<string> existing_pos;
-	if (m_location->licenseData != nullptr
-			&& m_location->licenseData[0] != '\0') {
+	if (m_location->licenseData[0] != '\0') {
 		eventRegistry.addEvent(LICENSE_SPECIFIED, get_strategy_name());
-		FILE_FORMAT licenseFormat = identify_format(m_location->licenseData);
-
-		if (licenseFormat == UNKNOWN) {
-			eventRegistry.addEvent(LICENSE_MALFORMED, get_strategy_name());
-		} else {
-			existing_pos.push_back(get_strategy_name());
-			licenseDataIsBase64 = (licenseFormat == BASE64);
+		switch (m_location->license_data_type) {
+			case LICENSE_PATH: {
+				string licData(m_location->licenseData, mstrnlen_s(m_location->licenseData, LCC_API_MAX_LICENSE_DATA_LENGTH));
+				const vector<string> declared_positions = license::split_string(licData, ';');
+				existing_pos =
+					license::filter_existing_files(declared_positions, eventRegistry, get_strategy_name().c_str());
+			} break;
+			case LICENSE_ENCODED:
+			case LICENSE_PLAIN_DATA:
+				existing_pos.push_back(get_strategy_name());
+				break;
+			default:
+				throw logic_error("license type not supported ");
 		}
-	}
-	if (m_location->licenseFileLocation != nullptr
-			&& strlen(m_location->licenseFileLocation) > 0) {
-		const vector<string> declared_positions = license::split_string(
-				m_location->licenseFileLocation, ';');
-		existing_pos = license::filter_existing_files(declared_positions,
-				eventRegistry, get_strategy_name().c_str());
 	}
 	return existing_pos;
 }
 
-const std::string ExternalDefinition::retrieve_license_content(
-		const std::string &licenseLocation) const {
+const std::string ExternalDefinition::retrieve_license_content(const std::string &licenseLocation) const {
 	if (licenseLocation == get_strategy_name()) {
-		if (licenseDataIsBase64) {
-			int flen = 0;
-			unsigned char *raw = unbase64(m_location->licenseData,
-					strlen(m_location->licenseData), &flen);
-			string str = string(reinterpret_cast<char*>(raw));
-			free(raw);
+		string licData(m_location->licenseData, mstrnlen_s(m_location->licenseData, LCC_API_MAX_LICENSE_DATA_LENGTH));
+		if (m_location->license_data_type == LICENSE_ENCODED) {
+			// FIXME what if license is wrong
+			vector<uint8_t> raw = unbase64(licData);
+			string str = string(reinterpret_cast<char *>(raw.data()));
 			return str;
 		} else {
-			return m_location->licenseData;
+			return licData;
 		}
 	} else {
 		return LocatorStrategy::retrieve_license_content(licenseLocation);
diff --git a/src/library/locate/ExternalDefinition.hpp b/src/library/locate/ExternalDefinition.hpp
index c70775a..7ffa9ae 100644
--- a/src/library/locate/ExternalDefinition.hpp
+++ b/src/library/locate/ExternalDefinition.hpp
@@ -16,11 +16,10 @@
 class ExternalDefinition: public LocatorStrategy {
 private:
 	const LicenseLocation* m_location;
-	bool licenseDataIsBase64 = false;
 public:
 	ExternalDefinition(const LicenseLocation* location);
-	virtual const std::vector<std::string> license_locations(EventRegistry& eventRegistry);
-	virtual const std::string retrieve_license_content(const std::string &licenseLocation) const;
+	const virtual std::vector<std::string> license_locations(EventRegistry& eventRegistry);
+	const virtual std::string retrieve_license_content(const std::string& licenseLocation) const;
 	virtual ~ExternalDefinition();
 };
 
diff --git a/src/library/locate/LocatorStrategy.cpp b/src/library/locate/LocatorStrategy.cpp
index 8bde5f1..04c722d 100644
--- a/src/library/locate/LocatorStrategy.cpp
+++ b/src/library/locate/LocatorStrategy.cpp
@@ -7,15 +7,15 @@
 
 #include <licensecc_properties.h>
 
-#include "../base/FileUtils.hpp"
 #include "LocatorStrategy.hpp"
+#include "../base/file_utils.hpp"
 
 namespace license {
 namespace locate {
 using namespace std;
 
 const string LocatorStrategy::retrieve_license_content(const string &licenseLocation) const {
-	return get_file_contents(licenseLocation.c_str(), MAX_LICENSE_LENGTH);
+	return get_file_contents(licenseLocation.c_str(), LCC_API_MAX_LICENSE_DATA_LENGTH);
 }
 
 }  // namespace locate
diff --git a/src/library/os/CMakeLists.txt b/src/library/os/CMakeLists.txt
index e9e74df..7244e0d 100644
--- a/src/library/os/CMakeLists.txt
+++ b/src/library/os/CMakeLists.txt
@@ -1,17 +1,41 @@
 IF(UNIX OR OPENSSL_FOUND)
 	IF(UNIX)
-		target_sources(licensecc_static PRIVATE
-		    ${CMAKE_CURRENT_SOURCE_DIR}/openssl/signature_verifier.cpp
-		    ${CMAKE_CURRENT_SOURCE_DIR}/os-linux.c 
-		    ${CMAKE_CURRENT_SOURCE_DIR}/network_id.c)
+		add_library(os OBJECT
+		    openssl/signature_verifier.cpp
+            execution_environment_common.cpp
+		    linux/execution_environment.cpp
+		    cpu_info_common.cpp
+		    linux/cpu_info.cpp
+		    linux/network.cpp
+		    linux/os_linux.cpp) 
 	ELSE(UNIX)
-  	    target_sources(licensecc_static PRIVATE
-		    ${CMAKE_CURRENT_SOURCE_DIR}/openssl/signature_verifier.cpp
-  	    	${CMAKE_CURRENT_SOURCE_DIR}/os-win.c)
+	    #windows and openssl
+  	    add_library(os OBJECT 
+  	    cpu_info_common.cpp windows/cpu_info.cpp 
+  	    openssl/signature_verifier.cpp 
+        execution_environment_common.cpp windows/execution_environment.cpp
+  	    windows/isvm/Native.cpp
+        windows/isvm/BIOSReader.cpp
+  	    windows/os_win.cpp
+  	    windows/network.cpp)
 	ENDIF(UNIX)
+	target_include_directories(os PUBLIC ${OPENSSL_INCLUDE_DIR})
 ELSE(UNIX OR OPENSSL_FOUND)
-    target_sources(licensecc_static PRIVATE
-        ${CMAKE_CURRENT_SOURCE_DIR}/windows/signature_verifier.cpp
-        ${CMAKE_CURRENT_SOURCE_DIR}/os-win.c)
+#windows no openssl
+    add_library(os OBJECT
+        cpu_info_common.cpp 
+        windows/cpu_info.cpp 
+        windows/signature_verifier.cpp 
+        execution_environment_common.cpp windows/execution_environment.cpp
+        windows/isvm/Native.cpp
+        windows/isvm/BIOSReader.cpp
+        windows/os_win.cpp
+        windows/network.cpp)
 ENDIF(UNIX OR OPENSSL_FOUND)
 
+#dependency of signature_verifier.cpp
+add_dependencies( os project_initialize )
+
+if(CODE_COVERAGE AND UNIX)
+	  target_compile_options(os PUBLIC -O0 -g --coverage)
+endif(CODE_COVERAGE AND UNIX)
\ No newline at end of file
diff --git a/src/library/os/cpu_info.hpp b/src/library/os/cpu_info.hpp
new file mode 100644
index 0000000..a35de10
--- /dev/null
+++ b/src/library/os/cpu_info.hpp
@@ -0,0 +1,39 @@
+/*
+ * cpu_info.h
+ *
+ *  Created on: Dec 14, 2019
+ *      Author: devel
+ */
+
+#ifndef SRC_LIBRARY_OS_CPU_INFO_H_
+#define SRC_LIBRARY_OS_CPU_INFO_H_
+#include <string>
+namespace license {
+namespace os {
+typedef enum { BARE_TO_METAL, VMWARE, VIRTUALBOX, V_XEN, KVM, HV, V_OTHER } VIRTUALIZATION_DETAIL;
+
+/**
+ * Cpu informations
+ */
+class CpuInfo {
+private:
+	bool is_hypervisor_set() const;
+	const std::string m_vendor;
+	const std::string m_brand;
+public:
+	CpuInfo();
+	virtual ~CpuInfo();
+	/**
+	 * Detect Virtual machine using hypervisor bit or the cpu vendor name.
+	 * @return true if the cpu is detected to be a virtual cpu
+	 */
+	bool cpu_virtual() const;
+	uint32_t model() const;
+	const std::string& vendor() const { return m_vendor; }
+	const std::string& brand() const { return m_brand; }
+	VIRTUALIZATION_DETAIL virtualization_details() const;
+};
+
+}  // namespace os
+}  // namespace license
+#endif /* SRC_LIBRARY_OS_CPU_INFO_H_ */
diff --git a/src/library/os/cpu_info_common.cpp b/src/library/os/cpu_info_common.cpp
new file mode 100644
index 0000000..1ddf5ba
--- /dev/null
+++ b/src/library/os/cpu_info_common.cpp
@@ -0,0 +1,45 @@
+/*
+ * cpu_info_common.cpp
+ *
+ *  Created on: Jan 19, 2020
+ *      Author: GC
+ */
+#include <unordered_map>
+#include "cpu_info.hpp"
+
+namespace license {
+namespace os {
+using namespace std;
+
+const unordered_map<string, VIRTUALIZATION_DETAIL> virtual_cpu_names{
+	{"bhyve bhyve ", V_OTHER}, {"KVMKVMKVM", KVM},		  {"Microsoft Hv", HV},
+	{" lrpepyh vr", HV},	   {"prl hyperv  ", V_OTHER}, {"VMwareVMware", VMWARE},
+	{"XenVMMXenVMM", V_XEN},   {"ACRNACRNACRN", V_OTHER}, {"VBoxVBoxVBox", VIRTUALBOX}};
+
+/**
+ * Detect Virtual machine using hypervisor bit.
+ * @return true if the cpu hypervisor bit is set to 1
+ */
+bool CpuInfo::cpu_virtual() const {
+	bool is_virtual = is_hypervisor_set();
+	if (!is_virtual) {
+		string cpu_vendor = vendor();
+		auto it = virtual_cpu_names.find(cpu_vendor);
+		is_virtual = (it != virtual_cpu_names.end());
+	}
+	return is_virtual;
+}
+
+VIRTUALIZATION_DETAIL CpuInfo::virtualization_details() const {
+	string cpu_vendor = vendor();
+	auto it = virtual_cpu_names.find(cpu_vendor);
+	VIRTUALIZATION_DETAIL result = BARE_TO_METAL;
+	if (it != virtual_cpu_names.end()) {
+		result = it->second;
+	} else if (is_hypervisor_set()) {
+		result = (VIRTUALIZATION_DETAIL)V_OTHER;
+	}
+	return result;
+}
+}  // namespace os
+}  // namespace license
diff --git a/src/library/os/execution_environment.hpp b/src/library/os/execution_environment.hpp
new file mode 100644
index 0000000..97172e4
--- /dev/null
+++ b/src/library/os/execution_environment.hpp
@@ -0,0 +1,63 @@
+/*
+ * virtualization.hpp
+ *
+ *  Created on: Dec 15, 2019
+ *      Author: GC
+ */
+
+#ifndef SRC_LIBRARY_OS_VIRTUALIZATION_HPP_
+#define SRC_LIBRARY_OS_VIRTUALIZATION_HPP_
+
+#include <string>
+
+namespace license {
+namespace os {
+
+/*
+ * windows bios sometimes reports vm names add execution environment detection from bios
+const char *vmVendors[] = {
+	"VMware", "Microsoft Corporation", "Virtual Machine", "innotek GmbH", "PowerVM", "Bochs", "KVM"};
+*/
+
+typedef enum { NONE, CONTAINER, VM } VIRTUALIZATION;
+
+typedef enum {
+	PROV_UNKNOWN,
+	ON_PREMISE,
+	GOOGLE_CLOUD,
+	AZURE_CLOUD,
+	AWS,
+	/**
+	 * "/sys/class/dmi/id/bios_vendor" SeaBIOS
+	 * "/sys/class/dmi/id/sys_vendor" Alibaba Cloud
+	 * modalias
+	 * "dmi:bvnSeaBIOS:bvrrel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org:bd04/01/2014:svnAlibabaCloud:pnAlibabaCloudECS:pvrpc-i440fx-2.1:cvnAlibabaCloud:ct1:cvrpc-i440fx-2.1:"
+	 */
+	ALI_CLOUD
+} CLOUD_PROVIDER;
+
+class ExecutionEnvironment {
+private:
+	std::string m_sys_vendor;
+	std::string m_bios_vendor;
+	std::string m_bios_description;
+
+public:
+	ExecutionEnvironment();
+	~ExecutionEnvironment(){};
+	VIRTUALIZATION getVirtualization() const;
+	bool is_cloud() const;
+	bool is_docker() const;
+	// detect if it's a kind of container technology (docker or lxc)
+	bool is_container() const;
+	CLOUD_PROVIDER getCloudProvider() const;
+	const std::string& bios_vendor() const { return m_bios_vendor; };
+	const std::string& sys_vendor() const { return m_sys_vendor; };
+	const std::string& bios_description() const { return m_bios_description; };
+	// VIRTUALIZATION_DETAIL getVirtualizationDetail() const; //as reported by the bios
+};
+
+}  // namespace os
+}  // namespace license
+
+#endif /* SRC_LIBRARY_OS_VIRTUALIZATION_HPP_ */
diff --git a/src/library/os/execution_environment_common.cpp b/src/library/os/execution_environment_common.cpp
new file mode 100644
index 0000000..06f5c56
--- /dev/null
+++ b/src/library/os/execution_environment_common.cpp
@@ -0,0 +1,59 @@
+/*
+ *
+ *  Created on: Feb 23, 2020
+ *      Author: GC
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unordered_map>
+#include <array>
+
+#include "../base/base.h"
+#include "cpu_info.hpp"
+#include "execution_environment.hpp"
+
+namespace license {
+namespace os {
+using namespace std;
+
+VIRTUALIZATION ExecutionEnvironment::getVirtualization() const {
+	VIRTUALIZATION result;
+	CpuInfo cpuInfo;
+	bool isContainer = is_container();
+	if (isContainer) {
+		result = CONTAINER;
+	} else if (cpuInfo.cpu_virtual() || is_cloud()) {
+		result = VM;
+	} else {
+		result = NONE;
+	}
+	return result;
+}
+
+bool ExecutionEnvironment::is_cloud() const {
+	CLOUD_PROVIDER prov = getCloudProvider();
+	return prov != ON_PREMISE && prov != PROV_UNKNOWN;
+}
+
+// TODO test and azure
+CLOUD_PROVIDER ExecutionEnvironment::getCloudProvider() const {
+	CLOUD_PROVIDER result = PROV_UNKNOWN;
+	if (m_bios_description.size() > 0 || m_bios_vendor.size() > 0 || m_sys_vendor.size() > 0) {
+		if (m_bios_vendor.find("SEABIOS") != string::npos || m_bios_description.find("ALIBABA") != string::npos ||
+			m_sys_vendor.find("ALIBABA") != string::npos) {
+			result = ALI_CLOUD;
+		} else if (m_sys_vendor.find("GOOGLE") != string::npos || m_bios_description.find("GOOGLE") != string::npos) {
+			result = GOOGLE_CLOUD;
+		} else if (m_bios_vendor.find("AWS") != string::npos || m_bios_description.find("AMAZON") != string::npos ||
+				   m_sys_vendor.find("AWS") != string::npos) {
+			result = AWS;
+		} else if (m_bios_description.find("HP-COMPAQ") != string::npos || m_bios_description.find("ASUS") ||
+				   m_bios_description.find("DELL")) {
+			result = ON_PREMISE;
+		}
+	}
+	return result;
+}
+}  // namespace os
+}  // namespace license
diff --git a/src/library/os/linux/cpu_info.cpp b/src/library/os/linux/cpu_info.cpp
new file mode 100644
index 0000000..37620cb
--- /dev/null
+++ b/src/library/os/linux/cpu_info.cpp
@@ -0,0 +1,76 @@
+/*
+ * cpu_info.cpp
+ *
+ *  Created on: Dec 14, 2019
+ *      Author: devel
+ */
+
+#include <cpuid.h>
+#include <string>
+#include <unordered_set>
+#include <memory.h>
+#include "../cpu_info.hpp"
+
+namespace license {
+namespace os {
+using namespace std;
+
+struct CPUVendorID {
+	unsigned int ebx;
+	unsigned int edx;
+	unsigned int ecx;
+
+	string toString() const { return string(reinterpret_cast<const char *>(this), 12); }
+};
+
+static string get_cpu_vendor() {
+	unsigned int level = 0, eax = 0, ebx = 0, ecx = 0, edx = 0;
+	// hypervisor flag false, try to get the vendor name, see if it's a virtual cpu
+	__get_cpuid(level, &eax, &ebx, &ecx, &edx);
+	CPUVendorID vendorID{.ebx = ebx, .edx = edx, .ecx = ecx};
+	return vendorID.toString();
+}
+
+// https://en.wikipedia.org/wiki/CPUID
+static string get_cpu_brand() {
+	string result;
+	uint32_t brand[0x10];
+
+	if (!__get_cpuid_max(0x80000004, NULL)) {
+		result = "NA";
+	} else {
+		memset(brand, 0, sizeof(brand));
+		__get_cpuid(0x80000002, brand + 0x0, brand + 0x1, brand + 0x2, brand + 0x3);
+		__get_cpuid(0x80000003, brand + 0x4, brand + 0x5, brand + 0x6, brand + 0x7);
+		__get_cpuid(0x80000004, brand + 0x8, brand + 0x9, brand + 0xa, brand + 0xb);
+		result = string(reinterpret_cast<char *>(brand));
+	}
+	return result;
+}
+
+CpuInfo::CpuInfo() : m_vendor(get_cpu_vendor()), m_brand(get_cpu_brand()) {}
+
+CpuInfo::~CpuInfo() {}
+/**
+ * Detect Virtual machine using hypervisor bit.
+ * @return true if the cpu hypervisor bit is set to 1
+ */
+bool CpuInfo::is_hypervisor_set() const {
+	unsigned int level = 1, eax = 0, ebx = 0, ecx = 0, edx = 0;
+	__get_cpuid(level, &eax, &ebx, &ecx, &edx);
+
+	bool is_virtual = (((ecx >> 31) & 1) == 1);  // hypervisor flag
+	return is_virtual;
+}
+
+uint32_t CpuInfo::model() const {
+	unsigned int level = 1, eax = 0, ebx = 0, ecx = 0, edx = 0;
+	__get_cpuid(level, &eax, &ebx, &ecx, &edx);
+	// ax bits 0-3 stepping,4-7 model,8-11 family id,12-13 processor type
+	//        14-15 reserved, 16-19 extended model, 20-27 extended family, 27-31 reserved
+	// bx bits 0-7 brand index
+	return (eax & 0x3FFF) | (eax & 0x3FF8000) >> 2 | (ebx & 0xff) << 24;
+}
+
+}  // namespace os
+} /* namespace license */
diff --git a/src/library/os/linux/execution_environment.cpp b/src/library/os/linux/execution_environment.cpp
new file mode 100644
index 0000000..1f14d62
--- /dev/null
+++ b/src/library/os/linux/execution_environment.cpp
@@ -0,0 +1,115 @@
+/*
+ * virtualization.cpp
+ *
+ *  Created on: Dec 15, 2019
+ *      Author: GC
+ */
+#include <paths.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fstream>
+#include <iostream>
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/utsname.h>
+
+#include "../../base/base.h"
+#include "../cpu_info.hpp"
+#include "../execution_environment.hpp"
+#include "../../base/file_utils.hpp"
+#include "../../base/StringUtils.h"
+
+namespace license {
+namespace os {
+using namespace std;
+
+// 0=NO 1=Docker/2=Lxc
+static int checkContainerProc() {
+	// in docer /proc/self/cgroups contains the "docker" or "lxc" string
+	// https://stackoverflow.com/questions/23513045/how-to-check-if-a-process-is-running-inside-docker-container
+	char path[MAX_PATH] = {0};
+	char proc_path[MAX_PATH], pidStr[64];
+	pid_t pid = getpid();
+	sprintf(pidStr, "%d", pid);
+	strcpy(proc_path, "/proc/");
+	strcat(proc_path, pidStr);
+	strcat(proc_path, "/cgroup");
+
+	FILE *fp;
+	char *line = NULL;
+	size_t len = 0;
+	ssize_t read;
+	int result = 0;
+
+	fp = fopen(proc_path, "r");
+	if (fp == NULL) {
+		return 0;
+	}
+
+	while ((read = getline(&line, &len, fp)) != -1 && result == 0) {
+		// line[len]=0;
+		// printf("Retrieved line of length %zu:\n", read);
+		// printf("%s", line);
+		if (strstr(line, "docker") != NULL) {
+			result = 1;
+		}
+		if (strstr(line, "lxc") != NULL) {
+			result = 2;
+		}
+	}
+
+	fclose(fp);
+	if (line) free(line);
+	return result;
+}
+
+// 0=NO 1=Docker/2=Lxc
+static int checkSystemdContainer() {
+	ifstream systemd_container("/var/run/systemd/container");
+	int result = 0;
+	if (systemd_container.good()) {
+		result = 1;
+		for (string line; getline(systemd_container, line);) {
+			if (line.find("docker") != string::npos) {
+				result = 1;
+				break;
+			} else if (line.find("lxc") != string::npos) {
+				result = 2;
+				break;
+			}
+		}
+	}
+	return result;
+}
+
+ExecutionEnvironment::ExecutionEnvironment() {
+	try {
+		m_bios_vendor = toupper_copy(trim_copy(get_file_contents("/sys/class/dmi/id/sys_vendor", 256)));
+
+	} catch (...) {
+	}
+	try {
+		m_bios_description = toupper_copy(trim_copy(get_file_contents("/sys/class/dmi/id/modalias", 256)));
+		char last_char = m_bios_description[m_bios_description.length() - 1];
+		if (last_char == '\r' || last_char == '\n') {
+			m_bios_description = m_bios_description.erase(m_bios_description.length() - 1);
+		}
+	} catch (...) {
+	}
+	try {
+		m_sys_vendor = get_file_contents("/sys/class/dmi/id/sys_vendor", 256);
+		char last_char = m_sys_vendor[m_sys_vendor.length() - 2];
+		if (last_char == '\r' || last_char == '\n') {
+			m_sys_vendor = m_sys_vendor.erase(m_sys_vendor.length() - 1);
+		}
+	} catch (...) {
+	}
+}
+
+bool ExecutionEnvironment::is_container() const { return (checkContainerProc() != 0 || checkSystemdContainer() != 0); }
+
+bool ExecutionEnvironment::is_docker() const { return (checkContainerProc() == 1 || checkSystemdContainer() == 1); }
+
+}  // namespace os
+}  // namespace license
diff --git a/src/library/os/linux/network.cpp b/src/library/os/linux/network.cpp
new file mode 100644
index 0000000..1f7a76a
--- /dev/null
+++ b/src/library/os/linux/network.cpp
@@ -0,0 +1,125 @@
+/**
+ * @file network_id.c
+ * @date 16 Sep 2014
+ * @brief File containing network interface detection functions for Linux.
+ *
+ * The only public function of this module is #getAdapterInfos(OsAdapterInfo *,
+ *		size_t *), other functions are either static or inline.
+ *
+ * Responsibility of this module is to fill OsAdapterInfo structures, in a
+ * predictable way (skip "lo" interfaces,
+ * @TODO: place physical interfaces in front in a repeatable order: "eth", "wlan","ib"
+ * and other interfaces later, first the one with a a specified mac address, then
+ * the ones with only an ip.)
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE /* To get defns of NI_MAXSERV and NI_MAXHOST */
+#endif
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <ifaddrs.h>
+#include <linux/if_link.h>
+#include <netpacket/packet.h>
+#include <stdio.h>
+#include <unordered_map>
+#include <string.h>
+#include <memory.h>
+
+#include "../../base/StringUtils.h"
+#include "../../base/logger.h"
+#include "../network.hpp"
+
+namespace license {
+namespace os {
+using namespace std;
+
+
+/**
+ *
+ * @param adapterInfos
+ * @param adapter_info_size
+ * @return
+ */
+FUNCTION_RETURN getAdapterInfos(vector<OsAdapterInfo> &adapterInfos) {
+	unordered_map<string, OsAdapterInfo> adapterByName;
+
+	FUNCTION_RETURN f_return = FUNC_RET_OK;
+	struct ifaddrs *ifaddr, *ifa;
+	int family, n = 0;
+	unsigned int if_num, if_max;
+
+	if (getifaddrs(&ifaddr) == -1) {
+		LOG_WARN("getifaddrs failed == -1");
+		return FUNC_RET_ERROR;
+	}
+
+	for (ifa = ifaddr, n = 0, if_num = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
+		if (ifa->ifa_addr == NULL || (ifa->ifa_flags & IFF_LOOPBACK) != 0) {
+			continue;
+		}
+		string if_name(ifa->ifa_name, mstrnlen_s(ifa->ifa_name, NI_MAXHOST));
+		// if_name_position = ifname_position(ifnames, ifa->ifa_name, if_num);
+		// interface name not seen en advance
+		OsAdapterInfo *currentAdapter;
+		// FIXME not working
+		if (adapterByName.find(if_name) == adapterByName.end()) {
+			OsAdapterInfo newAdapter;
+			memset(&newAdapter, 0, sizeof(OsAdapterInfo));
+			strncpy(&newAdapter.description[0], ifa->ifa_name, NI_MAXHOST);
+			adapterByName[if_name] = newAdapter;
+		}
+		auto it = adapterByName.find(if_name);
+		currentAdapter = &it->second;
+		family = ifa->ifa_addr->sa_family;
+		/* Display interface name and family (including symbolic
+		 form of the latter for the common families) */
+#ifdef _DEBUG
+		printf("%-8s %s (%d)\n", ifa->ifa_name,
+			   (family == AF_PACKET) ? "AF_PACKET"
+									 : (family == AF_INET) ? "AF_INET" : (family == AF_INET6) ? "AF_INET6" : "???",
+			   family);
+#endif
+		/* For an AF_INET* interface address, display the address
+		 * || family == AF_INET6*/
+		if (family == AF_INET) {
+			struct sockaddr_in *s1 = (struct sockaddr_in *)ifa->ifa_addr;
+			in_addr_t iaddr = s1->sin_addr.s_addr;
+			currentAdapter->ipv4_address[0] = (iaddr & 0x000000ff);
+			currentAdapter->ipv4_address[1] = (iaddr & 0x0000ff00) >> 8;
+			currentAdapter->ipv4_address[2] = (iaddr & 0x00ff0000) >> 16;
+			currentAdapter->ipv4_address[3] = (iaddr & 0xff000000) >> 24;
+
+		} else if (family == AF_PACKET && ifa->ifa_data != NULL) {
+			struct sockaddr_ll *s1 = (struct sockaddr_ll *)ifa->ifa_addr;
+			int i;
+			for (i = 0; i < 6; i++) {
+				currentAdapter->mac_address[i] = s1->sll_addr[i];
+#ifdef _DEBUG
+				printf("%02x:", s1->sll_addr[i]);
+#endif
+			}
+#ifdef _DEBUG
+			printf("\t %s\n", ifa->ifa_name);
+#endif
+		}
+	}
+	freeifaddrs(ifaddr);
+
+	// FIXME sort by eth , enps, wlan
+	if (adapterByName.size() == 0) {
+		f_return = FUNC_RET_NOT_AVAIL;
+	} else {
+		f_return = FUNC_RET_OK;
+		adapterInfos.reserve(adapterByName.size());
+		for (auto &it : adapterByName) {
+			adapterInfos.push_back(it.second);
+		}
+	}
+	return f_return;
+}
+
+}  // namespace os
+}  // namespace license
diff --git a/src/library/os/os-linux.c b/src/library/os/linux/os_linux.cpp
similarity index 72%
rename from src/library/os/os-linux.c
rename to src/library/os/linux/os_linux.cpp
index 00409cc..57fb028 100644
--- a/src/library/os/os-linux.c
+++ b/src/library/os/linux/os_linux.cpp
@@ -1,9 +1,8 @@
 #include <paths.h>
 #include <sys/stat.h>
-#include "os.h"
-#include "../base/logger.h"
-#include <openssl/pem.h>
-#include <openssl/err.h>
+#include <stdio.h>
+#include "../os.h"
+#include "../../base/logger.h"
 
 #include <mntent.h>
 #include <dirent.h>
@@ -112,7 +111,9 @@
 				if (strcmp(ent->mnt_dir, "/") == 0) {
 					strcpy(tmpDrives[drive_found].label, "root");
 					LOG_DEBUG("drive %s set to preferred\n", ent->mnt_fsname);
-					tmpDrives[drive_found].preferred = true;
+					tmpDrives[drive_found].preferred = 1;
+				} else {
+					tmpDrives[drive_found].preferred = 0;
 				}
 			}
 		}
@@ -170,27 +171,9 @@
 	} else {
 		result = FUNC_RET_BUFFER_TOO_SMALL;
 	}
-	/*
-	 FILE *mounts = fopen(_PATH_MOUNTED, "r");
-	 if (mounts == NULL) {
-	 return ERROR;
-	 }
-
-	 while (fscanf(mounts, "%64s %64s %64s %1024[^\n]", device, name, type,
-	 discard) != EOF) {
-	 if (stat(device, &mount_stat) != 0)
-	 continue;
-	 if (filename_stat.st_dev == mount_stat.st_rdev) {
-	 fprintf(stderr, "device: %s; name: %s; type: %s\n", device, name,
-	 type);
-	 }
-	 }
-	 */
 	free(statDrives);
 	return result;
 }
-
-void os_initialize() {}
 
 static void _getCpuid(unsigned int *p, unsigned int ax) {
 	__asm __volatile(
@@ -212,78 +195,7 @@
 	return FUNC_RET_OK;
 }
 
-// 0=NO 1=Docker/Lxc
-static int checkContainerProc() {
-	// in docer /proc/self/cgroups contains the "docker" or "lxc" string
-	// https://stackoverflow.com/questions/23513045/how-to-check-if-a-process-is-running-inside-docker-container
-	char path[MAX_PATH] = {0};
-	char proc_path[MAX_PATH], pidStr[64];
-	pid_t pid = getpid();
-	sprintf(pidStr, "%d", pid);
-	strcpy(proc_path, "/proc/");
-	strcat(proc_path, pidStr);
-	strcat(proc_path, "/cgroup");
 
-	FILE *fp;
-	char *line = NULL;
-	size_t len = 0;
-	ssize_t read;
-	int result = 0;
-
-	fp = fopen(proc_path, "r");
-	if (fp == NULL) {
-		return 0;
-	}
-
-	while ((read = getline(&line, &len, fp)) != -1 && result == 0) {
-		// line[len]=0;
-		// printf("Retrieved line of length %zu:\n", read);
-		// printf("%s", line);
-		if (strstr(line, "docker") != NULL || strstr(line, "lxc") != NULL) {
-			result = 1;
-		}
-	}
-
-	fclose(fp);
-	if (line) free(line);
-	return result;
-}
-
-// 0=NO 1=Docker/Lxc
-static int checkLXC() { return (access("/var/run/systemd/container", F_OK) == 0) ? 1 : 0; }
-
-VIRTUALIZATION getVirtualization() {
-	VIRTUALIZATION result = NONE;
-	int isContainer = checkContainerProc();
-	if (isContainer == 1) {
-		result = CONTAINER;
-	} else if (checkLXC()) {
-		result = CONTAINER;
-	}
-	return result;
-
-	// http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
-	//
-	// bool rc = true;
-	/*__asm__ (
-	 "push   %edx\n"
-	 "push   %ecx\n"
-	 "push   %ebx\n"
-	 "mov    %eax, 'VMXh'\n"
-	 "mov    %ebx, 0\n" // any value but not the MAGIC VALUE
-	 "mov    %ecx, 10\n"// get VMWare version
-	 "mov    %edx, 'VX'\n"// port number
-	 "in     %eax, dx\n"// read port on return EAX returns the VERSION
-	 "cmp    %ebx, 'VMXh'\n"// is it a reply from VMWare?
-	 "setz   [rc] \n"// set return value
-	 "pop    %ebx \n"
-	 "pop    %ecx \n"
-	 "pop    %edx \n"
-	 );*/
-
-	// systemd-detect-virt
-	return NONE;
-}
 
 FUNCTION_RETURN getMachineName(unsigned char identifier[6]) {
 	static struct utsname u;
diff --git a/src/library/os/network.hpp b/src/library/os/network.hpp
new file mode 100644
index 0000000..6ba1611
--- /dev/null
+++ b/src/library/os/network.hpp
@@ -0,0 +1,32 @@
+/*
+ * network.hpp
+ *
+ *  Created on: Feb 8, 2020
+ *      Author: devel
+ */
+
+#ifndef SRC_LIBRARY_OS_NETWORK_HPP_
+#define SRC_LIBRARY_OS_NETWORK_HPP_
+#include <stdlib.h>
+#include <vector>
+
+#include "../base/base.h"
+
+namespace license {
+namespace os {
+
+typedef enum { IFACE_TYPE_ETHERNET, IFACE_TYPE_WIRELESS } IFACE_TYPE;
+
+typedef struct {
+	int id;
+	char description[1024];
+	unsigned char mac_address[8];
+	unsigned char ipv4_address[4];
+	IFACE_TYPE type;
+} OsAdapterInfo;
+
+FUNCTION_RETURN getAdapterInfos(std::vector<OsAdapterInfo>& adapterInfos);
+
+}  // namespace os
+}  // namespace license
+#endif /* SRC_LIBRARY_OS_NETWORK_HPP_ */
diff --git a/src/library/os/network_id.c b/src/library/os/network_id.c
deleted file mode 100644
index 556ef49..0000000
--- a/src/library/os/network_id.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/**
- * @file network_id.c
- * @date 16 Sep 2014
- * @brief File containing network interface detection functions for Linux.
- *
- * The only public function of this module is #getAdapterInfos(OsAdapterInfo *,
- *		size_t *), other functions are either static or inline.
- *
- * Responsibility of this module is to fill OsAdapterInfo structures, in a
- * predictable way (skip "lo" interfaces,
- * @TODO: place physical interfaces in front in a repeatable order: "eth", "wlan","ib"
- * and other interfaces later, first the one with a a specified mac address, then
- * the ones with only an ip.)
- */
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE     /* To get defns of NI_MAXSERV and NI_MAXHOST */
-#endif
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <ifaddrs.h>
-#include <linux/if_link.h>
-#include <netpacket/packet.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "os.h"
-
-/**
- *
- * @param ifnames
- * @param ifname
- * @param ifnames_max
- * @return
- */
-
-static int ifname_position(char *ifnames, char * ifname, int ifnames_max) {
-	int i, position;
-	position = -1;
-	for (i = 0; i < ifnames_max; i++) {
-		if (strcmp(ifname, &ifnames[i * NI_MAXHOST]) == 0) {
-			position = i;
-			break;
-		}
-	}
-	return position;
-}
-
-/**
- *
- * @param adapterInfos
- * @param adapter_info_size
- * @return
- */
-FUNCTION_RETURN getAdapterInfos(OsAdapterInfo * adapterInfos,
-		size_t * adapter_info_size) {
-
-	FUNCTION_RETURN f_return = FUNC_RET_OK;
-	struct ifaddrs *ifaddr, *ifa;
-	int family, n = 0, if_name_position;
-	unsigned int if_num, if_max;
-	//char host[NI_MAXHOST];
-	char *ifnames;
-
-	if (getifaddrs(&ifaddr) == -1) {
-		perror("getifaddrs");
-		return FUNC_RET_ERROR;
-	}
-
-	if (adapterInfos != NULL) {
-		memset(adapterInfos, 0, (*adapter_info_size) * sizeof(OsAdapterInfo));
-	}
-
-	/* count the maximum number of interfaces */
-	for (ifa = ifaddr, if_max = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
-		if (ifa->ifa_addr == NULL) {
-			continue;
-		}
-		if_max++;
-	}
-
-	/* allocate space for names */
-	ifnames = (char*) malloc(NI_MAXHOST * if_max);
-	memset(ifnames, 0, NI_MAXHOST * if_max);
-	/* Walk through linked list, maintaining head pointer so we
-	 can free list later */
-	for (ifa = ifaddr, n = 0, if_num = 0; ifa != NULL;
-			ifa = ifa->ifa_next, n++) {
-		if (ifa->ifa_addr == NULL) {
-			continue;
-		}
-		if_name_position = ifname_position(ifnames, ifa->ifa_name, if_num);
-		//interface name not seen en advance
-		if (if_name_position < 0) {
-			strncpy(&ifnames[if_num * NI_MAXHOST], ifa->ifa_name, NI_MAXHOST);
-			if (adapterInfos != NULL && if_num < *adapter_info_size) {
-				strncpy(adapterInfos[if_num].description, ifa->ifa_name,
-				NI_MAXHOST-1);
-			}
-			if_name_position = if_num;
-			if_num++;
-			if (adapterInfos == NULL) {
-				continue;
-			}
-		}
-		family = ifa->ifa_addr->sa_family;
-		/* Display interface name and family (including symbolic
-		 form of the latter for the common families) */
-#ifdef _DEBUG
-		printf("%-8s %s (%d)\n", ifa->ifa_name,
-				(family == AF_PACKET) ? "AF_PACKET" :
-				(family == AF_INET) ? "AF_INET" :
-				(family == AF_INET6) ? "AF_INET6" : "???", family);
-#endif
-		/* For an AF_INET* interface address, display the address
-		 * || family == AF_INET6*/
-		if (family == AF_INET) {
-			/*
-			 s = getnameinfo(ifa->ifa_addr,
-			 (family == AF_INET) ?
-			 sizeof(struct sockaddr_in) :
-			 sizeof(struct sockaddr_in6), host, NI_MAXHOST,
-			 NULL, 0, NI_NUMERICHOST);
-
-			 #ifdef _DEBUG
-			 s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host,
-			 NI_MAXHOST,
-			 NULL, 0, NI_NUMERICHOST);
-			 if (s != 0) {
-			 printf("getnameinfo() failed: %s\n", gai_strerror(s));
-			 }
-			 printf("\t\taddress: <%s>\n", host);
-			 #endif
-			 */
-			if (adapterInfos != NULL && if_name_position < *adapter_info_size) {
-				struct sockaddr_in *s1 = (struct sockaddr_in*) ifa->ifa_addr;
-				in_addr_t iaddr = s1->sin_addr.s_addr;
-				adapterInfos[if_name_position].ipv4_address[0] = (iaddr
-						& 0x000000ff);
-				adapterInfos[if_name_position].ipv4_address[1] = (iaddr
-						& 0x0000ff00) >> 8;
-				adapterInfos[if_name_position].ipv4_address[2] = (iaddr
-						& 0x00ff0000) >> 16;
-				adapterInfos[if_name_position].ipv4_address[3] = (iaddr
-						& 0xff000000) >> 24;
-			}
-		} else if (family == AF_PACKET && ifa->ifa_data != NULL) {
-			struct sockaddr_ll *s1 = (struct sockaddr_ll*) ifa->ifa_addr;
-			if (adapterInfos != NULL && if_name_position < *adapter_info_size) {
-				int i;
-				for (i = 0; i < 6; i++) {
-					adapterInfos[if_name_position].mac_address[i] =
-							s1->sll_addr[i];
-#ifdef _DEBUG
-					printf("%02x:", s1->sll_addr[i]);
-#endif
-				}
-#ifdef _DEBUG
-				printf("\t %s\n", ifa->ifa_name);
-#endif
-
-			}
-		}
-	}
-
-	*adapter_info_size = if_num;
-	if (adapterInfos == NULL) {
-		f_return = FUNC_RET_OK;
-	} else if (*adapter_info_size < if_num) {
-		f_return = FUNC_RET_BUFFER_TOO_SMALL;
-	}
-	freeifaddrs(ifaddr);
-	free(ifnames);
-	return f_return;
-}
diff --git a/src/library/os/openssl/signature_verifier.cpp b/src/library/os/openssl/signature_verifier.cpp
index 700210b..14063b9 100644
--- a/src/library/os/openssl/signature_verifier.cpp
+++ b/src/library/os/openssl/signature_verifier.cpp
@@ -10,16 +10,17 @@
 #include <stdlib.h>
 #include <errno.h>
 
-#ifdef _WIN32
-#include <windows.h>
-#endif
+//#ifdef _WIN32
+//#include <windows.h>
+//#endif
 
 #include <public_key.h>
 
-#include "../signature_verifier.h"
+#include "../signature_verifier.hpp"
+#include "../../base/logger.h"
 
 namespace license {
-#include "../../base/logger.h"
+namespace os {
 
 static void free_resources(EVP_PKEY* pkey, EVP_MD_CTX* mdctx) {
 	if (pkey) {
@@ -103,5 +104,5 @@
 	free_resources(pkey, mdctx);
 	return result;
 }
-
+}  // namespace os
 } /* namespace license */
diff --git a/src/library/os/os-win.c b/src/library/os/os-win.c
deleted file mode 100644
index eab2f28..0000000
--- a/src/library/os/os-win.c
+++ /dev/null
@@ -1,214 +0,0 @@
-#ifdef _MSC_VER
-#include <Windows.h>
-#endif
-#include "../base/logger.h"
-#include "os.h"
-#include <iphlpapi.h>
-#include <stdio.h>
-#pragma comment(lib, "IPHLPAPI.lib")
-
-unsigned char* unbase64(const char* ascii, int len, int *flen);
-
-FUNCTION_RETURN getOsSpecificIdentifier(unsigned char identifier[6]) {
-	return FUNC_RET_NOT_AVAIL;
-}
-
-FUNCTION_RETURN getMachineName(unsigned char identifier[6]) {
-	FUNCTION_RETURN result = FUNC_RET_ERROR;
-	char buffer[MAX_COMPUTERNAME_LENGTH + 1];
-	int bufsize = MAX_COMPUTERNAME_LENGTH + 1;
-	const BOOL cmpName = GetComputerName(buffer, (unsigned long*)&bufsize);
-	if (cmpName) {
-		strncpy((char*)identifier, buffer, 6);
-		result = FUNC_RET_OK;
-	}
-	return result;
-}
-
-FUNCTION_RETURN getCpuId(unsigned char identifier[6]) {
-	return FUNC_RET_NOT_AVAIL;
-}
-
-void os_initialize() {
-}
-
-//http://www.ok-soft-gmbh.com/ForStackOverflow/EnumMassStorage.c
-//http://stackoverflow.com/questions/3098696/same-code-returns-diffrent-result-on-windows7-32-bit-system
-#define MAX_UNITS 30
-//bug check return with diskinfos == null func_ret_ok
-FUNCTION_RETURN getDiskInfos(DiskInfo * diskInfos, size_t * disk_info_size) {
-	DWORD FileMaxLen;
-	int ndrives = 0;
-	DWORD FileFlags;
-	char volName[_MAX_FNAME], FileSysName[_MAX_FNAME];
-	DWORD volSerial = 0;
-	const DWORD dwSize = MAX_PATH;
-
-	char szLogicalDrives[MAX_PATH] = { 0 };
-    unsigned char buf[8] = "";
-
-	FUNCTION_RETURN return_value = FUNC_RET_NOT_AVAIL;
-	const DWORD dwResult = GetLogicalDriveStrings(dwSize, szLogicalDrives);
-
-	if (dwResult > 0 && dwResult <= MAX_PATH) {
-		return_value = FUNC_RET_OK;
-		char* szSingleDrive = szLogicalDrives;
-		while (*szSingleDrive && ndrives < MAX_UNITS) {
-
-			// get the next drive
-			UINT driveType = GetDriveType(szSingleDrive);
-			if (driveType == DRIVE_FIXED) {
-				BOOL success = GetVolumeInformation(szSingleDrive, volName, MAX_PATH,
-				                                    &volSerial, &FileMaxLen, &FileFlags, FileSysName,
-				                                    MAX_PATH);
-				if (success) {
-					LOG_INFO("drive         : %s", szSingleDrive);
-					LOG_INFO("Volume Name   : %s", volName);
-					LOG_INFO("Volume Serial : 0x%x", volSerial);
-					LOG_DEBUG("Max file length : %d", FileMaxLen);
-					LOG_DEBUG("Filesystem      : %s", FileSysName);
-					if (diskInfos != NULL) {
-						if (ndrives < (int)*disk_info_size) {
-							diskInfos[ndrives].id = ndrives;
-							strncpy(diskInfos[ndrives].device, volName, MAX_PATH);
-							strncpy(diskInfos[ndrives].label, FileSysName, MAX_PATH);
-                            memcpy(diskInfos[ndrives].disk_sn, &buf, sizeof(buf));
-							memcpy(diskInfos[ndrives].disk_sn, &volSerial, sizeof(DWORD));
-							diskInfos[ndrives].preferred = (strncmp(szSingleDrive, "C", 1) != 0);
-						} else {
-							return_value = FUNC_RET_BUFFER_TOO_SMALL;
-						}
-					}
-					ndrives++;
-				} else {
-					LOG_WARN("Unable to retrieve information of '%s'", szSingleDrive);
-				}
-			} else {
-				LOG_INFO("This volume is not fixed : %s, type: %d",	szSingleDrive);
-			}
-			szSingleDrive += strlen(szSingleDrive) + 1;
-		}
-	}
-	if (diskInfos == NULL || *disk_info_size == 0) {
-		if (ndrives > 0) {
-			return_value = FUNC_RET_OK;
-		} else {
-			return_value = FUNC_RET_NOT_AVAIL;
-			LOG_INFO("No fixed drive was detected");
-		}
-		*disk_info_size = ndrives;
-	} else {
-		*disk_info_size = min(ndrives, *disk_info_size);
-	}
-	return return_value;
-}
-
-static int translate(char ipStringIn[16], unsigned char ipv4[4]) {
-	size_t index = 0;
-
-	char* str2 = ipStringIn; /* save the pointer */
-	while (*str2) {
-		if (isdigit((unsigned char) *str2)) {
-			ipv4[index] *= 10;
-			ipv4[index] += *str2 - '0';
-		} else {
-			index++;
-		}
-		str2++;
-	}
-	return 0;
-}
-
-//http://stackoverflow.com/questions/18046063/mac-address-using-c
-//TODO: count only interfaces with type (MIB_IF_TYPE_ETHERNET IF_TYPE_IEEE80211)
-FUNCTION_RETURN getAdapterInfos(OsAdapterInfo * adapterInfos,
-		size_t * adapter_info_size) {
-	DWORD dwStatus;
-	PIP_ADAPTER_INFO pAdapterInfo;
-	//IP_ADAPTER_INFO AdapterInfo[20];              // Allocate information for up to 16 NICs
-	DWORD dwBufLen = sizeof(IP_ADAPTER_INFO); //10 * sizeof(IP_ADAPTER_INFO);  // Save the memory size of buffer
-
-	unsigned int i = 3;
-	do {
-		pAdapterInfo = (PIP_ADAPTER_INFO) malloc(dwBufLen);
-		dwStatus = GetAdaptersInfo(               // Call GetAdapterInfo
-				pAdapterInfo, // [out] buffer to receive data
-				&dwBufLen   // [in] size of receive data buffer
-				);
-		if (dwStatus != NO_ERROR) {
-			free(pAdapterInfo);
-            pAdapterInfo = NULL;
-		}
-	} while (dwStatus == ERROR_BUFFER_OVERFLOW && i-- > 0);
-
-	if (dwStatus == ERROR_BUFFER_OVERFLOW) {
-		return FUNC_RET_ERROR;
-	}
-
-	if (adapterInfos == NULL || *adapter_info_size == 0) {
-		*adapter_info_size = dwBufLen / sizeof(IP_ADAPTER_INFO);
-		if (pAdapterInfo != NULL){
-			free(pAdapterInfo);
-		}
-		return FUNC_RET_OK;
-	}
-
-	*adapter_info_size = dwBufLen / sizeof(IP_ADAPTER_INFO);
-	memset(adapterInfos, 0, dwBufLen);
-	PIP_ADAPTER_INFO pAdapter = pAdapterInfo;
-	i = 0;
-	FUNCTION_RETURN result = FUNC_RET_OK;
-	while (pAdapter) {
-		strncpy(adapterInfos[i].description, pAdapter->Description,
-				min(sizeof(adapterInfos->description),
-						MAX_ADAPTER_DESCRIPTION_LENGTH));
-		memcpy(adapterInfos[i].mac_address, pAdapter->Address, 8);
-		translate(pAdapter->IpAddressList.IpAddress.String,
-				adapterInfos[i].ipv4_address);
-		adapterInfos[i].type = IFACE_TYPE_ETHERNET;
-		i++;
-		pAdapter = pAdapter->Next;
-		if (i == *adapter_info_size) {
-			result = FUNC_RET_BUFFER_TOO_SMALL;
-			break;
-		}
-	}
-	free(pAdapterInfo);
-	return result;
-}
-
-FUNCTION_RETURN getModuleName(char buffer[MAX_PATH]) {
-	FUNCTION_RETURN result = FUNC_RET_OK;
-	const DWORD wres = GetModuleFileName(NULL, buffer, MAX_PATH);
-	if (wres == 0) {
-		result = FUNC_RET_ERROR;
-	}
-	return result;
-}
-
-// TODO: remove unused
-static void printHash(HCRYPTHASH* hHash) {
-	DWORD dwHashLen;
-	DWORD dwHashLenSize = sizeof(DWORD);
-
-	if (CryptGetHashParam(*hHash, HP_HASHSIZE, (BYTE *) &dwHashLen,
-			&dwHashLenSize, 0)) {
-		BYTE* pbHash = (BYTE*)malloc(dwHashLen);
-		char* hashStr = (char*)malloc(dwHashLen * 2 + 1);
-		if (CryptGetHashParam(*hHash, HP_HASHVAL, pbHash, &dwHashLen, 0)) {
-			for (unsigned int i = 0; i < dwHashLen; i++) {
-				sprintf(&hashStr[i * 2], "%02x", pbHash[i]);
-			} LOG_DEBUG("Hash to verify: %s", hashStr);
-		}
-		free(pbHash);
-		free(hashStr);
-	}
-}
-
-/**
- * Not implemented yet.
- */
-VIRTUALIZATION getVirtualization() {
-	return NONE;
-}
-
diff --git a/src/library/os/os.h b/src/library/os/os.h
index f32ca92..fa1862f 100644
--- a/src/library/os/os.h
+++ b/src/library/os/os.h
@@ -12,48 +12,29 @@
 extern "C" {
 #endif
 
-#include "../base/base.h"
 #include <stddef.h>
 #include <string.h>
 #include <ctype.h>
 #include <sys/types.h>
-//definition of size_t
+// definition of size_t
 #include <stdlib.h>
 #ifdef __unix__
 #include <unistd.h>
 #include <stdbool.h>
 #endif
-
-typedef enum {
-	NONE, CONTAINER, VM
-} VIRTUALIZATION;
-
-typedef enum {
-	IFACE_TYPE_ETHERNET, IFACE_TYPE_WIRELESS
-} IFACE_TYPE;
+#include "../base/base.h"
 
 typedef struct {
 	int id;
-	char description[1024];
-	unsigned char mac_address[8];
-	unsigned char ipv4_address[4];
-	IFACE_TYPE type;
-} OsAdapterInfo;
-
-typedef struct {
-	int id;
-	char device[255];
+	char device[MAX_PATH];
 	unsigned char disk_sn[8];
 	char label[255];
-	bool preferred;
+	int preferred;
 } DiskInfo;
 
-FUNCTION_RETURN getAdapterInfos(OsAdapterInfo * adapterInfos,
-		size_t * adapter_info_size);
-FUNCTION_RETURN getDiskInfos(DiskInfo * diskInfos, size_t * disk_info_size);
+FUNCTION_RETURN getDiskInfos(DiskInfo* diskInfos, size_t* disk_info_size);
 FUNCTION_RETURN getUserHomePath(char[MAX_PATH]);
 FUNCTION_RETURN getModuleName(char buffer[MAX_PATH]);
-FUNCTION_RETURN getCpuId(unsigned char identifier[6]);
 FUNCTION_RETURN getMachineName(unsigned char identifier[6]);
 /**
  * Get an identifier of the machine in an os specific way.
@@ -74,17 +55,15 @@
  * @return
  */
 FUNCTION_RETURN getOsSpecificIdentifier(unsigned char identifier[6]);
-VIRTUALIZATION getVirtualization();
-void os_initialize();
 
 // FUNCTION_RETURN verifySignature(const char* stringToVerify, const char* signatureB64);
 
 #ifdef _WIN32
-#define SETENV(VAR,VAL) _putenv_s(VAR, VAL);
-#define	UNSETENV(P) _putenv_s(P, "");
+#define SETENV(VAR, VAL) _putenv_s(VAR, VAL);
+#define UNSETENV(P) _putenv_s(P, "");
 #else
-#define SETENV(VAR,VAL) setenv(VAR, VAL, 1);
-#define	UNSETENV(P)	unsetenv(P);
+#define SETENV(VAR, VAL) setenv(VAR, VAL, 1);
+#define UNSETENV(P) unsetenv(P);
 #endif
 
 #ifdef __cplusplus
diff --git a/src/library/os/signature_verifier.h b/src/library/os/signature_verifier.hpp
similarity index 95%
rename from src/library/os/signature_verifier.h
rename to src/library/os/signature_verifier.hpp
index 4dfe1d0..410b229 100644
--- a/src/library/os/signature_verifier.h
+++ b/src/library/os/signature_verifier.hpp
@@ -12,9 +12,9 @@
 #include "../base/base.h"
 
 namespace license {
-
+namespace os {
 FUNCTION_RETURN verify_signature(const std::string& stringToVerify, const std::string& signatureB64);
-
+}
 } /* namespace license */
 
 #endif /* SRC_LIBRARY_OS_VERIFIER_HPP_ */
diff --git a/src/library/os/windows/cpu_info.cpp b/src/library/os/windows/cpu_info.cpp
new file mode 100644
index 0000000..a58cc6c
--- /dev/null
+++ b/src/library/os/windows/cpu_info.cpp
@@ -0,0 +1,78 @@
+/*
+ * cpu_info.cpp
+ *
+ *  Created on: Dec 14, 2019
+ *      Author: devel
+ */
+
+
+#include <intrin.h>
+#include <string>
+#include <unordered_set>
+#include "../cpu_info.hpp"
+
+namespace license {
+namespace os {
+using namespace std;
+
+static string get_cpu_vendor() {
+	// hypervisor flag false, try to get the vendor name, see if it's a virtual cpu
+	int cpui[4] = {0};
+	__cpuidex(cpui, 0x0, 0x0);
+
+	char vendor[13];
+	memset(vendor, 0, sizeof(vendor));
+	*reinterpret_cast<int *>(vendor) = cpui[1];
+	*reinterpret_cast<int *>(vendor + 4) = cpui[3];
+	*reinterpret_cast<int *>(vendor + 8) = cpui[2];
+	return string(vendor, 12);
+}
+
+static string get_cpu_brand() {
+	int cpui[4] = {0};
+	__cpuid(cpui, 0x80000000);
+	int maxSupported = cpui[0];
+
+	char brand[0x41];
+	memset(brand, 0, sizeof(brand));
+	string result;
+	if (maxSupported >= 0x80000004) {
+		int instruction = 0x80000002;
+		for (int i = 0; i <= 2; ++i) {
+			__cpuidex(cpui, instruction + i, 0);
+			memcpy(&brand[i * sizeof(cpui)], cpui, sizeof(cpui));
+		}
+		result = string(brand);
+	} else {
+		result = "NA";
+	}
+
+	return result;
+}
+
+CpuInfo::CpuInfo() : m_vendor(get_cpu_vendor()), m_brand(get_cpu_brand()) {}
+
+CpuInfo::~CpuInfo() {}
+/**
+ * Detect Virtual machine using hypervisor bit.
+ * @return true if the cpu hypervisor bit is set to 1
+ */
+bool CpuInfo::is_hypervisor_set() const {
+	int cpui[4] = {0};
+	__cpuid(cpui, 0x1);
+
+	return ((cpui[2] >> 31) & 1);
+}
+
+uint32_t CpuInfo::model() const {
+	int cpui[4] = {0};
+	__cpuid(cpui, 0x1);
+	// ax bits 0-3 stepping,4-7 model,8-11 family id,12-13 processor type
+	//        14-15 reserved, 16-19 extended model, 20-27 extended family, 27-31 reserved
+	// bx bits 0-7 brand index
+	return (cpui[0] & 0x3FFF) | (cpui[0] & 0x3FF8000) >> 2 | (cpui[1] & 0xff) << 24;
+}
+
+
+}  // namespace os
+} /* namespace license */
diff --git a/src/library/os/windows/execution_environment.cpp b/src/library/os/windows/execution_environment.cpp
new file mode 100644
index 0000000..3e65bc8
--- /dev/null
+++ b/src/library/os/windows/execution_environment.cpp
@@ -0,0 +1,86 @@
+/*
+ * virtualization.cpp
+ *
+ *  Created on: Dec 15, 2019
+ *      Author: GC
+ */
+#include <windows.h>
+#include <sys/stat.h>
+#include <fstream>
+#include <iostream>
+#include <stdio.h>
+#include <string>
+
+#include "isvm/BIOSReader.h"
+#include "isvm/Native.h"
+#include "../../base/base.h"
+#include "../../base/StringUtils.h"
+#include "../cpu_info.hpp"
+#include "../execution_environment.hpp"
+
+namespace license {
+namespace os {
+using namespace std;
+
+ExecutionEnvironment::ExecutionEnvironment() {
+	if (InitEntryPoints()) {
+		BIOSReader reader;
+		SystemInformation info = reader.readSystemInfo();
+		m_sys_vendor = toupper_copy(info.Manufacturer);
+		m_bios_vendor = toupper_copy(info.ProductName);
+		m_bios_description = toupper_copy(info.SysVersion) + toupper_copy(info.family);
+	}
+}
+
+#define MAX_UNITS 20
+int wine_container() {
+DWORD fileMaxLen;
+size_t ndrives = 0;
+DWORD fileFlags;
+char volName[MAX_PATH], fileSysName[MAX_PATH];
+DWORD volSerial = 0;
+const DWORD dwSize = MAX_PATH;
+char szLogicalDrives[MAX_PATH] = {0};
+
+int result = 0;
+const DWORD dwResult = GetLogicalDriveStrings(dwSize, szLogicalDrives);
+
+if (dwResult > 0 && dwResult <= MAX_PATH) {
+	char* szSingleDrive = szLogicalDrives;
+	while (*szSingleDrive && ndrives < MAX_UNITS) {
+		// get the next drive
+		UINT driveType = GetDriveType(szSingleDrive);
+		if (driveType == DRIVE_FIXED) {
+			string name = szSingleDrive + string("/var/run/systemd/container");
+			try {
+				ifstream systemd_container(name);
+				if (systemd_container.good()) {
+					result = 1;
+					for (string line; getline(systemd_container, line);) {
+						if (line.find("docker") != string::npos) {
+							result = 1;
+							break;
+						} else if (line.find("lxc") != string::npos) {
+							result = 2;
+							break;
+						}
+					}
+				}
+			} catch (...) {
+				//no problem,we're just guessing
+			}
+		}
+	}
+}
+	return result;
+}
+
+bool ExecutionEnvironment::is_docker() const {
+	// let's check we're not in linux under wine ;) ...
+//int cont = wine_container();
+	return false; 
+}
+//TODO
+bool ExecutionEnvironment::is_container() const { return is_docker(); }
+}  // namespace os
+}  // namespace license
diff --git a/src/library/os/windows/isvm/BIOSReader.cpp b/src/library/os/windows/isvm/BIOSReader.cpp
new file mode 100644
index 0000000..3300964
--- /dev/null
+++ b/src/library/os/windows/isvm/BIOSReader.cpp
@@ -0,0 +1,121 @@
+#include "BIOSReader.h"
+
+#include <cstdint>
+
+#include "Native.h"
+
+struct smbios_structure_header {
+	uint8_t type;
+	uint8_t length;
+	uint16_t handle;
+};
+
+//
+//	System information
+//
+struct smbios_type_1 {
+	struct smbios_structure_header header;
+	uint8_t manufacturer_str;
+	uint8_t product_name_str;
+	uint8_t version_str;
+	uint8_t serial_number_str;
+	uint8_t uuid[16];
+	uint8_t wake_up_type;
+	uint8_t sku_number_str;
+	uint8_t family_str;
+};
+
+#define _TYPE_COUNT1 6
+
+#define _CONCATE(x, y) x##y
+#define CONCATE(x, y) _CONCATE(x, y)
+#define TYPE_COUNT(t) CONCATE(_TYPE_COUNT, t)
+
+//
+//	Windows
+//
+#include <windows.h>
+#include <tchar.h>
+
+int8_t *parse_smbiod_content(int8_t *addr, int8_t **indexes, int32_t *count) {
+	//!	ignore 0
+	int8_t parsed_count = 0;
+	int8_t *raw_addr = addr;
+
+	//!	first one
+	if (indexes) *indexes = raw_addr;
+
+	bool reach_terminal = false;
+
+	while (true) {
+		if (0 == *raw_addr++) {
+			if (reach_terminal)
+				break;
+			else {
+				++parsed_count;
+
+				if (count && parsed_count < *count) {
+					if (indexes) *(indexes + parsed_count) = raw_addr;
+				}
+
+				reach_terminal = true;
+			}
+		} else {
+			reach_terminal = false;
+			continue;
+		}
+	}
+
+	if (count) *count = parsed_count;
+
+	return raw_addr;
+}
+
+void read_smbios_type_1(int8_t *addr, SystemInformation *info) {
+	smbios_type_1 *t1 = (smbios_type_1 *)addr;
+
+	int32_t offset = ((0x0F) & (t1->header.length >> 4)) * 16 + (t1->header.length & 0x0F);
+
+	int8_t *string_addr[TYPE_COUNT(1)] = {0};
+
+	int32_t count = TYPE_COUNT(1);
+	parse_smbiod_content((int8_t *)t1 + offset, string_addr, &count);
+
+	if (0 != t1->manufacturer_str)
+		info->Manufacturer = (std::string::traits_type::char_type *)string_addr[t1->manufacturer_str - 1];
+
+	if (0 != t1->product_name_str)
+		info->ProductName = (std::string::traits_type::char_type *)string_addr[t1->product_name_str - 1];
+
+	if (0 != t1->serial_number_str)
+		info->SerialNum = (std::string::traits_type::char_type *)string_addr[t1->serial_number_str - 1];
+
+	if (0 != t1->version_str)
+		info->SysVersion = (std::string::traits_type::char_type *)string_addr[t1->version_str - 1];
+
+	if (0 != t1->family_str) info->family = (std::string::traits_type::char_type *)string_addr[t1->family_str - 1];
+}
+
+SystemInformation BIOSReader::readSystemInfo() {
+	SystemInformation info;
+
+	uint32_t size = 0;
+	RawSMBIOSData *data = (RawSMBIOSData *)(LocateSMBIOS(&size));
+
+	if (NULL == data || 0 == size) return info;
+
+	smbios_structure_header *header = (smbios_structure_header *)(data->SMBIOSTableData);
+
+	while (NULL != header) {
+		if (1 == header->type) {
+			read_smbios_type_1((int8_t *)header, &info);
+			header = NULL;	//!	stop
+		} else {
+			int32_t offset = ((0x0F) & (header->length >> 4)) * 16 + (header->length & 0x0F);
+			header = (smbios_structure_header *)parse_smbiod_content((int8_t *)header + offset, NULL, NULL);
+		}
+	}
+
+	free(data);
+	return info;
+}
diff --git a/src/library/os/windows/isvm/BIOSReader.h b/src/library/os/windows/isvm/BIOSReader.h
new file mode 100644
index 0000000..4fcfb05
--- /dev/null
+++ b/src/library/os/windows/isvm/BIOSReader.h
@@ -0,0 +1,22 @@
+#ifndef BIOSREADER_H
+#define BIOSREADER_H
+
+#include <string>
+
+class SystemInformation
+{
+public:
+    std::string Manufacturer;
+    std::string ProductName;
+    std::string SysVersion;
+    std::string SerialNum;
+	std::string family;
+};
+
+class BIOSReader
+{
+public:
+	SystemInformation readSystemInfo();
+};
+
+#endif
diff --git a/src/library/os/windows/isvm/Native.cpp b/src/library/os/windows/isvm/Native.cpp
new file mode 100644
index 0000000..f8568e6
--- /dev/null
+++ b/src/library/os/windows/isvm/Native.cpp
@@ -0,0 +1,438 @@
+#include "Native.h"
+
+#include <tchar.h>
+
+typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS; // windbgkd
+
+typedef LONG NTSTATUS;
+#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
+
+typedef struct _UNICODE_STRING
+{
+    USHORT Length;
+    USHORT MaximumLength;
+#ifdef MIDL_PASS
+    [size_is(MaximumLength / 2), length_is((Length) / 2)] USHORT * Buffer;
+#else // MIDL_PASS
+    PWSTR  Buffer;
+#endif // MIDL_PASS
+} UNICODE_STRING;
+typedef UNICODE_STRING *PUNICODE_STRING;
+
+typedef enum _SECTION_INHERIT
+{
+    ViewShare = 1,
+    ViewUnmap = 2
+} SECTION_INHERIT;
+
+#define OBJ_INHERIT             0x00000002L
+#define OBJ_PERMANENT           0x00000010L
+#define OBJ_EXCLUSIVE           0x00000020L
+#define OBJ_CASE_INSENSITIVE    0x00000040L
+#define OBJ_OPENIF              0x00000080L
+#define OBJ_OPENLINK            0x00000100L
+#define OBJ_VALID_ATTRIBUTES    0x000001F2L
+
+static bool bIsWindowsXPLater = false;
+static DWORD dwPageSize = 0;
+
+#ifdef _UNICODE
+#define GetVersionExProc "GetVersionExW"
+#else
+#define GetVersionExProc "GetVersionExA"
+#endif
+
+typedef struct _OBJECT_ATTRIBUTES
+{
+    ULONG Length;
+    HANDLE RootDirectory;
+    PUNICODE_STRING ObjectName;
+    ULONG Attributes;
+    PVOID SecurityDescriptor;        // Points to type SECURITY_DESCRIPTOR
+    PVOID SecurityQualityOfService;  // Points to type SECURITY_QUALITY_OF_SERVICE
+} OBJECT_ATTRIBUTES;
+typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;
+
+typedef struct SMBIOSEntryPoint
+{
+    char EntryPointString[4];
+    uint8_t Checksum;
+    uint8_t Length;
+    uint8_t MajorVersion;
+    uint8_t MinorVersion;
+    uint16_t MaxStructureSize;
+    uint8_t EntryPointRevision;
+    char FormattedArea[5];
+    char EntryPointString2[5];
+    uint8_t Checksum2;
+    uint16_t TableLength;
+    uint32_t TableAddress;
+    uint16_t NumberOfStructures;
+    uint8_t BCDRevision;
+} SMBIOSEntryPoint, *PSMBIOSEntryPoint;
+
+#define InitializeObjectAttributes( p, n, a, r, s ) { \
+    (p)->Length = sizeof(OBJECT_ATTRIBUTES);          \
+    (p)->RootDirectory = r;                             \
+    (p)->Attributes = a;                                \
+    (p)->ObjectName = n;                                \
+    (p)->SecurityDescriptor = s;                        \
+    (p)->SecurityQualityOfService = NULL;               \
+}
+
+NTSTATUS(WINAPI *NtUnmapViewOfSection)(
+    IN HANDLE  ProcessHandle,
+    IN PVOID  BaseAddress
+    );
+
+NTSTATUS(WINAPI *NtOpenSection)(
+    OUT PHANDLE  SectionHandle,
+    IN ACCESS_MASK  DesiredAccess,
+    IN POBJECT_ATTRIBUTES  ObjectAttributes
+    );
+
+NTSTATUS(WINAPI *NtMapViewOfSection)(
+    IN HANDLE  SectionHandle,
+    IN HANDLE  ProcessHandle,
+    IN OUT PVOID *BaseAddress,
+    IN ULONG  ZeroBits,
+    IN ULONG  CommitSize,
+    IN OUT PLARGE_INTEGER  SectionOffset,	/* optional */
+    IN OUT PULONG  ViewSize,
+    IN SECTION_INHERIT  InheritDisposition,
+    IN ULONG  AllocationType,
+    IN ULONG  Protect
+    );
+
+VOID(WINAPI *RtlInitUnicodeString)(
+    IN OUT PUNICODE_STRING  DestinationString,
+    IN PCWSTR  SourceString
+    );
+
+ULONG(WINAPI *RtlNtStatusToDosError) (
+    IN NTSTATUS Status
+    );
+
+UINT(WINAPI *Win32GetSystemFirmwareTable)(
+    _In_ DWORD FirmwareTableProviderSignature,
+    _In_ DWORD FirmwareTableID,
+    _Out_writes_bytes_to_opt_(BufferSize, return) PVOID pFirmwareTableBuffer,
+    _In_ DWORD BufferSize);
+
+BOOL(WINAPI *Win32GetVersionEx)(
+    _Inout_  LPOSVERSIONINFO lpVersionInfo
+    );
+
+VOID(WINAPI *Win32GetSystemInfo)(
+    _Out_  LPSYSTEM_INFO lpSystemInfo
+    );
+
+BOOL(WINAPI *Win32VirtualProtect)(
+    _In_   LPVOID lpAddress,
+    _In_   SIZE_T dwSize,
+    _In_   DWORD flNewProtect,
+    _Out_  PDWORD lpflOldProtect
+    );
+
+//----------------------------------------------------------------------
+//
+// PrintError
+//
+// Formats an error message for the last error
+//
+// Mark Russinovich
+// Systems Internals
+// http://www.sysinternals.com
+//----------------------------------------------------------------------
+void PrintError(char *message, NTSTATUS status)
+{
+    char *errMsg;
+
+    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+        NULL, RtlNtStatusToDosError(status),
+        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+        (LPTSTR)&errMsg, 0, NULL);
+    LocalFree(errMsg);
+}
+
+//--------------------------------------------------------
+//
+// UnmapPhysicalMemory
+//
+
+// Maps a view of a section.
+//
+// Mark Russinovich
+// Systems Internals
+// http://www.sysinternals.com
+//--------------------------------------------------------
+static VOID UnmapPhysicalMemory(PVOID Address)
+{
+    NTSTATUS		status;
+
+    status = NtUnmapViewOfSection((HANDLE)-1, Address);
+    if (!NT_SUCCESS(status))
+    {
+        PrintError("Unable to unmap view", status);
+    }
+}
+
+
+//--------------------------------------------------------
+//
+// MapPhysicalMemory
+//
+// Maps a view of a section.
+//
+// Mark Russinovich
+// Systems Internals
+// http://www.sysinternals.com
+//--------------------------------------------------------
+static BOOLEAN MapPhysicalMemory(HANDLE PhysicalMemory,
+    PVOID Address, PDWORD Length,
+    PVOID *VirtualAddress)
+{
+    NTSTATUS			ntStatus;
+    PHYSICAL_ADDRESS	viewBase;
+    char				error[256];
+
+    viewBase.QuadPart = (ULONGLONG)(Address);
+    ntStatus = NtMapViewOfSection(PhysicalMemory,
+        (HANDLE)-1,
+        VirtualAddress,
+        0L, *Length,
+        &viewBase,
+        Length,
+        ViewShare,
+        0,
+        PAGE_READONLY);
+
+    if (!NT_SUCCESS(ntStatus)) {
+
+        PrintError(error, ntStatus);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+
+//--------------------------------------------------------
+//
+// OpensPhysicalMemory
+//
+// This function opens the physical memory device. It
+// uses the native API since 
+//
+// Mark Russinovich
+// Systems Internals
+// http://www.sysinternals.com
+//--------------------------------------------------------
+static HANDLE OpenPhysicalMemory()
+{
+    NTSTATUS		status;
+    HANDLE			physmem;
+    UNICODE_STRING	physmemString;
+    OBJECT_ATTRIBUTES attributes;
+    WCHAR			physmemName[] = L"\\device\\physicalmemory";
+
+    RtlInitUnicodeString(&physmemString, physmemName);
+
+    InitializeObjectAttributes(&attributes, &physmemString,
+        OBJ_CASE_INSENSITIVE, NULL, NULL);
+    status = NtOpenSection(&physmem, SECTION_MAP_READ, &attributes);
+
+    if (!NT_SUCCESS(status))
+    {
+        PrintError("Could not open \\device\\physicalmemory", status);
+        return NULL;
+    }
+
+    return physmem;
+}
+
+static PVOID MapPhysicalMemoryWithBase(HANDLE hPhyHandle, PVOID pBase, PDWORD pLen, PVOID *pVirtualBase)
+{
+    DWORD dwOffset = (ULONGLONG)pBase % dwPageSize;
+    DWORD dwLen = *pLen + dwOffset;
+
+    PVOID pVAddr = NULL;
+
+    if (MapPhysicalMemory(hPhyHandle, pBase, &dwLen, &pVAddr))
+    {
+        *pVirtualBase = pVAddr;
+        *pLen = dwLen;
+
+        return (PBYTE)pVAddr + dwOffset;
+    }
+    else
+    {
+        return NULL;
+    }
+}
+
+bool InitEntryPoints()
+{
+    Win32GetVersionEx = decltype(Win32GetVersionEx)(GetProcAddress(::GetModuleHandle(_T("kernel32.dll")), GetVersionExProc));
+    if (!Win32GetVersionEx)
+        return false;
+
+    Win32GetSystemInfo = decltype(Win32GetSystemInfo)(GetProcAddress(::GetModuleHandle(_T("kernel32.dll")), "GetSystemInfo"));
+    if (!Win32GetSystemInfo)
+        return false;
+
+    OSVERSIONINFO osvi;
+    ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
+    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+
+    if (!Win32GetVersionEx(&osvi))
+        return false;
+
+    bIsWindowsXPLater = ((osvi.dwMajorVersion > 5) || ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion > 1)));
+
+    SYSTEM_INFO sysinfo;
+    ::ZeroMemory(&sysinfo, sizeof (SYSTEM_INFO));
+    Win32GetSystemInfo(&sysinfo);
+
+    dwPageSize = sysinfo.dwPageSize;
+
+    if (bIsWindowsXPLater)
+    {
+        Win32GetSystemFirmwareTable = decltype(Win32GetSystemFirmwareTable)(GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "GetSystemFirmwareTable"));
+        if (!Win32GetSystemFirmwareTable)
+            return false;
+    }
+    else
+    {
+        Win32VirtualProtect = decltype(Win32VirtualProtect)(GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "VirtualProtect"));
+        if (!Win32VirtualProtect)
+            return false;
+
+        RtlInitUnicodeString = (decltype(RtlInitUnicodeString))(GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "RtlInitUnicodeString"));
+        if (!RtlInitUnicodeString)
+            return false;
+
+        NtUnmapViewOfSection = (decltype(NtUnmapViewOfSection))(GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtUnmapViewOfSection"));
+        if (!NtUnmapViewOfSection)
+            return false;
+
+        NtOpenSection = (decltype(NtOpenSection))(GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtOpenSection"));
+        if (!NtOpenSection)
+            return false;
+
+        NtMapViewOfSection = (decltype(NtMapViewOfSection))(GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtMapViewOfSection"));
+        if (!NtMapViewOfSection)
+            return false;
+
+        RtlNtStatusToDosError = (decltype(RtlNtStatusToDosError))(GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "RtlNtStatusToDosError"));
+        if (!NtMapViewOfSection)
+            return false;
+    }
+
+    return true;
+}
+
+void *LocateSMBIOS(uint32_t *smbios_size) {
+    void *buf = NULL;
+	const DWORD tableSignature = ('R' << 24) | ('S' << 16) | ('M' << 8) | 'B';
+
+    if (bIsWindowsXPLater)
+    {
+        uint32_t size = 0;
+		size = Win32GetSystemFirmwareTable(tableSignature, 0, buf, size);
+        if (0 == size)
+        {
+            return NULL;
+        }
+
+        buf = malloc(size);
+        if (buf)
+        {
+			if (0 == Win32GetSystemFirmwareTable(tableSignature, 0, buf, size))
+            {
+                free(buf);
+                buf = NULL;
+            }
+            else
+            {
+                *smbios_size = size;
+            }
+        }
+    }
+    else
+    {
+        HANDLE hPhysMem = OpenPhysicalMemory();
+        if (NULL == hPhysMem)
+            return NULL;
+
+        DWORD dwReadLen = 0x10000;
+        DWORD dwActualLen = dwReadLen;
+        PVOID pBaseVAddr = NULL;
+        PVOID pVAddr = MapPhysicalMemoryWithBase(hPhysMem, (PVOID)0xF0000, &dwActualLen, &pBaseVAddr);
+        if (!pVAddr)
+        {
+            ::CloseHandle(hPhysMem);
+            return NULL;
+        }
+
+        DWORD dwReadOffset = 0;
+
+        PBYTE pbVAddr = (PBYTE)pVAddr;
+        PBYTE pbGuardVAddr = pbVAddr + dwReadLen;
+
+        while (pbVAddr < pbGuardVAddr)
+        {
+            if (pbVAddr[0] == '_' && pbVAddr[1] == 'S' && pbVAddr[2] == 'M' && pbVAddr[3] == '_')
+            {
+                break;
+            }
+
+            pbVAddr += 16;
+        }
+
+        //!	no SMBIOS found
+        if (pbVAddr >= pbGuardVAddr)
+        {
+            UnmapPhysicalMemory(pVAddr);
+            ::CloseHandle(hPhysMem);
+
+            return NULL;
+        }
+
+        PSMBIOSEntryPoint pEntryPoint = (PSMBIOSEntryPoint)pbVAddr;
+
+        RawSMBIOSData *pData = (RawSMBIOSData *)::malloc(pEntryPoint->TableLength + sizeof(RawSMBIOSData));
+        PVOID pTableBaseVAddr = NULL;
+        if (NULL != pData)
+        {
+            DWORD dwTableLen = pEntryPoint->TableLength;
+            PVOID pTableVAddr = MapPhysicalMemoryWithBase(hPhysMem, (PVOID)pEntryPoint->TableAddress, &dwTableLen, &pTableBaseVAddr);
+            if (!pTableVAddr)
+            {
+                UnmapPhysicalMemory(pBaseVAddr);
+                ::CloseHandle(hPhysMem);
+                return NULL;
+            }
+
+            pData->Used20CallingMethod = 0;
+            pData->DmiRevision = 0;
+            pData->SMBIOSMajorVersion = pEntryPoint->MajorVersion;
+            pData->SMBIOSMinorVersion = pEntryPoint->MinorVersion;
+            pData->Length = pEntryPoint->TableLength;
+
+            ::memcpy(pData->SMBIOSTableData, (PVOID)pTableVAddr, pEntryPoint->TableLength);
+            *smbios_size = pEntryPoint->TableLength;
+        }
+
+        if (NULL != pTableBaseVAddr)
+            UnmapPhysicalMemory(pTableBaseVAddr);
+        if (NULL != pBaseVAddr)
+            UnmapPhysicalMemory(pBaseVAddr);
+
+        ::CloseHandle(hPhysMem);
+
+        buf = pData;
+    }
+
+    return buf;
+}
diff --git a/src/library/os/windows/isvm/Native.h b/src/library/os/windows/isvm/Native.h
new file mode 100644
index 0000000..d22a908
--- /dev/null
+++ b/src/library/os/windows/isvm/Native.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include <stdint.h>
+#include <windows.h>
+
+struct RawSMBIOSData
+{
+    BYTE    Used20CallingMethod;
+    BYTE    SMBIOSMajorVersion;
+    BYTE    SMBIOSMinorVersion;
+    BYTE    DmiRevision;
+    DWORD   Length;
+    BYTE    SMBIOSTableData[];
+};
+
+bool InitEntryPoints();
+void *LocateSMBIOS(uint32_t *smbios_size);
+
diff --git a/src/library/os/windows/isvm/main.cpp b/src/library/os/windows/isvm/main.cpp
new file mode 100644
index 0000000..105c105
--- /dev/null
+++ b/src/library/os/windows/isvm/main.cpp
@@ -0,0 +1,51 @@
+#include "intrin.h"
+
+#include <iostream>
+#include "BIOSReader.h"
+#include "Native.h"
+
+int _tmain(int argc, _TCHAR* argv[])
+{
+    int cpui[4] = { 0 };
+    __cpuid(cpui, 0x1);
+
+    if ((cpui[2] >> 31) & 1)
+    {
+        std::cout << "Inside virual machine!";
+        return 1;
+    }
+
+    if (InitEntryPoints())
+    {
+        BIOSReader reader;
+        SystemInformation info = reader.readSystemInfo();
+
+        const char *vmVendors[] =
+        {
+            "VMware", "Microsoft Corporation", "Virtual Machine", "innotek GmbH", "PowerVM", "Bochs", "KVM"
+        };
+
+        const int count = _countof(vmVendors);
+        for (int i = 0; i != count; ++i)
+        {
+            const char *vendor = vmVendors[i];
+
+            if (std::string::npos != info.Manufacturer.find(vendor) ||
+                std::string::npos != info.ProductName.find(vendor) ||
+                std::string::npos != info.SerialNum.find(vendor))
+            {
+                std::cout << "Inside virual machine!";
+                return 1;
+            }
+        }
+    }
+    else
+    {
+        return -1;
+    }
+
+    std::cout << "Inside host machine!";
+
+    return 0;
+}
+
diff --git a/src/library/os/windows/network.cpp b/src/library/os/windows/network.cpp
new file mode 100644
index 0000000..6334b9d
--- /dev/null
+++ b/src/library/os/windows/network.cpp
@@ -0,0 +1,113 @@
+/**
+ * @file network_id.c
+ * @date 16 Sep 2014
+ * @brief File containing network interface detection functions for Windows.
+ *
+ * The only public function of this module is #getAdapterInfos(OsAdapterInfo *,
+ *		size_t *), other functions are either static or inline.
+ *
+ * Responsibility of this module is to fill OsAdapterInfo structures, in a predictable way (skip loopback/vpn interfaces)
+ */
+
+#ifdef _MSC_VER
+#include <Windows.h>
+#endif
+#include <iphlpapi.h>
+#include <unordered_map>
+#include <stdio.h>
+//#pragma comment(lib, "IPHLPAPI.lib")
+
+#include "../../base/StringUtils.h"
+#include "../../base/logger.h"
+#include "../network.hpp"
+
+namespace license {
+namespace os {
+using namespace std;
+
+static int translate(char ipStringIn[16], unsigned char ipv4[4]) {
+	size_t index = 0;
+
+	char *str2 = ipStringIn; /* save the pointer */
+	while (*str2) {
+		if (isdigit((unsigned char)*str2)) {
+			ipv4[index] *= 10;
+			ipv4[index] += *str2 - '0';
+		} else {
+			index++;
+		}
+		str2++;
+	}
+	return 0;
+}
+/**
+ *
+ * @param adapterInfos
+ * @param adapter_info_size
+ * @return
+ */
+FUNCTION_RETURN getAdapterInfos(vector<OsAdapterInfo> &adapterInfos) {
+	unordered_map<string, OsAdapterInfo> adapterByName;
+	FUNCTION_RETURN f_return = FUNC_RET_OK;
+	DWORD dwStatus;
+	int adapter_info_size;
+	PIP_ADAPTER_INFO pAdapterInfo;
+	DWORD dwBufLen = sizeof(IP_ADAPTER_INFO);
+
+	unsigned int i = 3;
+	do {
+		pAdapterInfo = (PIP_ADAPTER_INFO)malloc(dwBufLen);
+		dwStatus = GetAdaptersInfo(	 // Call GetAdapterInfo
+			pAdapterInfo,  // [out] buffer to receive data
+			&dwBufLen  // [in] size of receive data buffer
+		);
+		if (dwStatus != NO_ERROR && pAdapterInfo != nullptr) {
+			free(pAdapterInfo);
+			pAdapterInfo = nullptr;
+		}
+	} while (dwStatus == ERROR_BUFFER_OVERFLOW && i-- > 0);
+
+	if (dwStatus == ERROR_BUFFER_OVERFLOW) {
+		return FUNC_RET_ERROR;
+	}
+
+	adapter_info_size = dwBufLen / sizeof(IP_ADAPTER_INFO);
+	if (adapter_info_size == 0) {
+		return FUNC_RET_NOT_AVAIL;
+	}
+
+	PIP_ADAPTER_INFO pAdapter = pAdapterInfo;
+	i = 0;
+	FUNCTION_RETURN result = FUNC_RET_OK;
+	while (pAdapter) {
+		OsAdapterInfo ai = {};
+		strncpy(ai.description, pAdapter->Description,
+				min((int)sizeof(ai.description), MAX_ADAPTER_DESCRIPTION_LENGTH));
+		memcpy(ai.mac_address, pAdapter->Address, 8);
+		translate(pAdapter->IpAddressList.IpAddress.String, ai.ipv4_address);
+		ai.type = IFACE_TYPE_ETHERNET;
+		i++;
+		pAdapter = pAdapter->Next;
+		if (i == adapter_info_size) {
+			result = FUNC_RET_BUFFER_TOO_SMALL;
+			break;
+		}
+		adapterByName[string(ai.description)] = ai;
+	}
+	free(pAdapterInfo);
+
+	// FIXME sort by eth , enps, wlan
+	if (adapterByName.size() == 0) {
+		f_return = FUNC_RET_NOT_AVAIL;
+	} else {
+		f_return = FUNC_RET_OK;
+		adapterInfos.reserve(adapterByName.size());
+		for (auto &it : adapterByName) {
+			adapterInfos.push_back(it.second);
+		}
+	}
+	return f_return;
+}
+
+}  // namespace os
+}  // namespace license
diff --git a/src/library/os/windows/os_win.cpp b/src/library/os/windows/os_win.cpp
new file mode 100644
index 0000000..b6094da
--- /dev/null
+++ b/src/library/os/windows/os_win.cpp
@@ -0,0 +1,104 @@
+#define NOMINMAX
+#include <windows.h>
+#include <algorithm>
+#include <licensecc/datatypes.h>
+#include <iphlpapi.h>
+#include <stdio.h>
+
+#include "../../base/logger.h"
+#include "../os.h"
+using namespace std;
+
+FUNCTION_RETURN getMachineName(unsigned char identifier[6]) {
+	FUNCTION_RETURN result = FUNC_RET_ERROR;
+	char buffer[MAX_COMPUTERNAME_LENGTH + 1];
+	int bufsize = MAX_COMPUTERNAME_LENGTH + 1;
+	const BOOL cmpName = GetComputerName(buffer, (unsigned long*)&bufsize);
+	if (cmpName) {
+		strncpy((char*)identifier, buffer, 6);
+		result = FUNC_RET_OK;
+	}
+	return result;
+}
+
+//http://www.ok-soft-gmbh.com/ForStackOverflow/EnumMassStorage.c
+//http://stackoverflow.com/questions/3098696/same-code-returns-diffrent-result-on-windows7-32-bit-system
+#define MAX_UNITS 30
+//bug check return with diskinfos == null func_ret_ok
+FUNCTION_RETURN getDiskInfos(DiskInfo * diskInfos, size_t * disk_info_size) {
+	DWORD fileMaxLen;
+	size_t ndrives = 0;
+	DWORD fileFlags;
+	char volName[MAX_PATH], fileSysName[MAX_PATH];
+	DWORD volSerial = 0;
+	const DWORD dwSize = MAX_PATH;
+	char szLogicalDrives[MAX_PATH] = { 0 };
+
+
+	FUNCTION_RETURN return_value = FUNC_RET_NOT_AVAIL;
+	const DWORD dwResult = GetLogicalDriveStrings(dwSize, szLogicalDrives);
+
+	if (dwResult > 0 && dwResult <= MAX_PATH) {
+		return_value = FUNC_RET_OK;
+		char* szSingleDrive = szLogicalDrives;
+		while (*szSingleDrive && ndrives < MAX_UNITS) {
+
+			// get the next drive
+			UINT driveType = GetDriveType(szSingleDrive);
+			if (driveType == DRIVE_FIXED) {
+				BOOL success = GetVolumeInformation(szSingleDrive, volName, MAX_PATH,
+				                                    &volSerial, &fileMaxLen, &fileFlags, fileSysName,
+				                                    MAX_PATH);
+				if (success) {
+					LOG_INFO("drive         : %s", szSingleDrive);
+					LOG_INFO("Volume Name   : %s", volName);
+					LOG_INFO("Volume Serial : 0x%x", volSerial);
+					LOG_DEBUG("Max file length : %d", fileMaxLen);
+					LOG_DEBUG("Filesystem      : %s", fileSysName);
+					if (diskInfos != NULL) {
+						if (ndrives < (int)*disk_info_size) {
+							diskInfos[ndrives].id = (int)ndrives;
+							strncpy(diskInfos[ndrives].device, volName,
+									min(std::size_t{MAX_PATH}, sizeof(volName)) - 1);
+							strncpy(diskInfos[ndrives].label, fileSysName,
+									min(sizeof(diskInfos[ndrives].label), sizeof(fileSysName)) - 1);
+							memcpy(diskInfos[ndrives].disk_sn, &volSerial, sizeof(DWORD));
+							diskInfos[ndrives].preferred = (szSingleDrive[0] == 'C');
+						} else {
+							return_value = FUNC_RET_BUFFER_TOO_SMALL;
+						}
+					}
+					ndrives++;
+				} else {
+					LOG_WARN("Unable to retrieve information of '%s'", szSingleDrive);
+				}
+			} else {
+				LOG_INFO("This volume is not fixed : %s, type: %d",	szSingleDrive);
+			}
+			szSingleDrive += strlen(szSingleDrive) + 1;
+		}
+	}
+	if (diskInfos == NULL || *disk_info_size == 0) {
+		if (ndrives > 0) {
+			return_value = FUNC_RET_OK;
+		} else {
+			return_value = FUNC_RET_NOT_AVAIL;
+			LOG_INFO("No fixed drive was detected");
+		}
+		*disk_info_size = ndrives;
+	} else {
+		*disk_info_size = min(ndrives, *disk_info_size);
+	}
+	return return_value;
+}
+
+
+FUNCTION_RETURN getModuleName(char buffer[MAX_PATH]) {
+	FUNCTION_RETURN result = FUNC_RET_OK;
+	const DWORD wres = GetModuleFileName(NULL, buffer, MAX_PATH);
+	if (wres == 0) {
+		result = FUNC_RET_ERROR;
+	}
+	return result;
+}
+
diff --git a/src/library/os/windows/signature_verifier.cpp b/src/library/os/windows/signature_verifier.cpp
index 3c8779c..0c9c60f 100644
--- a/src/library/os/windows/signature_verifier.cpp
+++ b/src/library/os/windows/signature_verifier.cpp
@@ -15,16 +15,17 @@
 #include <wincrypt.h>
 #include <iphlpapi.h>
 #include <windows.h>
-#pragma comment(lib, "bcrypt.lib")
+//#pragma comment(lib, "bcrypt.lib")
 
 #include <public_key.h>
 #include "../../base/logger.h"
 #include "../../base/base64.h"
-#include "../signature_verifier.h"
+#include "../signature_verifier.hpp"
 
 #define RSA_KEY_BITLEN 1024
 
 namespace license {
+namespace os {
 using namespace std;
 #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
 
@@ -135,12 +136,11 @@
 	DWORD status;
 	FUNCTION_RETURN result = FUNC_RET_ERROR;
 	PBYTE pbSignature = nullptr;
-	DWORD dwSigLen;
-	BYTE* sigBlob = nullptr;
 	BCRYPT_ALG_HANDLE hSignAlg = nullptr;
 
-	// FIXME!!
-	sigBlob = unbase64(signatureBuffer.c_str(), (int)signatureBuffer.size(), (int*)&dwSigLen);
+	vector<uint8_t> signatureBlob = unbase64(signatureBuffer);
+	DWORD dwSigLen = (DWORD) signatureBlob.size();
+	BYTE* sigBlob = &signatureBlob[0];
 
 	if (NT_SUCCESS(status = BCryptOpenAlgorithmProvider(&hSignAlg, BCRYPT_RSA_ALGORITHM, NULL, 0))) {
 		if ((result = readPublicKey(hSignAlg, &phKey)) == FUNC_RET_OK) {
@@ -159,7 +159,8 @@
 		} else {
 			LOG_DEBUG("Error reading public key");
 		}
-	} else {
+	}
+	else {
 		result = FUNC_RET_NOT_AVAIL;
 #ifdef _DEBUG
 		formatError(status, "error opening RSA provider");
@@ -172,9 +173,9 @@
 	if (hSignAlg != nullptr) {
 		BCryptCloseAlgorithmProvider(hSignAlg, 0);
 	}
-	if (sigBlob) {
-		free(sigBlob);
-	}
+	//if (sigBlob) {
+	//	free(sigBlob);
+	//}
 	return result;
 }
 
@@ -241,5 +242,5 @@
 	}
 	return result;
 }
-
+}  // namespace os
 } /* namespace license */
diff --git a/src/library/pc-identifiers.c b/src/library/pc-identifiers.c
deleted file mode 100644
index f1ec089..0000000
--- a/src/library/pc-identifiers.c
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- * pc-identifiers.c
- *
- *  Created on: Apr 16, 2014
- *
- */
-
-#include "os/os.h"
-#include "pc-identifiers.h"
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include "base/base64.h"
-#include "base/base.h"
-#ifdef __linux__
-#include <stdbool.h>
-#include <valgrind/memcheck.h>
-#else
-#ifdef __MINGW32__
-#include <windows.h>
-#else
-#include <Windows.h>
-#endif
-#endif
-
-static FUNCTION_RETURN generate_disk_pc_id(PcIdentifier *identifiers, unsigned int *num_identifiers, bool use_label);
-
-static FUNCTION_RETURN generate_ethernet_pc_id(PcIdentifier *identifiers, unsigned int *num_identifiers, int use_mac);
-
-static FUNCTION_RETURN generate_default_pc_id(PcIdentifier *identifiers, unsigned int *num_identifiers) {
-	size_t adapter_num, disk_num;
-	FUNCTION_RETURN result_adapterInfos, result_diskinfos, function_return;
-	unsigned int caller_identifiers, i, j, k, array_index;
-	DiskInfo *diskInfoPtr;
-	OsAdapterInfo *adapterInfoPtr;
-
-	if (identifiers == NULL || *num_identifiers == 0) {
-		result_adapterInfos = getAdapterInfos(NULL, &adapter_num);
-		if ((result_adapterInfos != FUNC_RET_OK) || (adapter_num == 0)) {
-			return generate_disk_pc_id(identifiers, num_identifiers, false);
-		}
-		result_diskinfos = getDiskInfos(NULL, &disk_num);
-		if ((result_diskinfos != FUNC_RET_OK) || (disk_num == 0)) {
-			return generate_ethernet_pc_id(identifiers, num_identifiers, true);
-		}
-		*num_identifiers = disk_num * adapter_num;
-		function_return = FUNC_RET_OK;
-	} else {
-		adapterInfoPtr = (OsAdapterInfo *)malloc((*num_identifiers) * sizeof(OsAdapterInfo));
-		adapter_num = *num_identifiers;
-		result_adapterInfos = getAdapterInfos(adapterInfoPtr, &adapter_num);
-		if (result_adapterInfos != FUNC_RET_OK && result_adapterInfos != FUNC_RET_BUFFER_TOO_SMALL) {
-			free(adapterInfoPtr);
-			return generate_disk_pc_id(identifiers, num_identifiers, false);
-		}
-		diskInfoPtr = (DiskInfo *)malloc((*num_identifiers) * sizeof(DiskInfo));
-		disk_num = *num_identifiers;
-		result_diskinfos = getDiskInfos(diskInfoPtr, &disk_num);
-		if (result_diskinfos != FUNC_RET_OK && result_diskinfos != FUNC_RET_BUFFER_TOO_SMALL) {
-			free(diskInfoPtr);
-			free(adapterInfoPtr);
-			return generate_ethernet_pc_id(identifiers, num_identifiers, true);
-		}
-		function_return = FUNC_RET_OK;
-
-		caller_identifiers = *num_identifiers;
-		for (i = 0; i < disk_num; i++) {
-			for (j = 0; j < adapter_num; j++) {
-				array_index = i * adapter_num + j;
-				if (array_index >= caller_identifiers) {
-					function_return = FUNC_RET_BUFFER_TOO_SMALL;
-					// sweet memories...
-					goto end;
-				}
-				for (k = 0; k < 6; k++)
-					identifiers[array_index][k] = diskInfoPtr[i].disk_sn[k + 2] ^ adapterInfoPtr[j].mac_address[k + 2];
-			}
-		}
-	end:
-#ifdef _MSC_VER
-		*num_identifiers = min(*num_identifiers, adapter_num * disk_num);
-#else
-		*num_identifiers = cmin(*num_identifiers, adapter_num * disk_num);
-#endif
-		free(diskInfoPtr);
-		free(adapterInfoPtr);
-	}
-	return function_return;
-}
-
-static FUNCTION_RETURN generate_ethernet_pc_id(PcIdentifier *identifiers, unsigned int *num_identifiers, int use_mac) {
-	FUNCTION_RETURN result_adapterInfos;
-	OsAdapterInfo *adapterInfos;
-	size_t defined_adapters, adapters = 0;
-
-	if (identifiers == NULL || *num_identifiers == 0) {
-		result_adapterInfos = getAdapterInfos(NULL, &adapters);
-		if (result_adapterInfos == FUNC_RET_OK || result_adapterInfos == FUNC_RET_BUFFER_TOO_SMALL) {
-			*num_identifiers = adapters;
-			result_adapterInfos = FUNC_RET_OK;
-		}
-	} else {
-		defined_adapters = adapters = *num_identifiers;
-		adapterInfos = (OsAdapterInfo *)malloc(adapters * sizeof(OsAdapterInfo));
-		result_adapterInfos = getAdapterInfos(adapterInfos, &adapters);
-		if (result_adapterInfos == FUNC_RET_BUFFER_TOO_SMALL || result_adapterInfos == FUNC_RET_OK) {
-			unsigned int j;
-			for (j = 0; j < adapters; j++) {
-				unsigned int k;
-				for (k = 0; k < 6; k++)
-					if (use_mac) {
-						identifiers[j][k] = adapterInfos[j].mac_address[k + 2];
-					} else {
-						// use ip
-						if (k < 4) {
-							identifiers[j][k] = adapterInfos[j].ipv4_address[k];
-						} else {
-							// padding
-							identifiers[j][k] = 42;
-						}
-					}
-			}
-			result_adapterInfos = (adapters > defined_adapters ? FUNC_RET_BUFFER_TOO_SMALL : FUNC_RET_OK);
-		}
-		free(adapterInfos);
-	}
-	return result_adapterInfos;
-}
-
-static FUNCTION_RETURN generate_disk_pc_id(PcIdentifier *identifiers, unsigned int *num_identifiers, bool use_label) {
-	size_t disk_num, available_disk_info = 0;
-	FUNCTION_RETURN result_diskinfos;
-	unsigned int i, j;
-	int defined_identifiers;
-	DiskInfo *diskInfos;
-
-	result_diskinfos = getDiskInfos(NULL, &disk_num);
-	if (result_diskinfos != FUNC_RET_OK) {
-		return result_diskinfos;
-	}
-	diskInfos = (DiskInfo *)malloc(disk_num * sizeof(DiskInfo));
-	memset(diskInfos, 0, disk_num * sizeof(DiskInfo));
-	result_diskinfos = getDiskInfos(diskInfos, &disk_num);
-	if (result_diskinfos != FUNC_RET_OK) {
-		free(diskInfos);
-		return result_diskinfos;
-	}
-	for (i = 0; i < disk_num; i++) {
-		char firstChar = use_label ? diskInfos[i].label[0] : diskInfos[i].disk_sn[0];
-		available_disk_info += firstChar == 0 ? 0 : 1;
-	}
-
-	defined_identifiers = *num_identifiers;
-	*num_identifiers = available_disk_info;
-	if (identifiers == NULL) {
-		free(diskInfos);
-		return FUNC_RET_OK;
-	} else if (available_disk_info > defined_identifiers) {
-		free(diskInfos);
-		return FUNC_RET_BUFFER_TOO_SMALL;
-	}
-
-	j = 0;
-	for (i = 0; i < disk_num; i++) {
-		if (use_label) {
-			if (diskInfos[i].label[0] != 0) {
-				memset(identifiers[j], 0, sizeof(PcIdentifier));  //!!!!!!!
-				strncpy((char *)identifiers[j], diskInfos[i].label, sizeof(PcIdentifier));
-				j++;
-			}
-		} else {
-			if (diskInfos[i].disk_sn[0] != 0) {
-				memcpy(identifiers[j], &diskInfos[i].disk_sn[2], sizeof(PcIdentifier));
-				j++;
-			}
-		}
-	}
-	free(diskInfos);
-	return FUNC_RET_OK;
-}
-
-/**
- *
- * Calculates all the possible identifiers for the current machine, for the
- * given calculation strategy requested. Pc identifiers are more than one,
- * for instance a machine with more than one disk and one network interface has
- * usually multiple identifiers.
- *
- * First 4 bit of each pc identifier are reserved 3 for the type of strategy
- * used in calculation and 1 for parity checks (not implemented here)
- *
- * @param identifiers
- * @param array_size
- * @param
- * @return
- */
-
-FUNCTION_RETURN generate_pc_id(PcIdentifier *identifiers, unsigned int *array_size, IDENTIFICATION_STRATEGY strategy) {
-	FUNCTION_RETURN result;
-	unsigned int i, j;
-	const unsigned int original_array_size = *array_size;
-	unsigned char strategy_num;
-	switch (strategy) {
-		case STRATEGY_DEFAULT:
-			result = generate_default_pc_id(identifiers, array_size);
-			break;
-		case STRATEGY_ETHERNET:
-			result = generate_ethernet_pc_id(identifiers, array_size, true);
-			break;
-		case STRATEGY_IP_ADDRESS:
-			result = generate_ethernet_pc_id(identifiers, array_size, false);
-			break;
-		case STRATEGY_DISK_NUM:
-			result = generate_disk_pc_id(identifiers, array_size, false);
-			break;
-		case STRATEGY_DISK_LABEL:
-			result = generate_disk_pc_id(identifiers, array_size, true);
-			break;
-		default:
-			return FUNC_RET_ERROR;
-	}
-
-	if (result == FUNC_RET_OK && identifiers != NULL) {
-		strategy_num = strategy << 5;
-		for (i = 0; i < *array_size; i++) {
-			// encode strategy in the first three bits of the pc_identifier
-			identifiers[i][0] = (identifiers[i][0] & 15) | strategy_num;
-		}
-		// fill array if larger
-		for (i = *array_size; i < original_array_size; i++) {
-			identifiers[i][0] = STRATEGY_UNKNOWN << 5;
-			for (j = 1; j < sizeof(PcIdentifier); j++) {
-				identifiers[i][j] = 42;  // padding
-			}
-		}
-	}
-	return result;
-}
-
-char *MakeCRC(char *BitString) {
-	static char Res[3];  // CRC Result
-	char CRC[2];
-	int i;
-
-	for (i = 0; i < 2; ++i) CRC[i] = 0;  // Init before calculation
-
-	for (i = 0; i < strlen(BitString); ++i) {
-		char doInvert = ('1' == BitString[i]) ^ CRC[1];  // XOR required?
-
-		CRC[1] = CRC[0];
-		CRC[0] = doInvert;
-	}
-
-	for (i = 0; i < 2; ++i) Res[1 - i] = CRC[i] ? '1' : '0';  // Convert binary to ASCII
-	Res[2] = 0;  // Set string terminator
-
-	return (Res);
-}
-
-FUNCTION_RETURN encode_pc_id(PcIdentifier identifier1, PcIdentifier identifier2, PcSignature pc_identifier_out) {
-	// TODO base62 encoding, now uses base64
-	PcIdentifier concat_identifiers[2];
-	char *b64_data = NULL;
-	int b64_size = 0;
-	const size_t concatIdentifiersSize = sizeof(PcIdentifier) * 2;
-	// concat_identifiers = (PcIdentifier *) malloc(concatIdentifiersSize);
-	memcpy(&concat_identifiers[0], identifier1, sizeof(PcIdentifier));
-	memcpy(&concat_identifiers[1], identifier2, sizeof(PcIdentifier));
-	b64_data = base64(concat_identifiers, concatIdentifiersSize, &b64_size);
-	if (b64_size > sizeof(PcSignature)) {
-		free(b64_data);
-		return FUNC_RET_BUFFER_TOO_SMALL;
-	}
-	sprintf(pc_identifier_out, "%.4s-%.4s-%.4s-%.4s", &b64_data[0], &b64_data[4], &b64_data[8], &b64_data[12]);
-	// free(concat_identifiers);
-	free(b64_data);
-	return FUNC_RET_OK;
-}
-
-FUNCTION_RETURN parity_check_id(PcSignature pc_identifier) { return FUNC_RET_OK; }
-
-FUNCTION_RETURN generate_user_pc_signature(PcSignature identifier_out, IDENTIFICATION_STRATEGY strategy) {
-	FUNCTION_RETURN result;
-	PcIdentifier *identifiers;
-	unsigned int req_buffer_size = 0;
-	result = generate_pc_id(NULL, &req_buffer_size, strategy);
-	if (result != FUNC_RET_OK) {
-		return result;
-	}
-	if (req_buffer_size == 0) {
-		return FUNC_RET_ERROR;
-	}
-	req_buffer_size = req_buffer_size < 2 ? 2 : req_buffer_size;
-	identifiers = (PcIdentifier *)malloc(sizeof(PcIdentifier) * req_buffer_size);
-	memset(identifiers, 0, sizeof(PcIdentifier) * req_buffer_size);
-	result = generate_pc_id(identifiers, &req_buffer_size, strategy);
-	if (result != FUNC_RET_OK) {
-		free(identifiers);
-		return result;
-	}
-#ifdef __linux__
-	VALGRIND_CHECK_VALUE_IS_DEFINED(identifiers[0]);
-	VALGRIND_CHECK_VALUE_IS_DEFINED(identifiers[1]);
-#endif
-	result = encode_pc_id(identifiers[0], identifiers[1], identifier_out);
-#ifdef __linux__
-	VALGRIND_CHECK_VALUE_IS_DEFINED(identifier_out);
-#endif
-	free(identifiers);
-	return result;
-}
-
-/**
- * Extract the two pc identifiers from the user provided code.
- * @param identifier1_out
- * @param identifier2_out
- * @param str_code: the code in the string format XXXX-XXXX-XXXX-XXXX
- * @return
- */
-static FUNCTION_RETURN decode_pc_id(PcIdentifier identifier1_out, PcIdentifier identifier2_out,
-									PcSignature pc_signature_in) {
-	// TODO base62 encoding, now uses base64
-
-	unsigned char *concat_identifiers = NULL;
-	char base64ids[17];
-	int identifiers_size;
-
-	sscanf(pc_signature_in, "%4s-%4s-%4s-%4s", &base64ids[0], &base64ids[4], &base64ids[8], &base64ids[12]);
-	concat_identifiers = unbase64(base64ids, 16, &identifiers_size);
-	if (identifiers_size > sizeof(PcIdentifier) * 2) {
-		free(concat_identifiers);
-		return FUNC_RET_BUFFER_TOO_SMALL;
-	}
-	memcpy(identifier1_out, concat_identifiers, sizeof(PcIdentifier));
-	memcpy(identifier2_out, concat_identifiers + sizeof(PcIdentifier), sizeof(PcIdentifier));
-	free(concat_identifiers);
-	return FUNC_RET_OK;
-}
-
-static IDENTIFICATION_STRATEGY strategy_from_pc_id(PcIdentifier identifier) {
-	return (IDENTIFICATION_STRATEGY)identifier[0] >> 5;
-}
-
-EVENT_TYPE validate_pc_signature(PcSignature str_code) {
-	PcIdentifier user_identifiers[2];
-	FUNCTION_RETURN result;
-	IDENTIFICATION_STRATEGY previous_strategy_id, current_strategy_id;
-	PcIdentifier *calculated_identifiers = NULL;
-	unsigned int calc_identifiers_size = 0;
-	int i = 0, j = 0;
-	// bool found;
-#ifdef _DEBUG
-	printf("Comparing pc identifiers: \n");
-#endif
-	result = decode_pc_id(user_identifiers[0], user_identifiers[1], str_code);
-	if (result != FUNC_RET_OK) {
-		return result;
-	}
-	previous_strategy_id = STRATEGY_UNKNOWN;
-	// found = false;
-	for (i = 0; i < 2; i++) {
-		current_strategy_id = strategy_from_pc_id(user_identifiers[i]);
-		if (current_strategy_id == STRATEGY_UNKNOWN && previous_strategy_id == STRATEGY_UNKNOWN && i == 1) {
-			free(calculated_identifiers);
-			printf("Comparing pc identifiers: %d %d %d %s\n", current_strategy_id, previous_strategy_id, i, str_code);
-			return LICENSE_MALFORMED;
-		} else if (current_strategy_id == STRATEGY_UNKNOWN) {
-			continue;
-		}
-		if (current_strategy_id != previous_strategy_id) {
-			if (calculated_identifiers != NULL) {
-				free(calculated_identifiers);
-			}
-			previous_strategy_id = current_strategy_id;
-			generate_pc_id(NULL, &calc_identifiers_size, current_strategy_id);
-			calculated_identifiers = (PcIdentifier *)malloc(sizeof(PcIdentifier) * calc_identifiers_size);
-			memset(calculated_identifiers, 0, sizeof(PcIdentifier) * calc_identifiers_size);
-			generate_pc_id(calculated_identifiers, &calc_identifiers_size, current_strategy_id);
-		}
-		// maybe skip the byte 0
-		for (j = 0; j < calc_identifiers_size; j++) {
-#ifdef _DEBUG
-			printf(
-				"generated id: %02x%02x%02x%02x%02x%02x index %d, user_supplied id %02x%02x%02x%02x%02x%02x idx: %d\n",
-				calculated_identifiers[j][0], calculated_identifiers[j][1], calculated_identifiers[j][2],
-				calculated_identifiers[j][3], calculated_identifiers[j][4], calculated_identifiers[j][5], j,
-				user_identifiers[i][0], user_identifiers[i][1], user_identifiers[i][2], user_identifiers[i][3],
-				user_identifiers[i][4], user_identifiers[i][5], i);
-
-#endif
-			if (!memcmp(user_identifiers[i], calculated_identifiers[j], sizeof(PcIdentifier))) {
-				free(calculated_identifiers);
-				return LICENSE_OK;
-			}
-		}
-	}
-	free(calculated_identifiers);
-	return IDENTIFIERS_MISMATCH;
-}
diff --git a/src/library/pc-identifiers.h b/src/library/pc-identifiers.h
deleted file mode 100644
index 2eb0d56..0000000
--- a/src/library/pc-identifiers.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * pc-identifiers.h
- *
- *  Created on: Apr 16, 2014
- *
- */
-
-#ifndef PC_IDENTIFIERS_H_
-#define PC_IDENTIFIERS_H_
-
-#include <licensecc/datatypes.h>
-#include "base/base.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef unsigned char PcIdentifier[6];
-typedef char PcSignature[PC_IDENTIFIER_SIZE + 1];
-
-FUNCTION_RETURN generate_pc_id(PcIdentifier * identifiers, unsigned int * array_size,
-		IDENTIFICATION_STRATEGY strategy);
-
-EVENT_TYPE validate_pc_signature(PcSignature str_code);
-
-/**
- * Generates an UserPcIdentifier.
- *
- * @param identifier_out
- * @param strategy
- * @return
- */
-FUNCTION_RETURN generate_user_pc_signature(PcSignature identifier_out, IDENTIFICATION_STRATEGY strategy);
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* PC_IDENTIFIERS_H_ */
diff --git a/src/templates/licensecc_properties.h.in b/src/templates/licensecc_properties.h.in
index c1af888..b8026f9 100644
--- a/src/templates/licensecc_properties.h.in
+++ b/src/templates/licensecc_properties.h.in
@@ -1,17 +1,74 @@
 #ifndef BUILD_PROPERTIES_H_
 #define BUILD_PROPERTIES_H_
 
+/**
+ * This file contains all the properties that are customizable on on a per-project basis eg:
+ * 1) api parameter sizes
+ * 2) 
+ *
+ * It is safe to place the values that your project need to customize here, since each project get its own copy of this
+ * file.
+ */
+
 #define LCC_PROJECT_NAME "@LCC_PROJECT_NAME@"
 
 //License retrieval configuration
 #define FIND_LICENSE_NEAR_MODULE true
 #define FIND_LICENSE_WITH_ENV_VAR false
 
-#define LICENSE_FILE_EXTENSION ".lic"
-#define LICENSE_LOCATION_ENV_VAR "LICENSE_LOCATION"
-#define LICENSE_DATA_ENV_VAR "LICENSE_DATA"
+/**
+ * License file name extension
+ */
+#define LCC_LICENSE_FILE_EXTENSION ".lic"
+#define LCC_LICENSE_LOCATION_ENV_VAR "LICENSE_LOCATION"
+#define LCC_LICENSE_DATA_ENV_VAR "LICENSE_DATA"
+/**
+ * Environment variable that if defined will change the identification strategy used to generate the hardware identifier.
+ * If a client has an unstable pc-identifier use this variable to generate one. 
+ * Valid values are integers defined in `LCC_IDENTIFICATION_STRATEGY` enum.
+ */
+#define LCC_IDENTIFICATION_STRATEGY_ENV_VAR "IDENTIFICATION_STRATEGY"
 
-//Internal data structures limits
-#define MAX_LICENSE_LENGTH 256*1024
+/**
+ * Enum to select a specific pc identification_strategy. DEFAULT Should be used in most cases.
+ */
+typedef enum {
+	STRATEGY_DEFAULT = -1,
+	STRATEGY_ETHERNET = 0,
+	STRATEGY_IP_ADDRESS = 1,
+	STRATEGY_DISK_NUM = 2,
+	STRATEGY_DISK_LABEL = 3,
+	STRATEGY_MEMORY_CPU_SIZE = 4,
+	STRATEGY_HOST_NAME = 5,
+	STRATEGY_NONE = -2
+} LCC_API_IDENTIFICATION_STRATEGY;
+
+//strategies used for each virtual environment.
+#define LCC_BARE_TO_METAL_STRATEGIES { STRATEGY_ETHERNET, STRATEGY_DISK_LABEL, STRATEGY_NONE }
+#define LCC_VM_STRATEGIES { STRATEGY_ETHERNET, STRATEGY_NONE }
+#define LCC_LXC_STRATEGIES { STRATEGY_ETHERNET, STRATEGY_NONE }
+#define LCC_DOCKER_STRATEGIES { STRATEGY_NONE }
+#define LCC_CLOUD_STRATEGIES { STRATEGY_NONE }
+
+//Api structure limits
+/**
+ * Maximum size of a license file or base64 data
+ */
+#define LCC_API_MAX_LICENSE_DATA_LENGTH 1024 * 4
+
+// define api structure sizes
+#define LCC_API_PC_IDENTIFIER_SIZE 19
+#define LCC_API_PROPRIETARY_DATA_SIZE 16
+#define LCC_API_AUDIT_EVENT_NUM 5
+#define LCC_API_AUDIT_EVENT_PARAM2 255
+#define LCC_API_VERSION_LENGTH 15
+#define LCC_API_PROJECT_NAME_SIZE 15
+#define LCC_API_EXPIRY_DATE_SIZE 10
+#define LCC_API_ERROR_BUFFER_SIZE 256
+
+/**
+This definition allows to specify a custom expression to verify the magic number passed in by the api.
+*/
+#define LCC_VERIFY_MAGIC (lic_info.m_magic == @LCC_PROJECT_MAGIC_NUM@)
 
 #endif
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index ec61aef..924c9f0 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,8 +1,5 @@
 #if we're here boost has been found
 add_definitions(-DBOOST_ALL_NO_LIB) #Disable Boost Microsoft magic, all dependencies are handled by cmake
-add_definitions(-DBOOST_LIB_DIAGNOSTIC) #Check it is really disabled
-include_directories(${Boost_INCLUDE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
-link_directories ( ${Boost_LIBRARY_DIR} )
 
 configure_file (
 	"${CMAKE_CURRENT_SOURCE_DIR}/../src/templates/licensecc_properties_test.h.in" 
@@ -11,7 +8,6 @@
 file(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/include/$<CONFIG>/licensecc_properties_test.h" 
 		INPUT "${CMAKE_BINARY_DIR}/licensecc_properties_test.h.tmp")
 include_directories ( ${CMAKE_BINARY_DIR}/include/$<CONFIG> )
-
 
 add_subdirectory(library)
 add_subdirectory(functional)
\ No newline at end of file
diff --git a/test/IdentificationStrategy_test.cpp b/test/IdentificationStrategy_test.cpp
new file mode 100644
index 0000000..f81a169
--- /dev/null
+++ b/test/IdentificationStrategy_test.cpp
@@ -0,0 +1,10 @@
+/*
+ * IdentificationStrategy_test.cpp
+ *
+ *  Created on: Jan 1, 2020
+ *      Author: devel
+ */
+
+#include "identification_strategy.hpp"
+
+namespace license {} /* namespace license */
diff --git a/test/default_strategy_test.cpp b/test/default_strategy_test.cpp
new file mode 100644
index 0000000..8cba3cf
--- /dev/null
+++ b/test/default_strategy_test.cpp
@@ -0,0 +1,10 @@
+/*
+ * default_strategy_test.cpp
+ *
+ *  Created on: Jan 2, 2020
+ *      Author: devel
+ */
+
+#include "default_strategy.hpp"
+
+namespace license {} /* namespace license */
diff --git a/test/functional/CMakeLists.txt b/test/functional/CMakeLists.txt
index 60c676e..6d2397b 100644
--- a/test/functional/CMakeLists.txt
+++ b/test/functional/CMakeLists.txt
@@ -2,20 +2,17 @@
  	generate-license.cpp
 )
 
-target_link_libraries(
-	license_generator_snippet
+target_link_libraries( license_generator_snippet
  	 Boost::unit_test_framework 
      Boost::filesystem
      Boost::system
 )
 
-add_executable(
- test_standard_license
+add_executable( test_standard_license
  standard-license_test.cpp
 )
 
-target_link_libraries(
- test_standard_license
+target_link_libraries( test_standard_license
  licensecc_static
  license_generator_snippet
  Boost::unit_test_framework 
@@ -23,13 +20,11 @@
  Boost::system
 )
 
-add_executable(
- test_date
+add_executable( test_date
  date_test.cpp
 )
 
-target_link_libraries(
- test_date
+target_link_libraries( test_date
  licensecc_static
  license_generator_snippet
  Boost::unit_test_framework 
@@ -37,8 +32,7 @@
  Boost::system
 )
 
-add_executable(
- test_signature_verifier
+add_executable( test_signature_verifier
  signature_verifier_test.cpp
 )
 
@@ -52,24 +46,30 @@
 )
 
 
-add_executable(
- test_volid
- volid_test.cpp
-)
+add_executable(test_it_hw_identifier hw_identifier_it_test.cpp)
 
-target_link_libraries(
- test_volid
- licensecc_static
+target_link_libraries(test_it_hw_identifier
  license_generator_snippet
+ licensecc_static
  Boost::unit_test_framework 
  Boost::filesystem
  Boost::system
 )
 
+add_executable(test_crack crack_test.cpp)
 
+target_link_libraries( test_crack
+ license_generator_snippet
+ licensecc_static
+ Boost::unit_test_framework 
+ Boost::filesystem
+ Boost::system
+)
+
+ADD_TEST(NAME test_crack COMMAND test_crack WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
 ADD_TEST(NAME test_date COMMAND test_date WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
+ADD_TEST(NAME test_it_hw_identifier COMMAND test_it_hw_identifier WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
 ADD_TEST(NAME test_standard_license COMMAND test_standard_license WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
 ADD_TEST(NAME test_signature_verifier COMMAND test_signature_verifier WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
-ADD_TEST(NAME test_volid COMMAND test_volid WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
 
 
diff --git a/test/functional/crack_test.cpp b/test/functional/crack_test.cpp
new file mode 100644
index 0000000..b427928
--- /dev/null
+++ b/test/functional/crack_test.cpp
@@ -0,0 +1,39 @@
+
+#define BOOST_TEST_MODULE standard_license_test
+
+#include <boost/test/unit_test.hpp>
+#include <boost/filesystem.hpp>
+
+#include <licensecc/licensecc.h>
+#include <licensecc_properties_test.h>
+#include <licensecc_properties.h>
+#include <iostream>
+#include "../../src/library/ini/SimpleIni.h"
+#include "generate-license.h"
+#include "../../src/library/base/file_utils.hpp"
+
+namespace license {
+namespace test {
+namespace fs = boost::filesystem;
+using namespace license;
+using namespace std;
+
+/**
+ * Test a generic license, passing a bad license number trough the api.
+ * see projects/DEFAULT/include/licensecc/DEFAULT/licensecc_properties.h (magic should be 0)
+ */
+BOOST_AUTO_TEST_CASE(test_bad_magic_number) {
+	const vector<string> extraArgs;
+	const string licLocation = generate_license("standard_license", extraArgs);
+	/* */
+	LicenseInfo license;
+	LicenseLocation location = {LICENSE_PATH};
+	std::copy(licLocation.begin(), licLocation.end(), location.licenseData);
+	// magic should be 0 for this build...
+	CallerInformations callInfo{{0}, {0}, 42};
+	const LCC_EVENT_TYPE result = acquire_license(&callInfo, &location, &license);
+	BOOST_CHECK_EQUAL(result, LICENSE_CORRUPTED);
+}
+
+}  // namespace test
+}  // namespace license
diff --git a/test/functional/date_test.cpp b/test/functional/date_test.cpp
index 15fbdd0..9638f1b 100644
--- a/test/functional/date_test.cpp
+++ b/test/functional/date_test.cpp
@@ -24,14 +24,14 @@
 	const string licLocation = generate_license("not_expired.lic", extraArgs);
 	/* */
 	LicenseInfo license;
-	LicenseLocation licenseLocation;
-	licenseLocation.licenseFileLocation = licLocation.c_str();
-	licenseLocation.licenseData = "";
-	const EVENT_TYPE result = acquire_license(nullptr, &licenseLocation, &license);
+	LicenseLocation location = {LICENSE_PATH};
+	std::copy(licLocation.begin(), licLocation.end(), location.licenseData);
+
+	const LCC_EVENT_TYPE result = acquire_license(nullptr, &location, &license);
 	BOOST_CHECK_EQUAL(result, LICENSE_OK);
 	BOOST_CHECK_EQUAL(license.has_expiry, true);
 	BOOST_CHECK_EQUAL(license.linked_to_pc, false);
-	BOOST_CHECK_GT(license.days_left, 0);
+	BOOST_CHECK_GT(license.days_left, (unsigned int)0);
 }
 
 BOOST_AUTO_TEST_CASE(license_expired) {
@@ -41,11 +41,10 @@
 	const string licLocation = generate_license("expired", extraArgs);
 	/* */
 	LicenseInfo license;
-	LicenseLocation licenseLocation;
-	licenseLocation.licenseFileLocation = licLocation.c_str();
-	licenseLocation.licenseData = nullptr;
+	LicenseLocation location = {LICENSE_PATH};
+	std::copy(licLocation.begin(), licLocation.end(), location.licenseData);
 	BOOST_TEST_MESSAGE("before acquire license");
-	const EVENT_TYPE result = acquire_license(nullptr, &licenseLocation, &license);
+	const LCC_EVENT_TYPE result = acquire_license(nullptr, &location, &license);
 	BOOST_CHECK_EQUAL(result, PRODUCT_EXPIRED);
 	BOOST_CHECK_EQUAL(license.has_expiry, true);
 	BOOST_CHECK_EQUAL(license.linked_to_pc, false);
diff --git a/test/functional/generate-license.cpp b/test/functional/generate-license.cpp
index 8ef9477..98cd979 100644
--- a/test/functional/generate-license.cpp
+++ b/test/functional/generate-license.cpp
@@ -20,8 +20,10 @@
 
 namespace fs = boost::filesystem;
 using namespace std;
+
 namespace license {
 namespace test {
+
 string generate_license(const string& license_name, const vector<string>& other_args) {
 	fs::path lcc_exe(LCC_EXE);
 	BOOST_REQUIRE_MESSAGE(fs::is_regular_file(lcc_exe), "License generator not found: " LCC_EXE);
diff --git a/test/functional/hijiaking_test.cpp b/test/functional/hijiaking_test.cpp
deleted file mode 100644
index d18b84d..0000000
--- a/test/functional/hijiaking_test.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-#define BOOST_TEST_MODULE standard_license_test
-
-#include <build_properties.h>
-#include <boost/filesystem.hpp>
-#include <boost/test/unit_test.hpp>
-
-#include "../../src/tools/license-generator/license-generator.h"
-#include <licensecc/licensecc.h>
-#include "../../src/library/ini/SimpleIni.h"
-#include "generate-license.h"
-
-namespace fs = boost::filesystem;
-using namespace license;
-using namespace std;
-
-
-BOOST_AUTO_TEST_CASE( standard_lic_file ) {
-	const string licLocation(PROJECT_TEST_TEMP_DIR "/standard_license.lic");
-	vector<string> extraArgs;
-	generate_license(licLocation, extraArgs);
-	/* */
-	LicenseInfo license;
-	LicenseLocation licenseLocation;
-	licenseLocation.openFileNearModule=false;
-	licenseLocation.licenseFileLocation = licLocation.c_str();
-	licenseLocation.licenseData = "";
-	EVENT_TYPE result = acquire_license("TEST",
-			licenseLocation, & license);
-	BOOST_CHECK_EQUAL(result, LICENSE_OK);
-	BOOST_CHECK_EQUAL(license.has_expiry, false);
-	BOOST_CHECK_EQUAL(license.linked_to_pc, false);
-}
-
diff --git a/test/functional/hw_identifier_it_test.cpp b/test/functional/hw_identifier_it_test.cpp
new file mode 100644
index 0000000..e1ae99a
--- /dev/null
+++ b/test/functional/hw_identifier_it_test.cpp
@@ -0,0 +1,95 @@
+#define BOOST_TEST_MODULE integration_test_hw_identifier
+
+#include <boost/test/unit_test.hpp>
+#include <fstream>
+#include <iostream>
+#include <stdio.h>
+#include <cstring>
+#include <boost/filesystem.hpp>
+#include <licensecc_properties.h>
+#include <licensecc_properties_test.h>
+
+#include <licensecc/licensecc.h>
+#include "../../src/library/ini/SimpleIni.h"
+#include "../../src/library/hw_identifier/hw_identifier_facade.hpp"
+#include "../../src/library/os/os.h"
+#include "../../src/library/os/network.hpp"
+#include "generate-license.h"
+
+
+namespace license {
+namespace test {
+namespace fs = boost::filesystem;
+using namespace std;
+using namespace hw_identifier;
+
+/**
+ * If the current pc has at least one disk generate a hardware identifier using disk, generate a license, verify the license
+ * is OK
+ */
+
+static void generate_and_verify_license(LCC_API_IDENTIFICATION_STRATEGY strategy, const string& lic_fname) {
+	BOOST_TEST_CHECKPOINT("Before generate");
+	const string identifier_out = HwIdentifierFacade::generate_user_pc_signature(strategy);
+	BOOST_TEST_CHECKPOINT("After generate signature");
+	cout << "Identifier:" << identifier_out << endl;
+	vector<string> extraArgs;
+	extraArgs.push_back("-s");
+	extraArgs.push_back(identifier_out);
+	BOOST_TEST_CHECKPOINT("Before generate license");
+	const string licLocation = generate_license(lic_fname, extraArgs);
+	LicenseInfo license;
+	LicenseLocation location = {LICENSE_PATH};
+	std::copy(licLocation.begin(), licLocation.end(), location.licenseData);
+	const LCC_EVENT_TYPE result = acquire_license(nullptr, &location, &license);
+	BOOST_CHECK_EQUAL(result, LICENSE_OK);
+	BOOST_CHECK_EQUAL(license.has_expiry, false);
+	BOOST_CHECK_EQUAL(license.linked_to_pc, true);
+}
+
+BOOST_AUTO_TEST_CASE(volid_lic_file) {
+	HwIdentifier identifier_out;
+	size_t disk_num;
+	FUNCTION_RETURN result_diskinfos = getDiskInfos(nullptr, &disk_num);
+	if ((result_diskinfos == FUNC_RET_BUFFER_TOO_SMALL || result_diskinfos == FUNC_RET_OK) && disk_num > 0) {
+		generate_and_verify_license(LCC_API_IDENTIFICATION_STRATEGY::STRATEGY_DISK_NUM, "volid_lic_file");
+	} else {
+		BOOST_TEST_MESSAGE("No disk found skipping testing disk hardware identifier");
+	}
+}
+
+BOOST_AUTO_TEST_CASE(volume_name_lic_file) {
+	HwIdentifier identifier_out;
+	size_t disk_num;
+	FUNCTION_RETURN result_diskinfos = getDiskInfos(nullptr, &disk_num);
+	if ((result_diskinfos == FUNC_RET_BUFFER_TOO_SMALL || result_diskinfos == FUNC_RET_OK) && disk_num > 0) {
+		generate_and_verify_license(LCC_API_IDENTIFICATION_STRATEGY::STRATEGY_DISK_LABEL, "volume_name_lic_file");
+	} else {
+		BOOST_TEST_MESSAGE("No disk found skipping testing volume name disk hardware identifier");
+	}
+}
+
+BOOST_AUTO_TEST_CASE(strategy_mac_address) {
+	vector<os::OsAdapterInfo> adapters;
+	FUNCTION_RETURN result_adapterInfos = os::getAdapterInfos(adapters);
+	if ((result_adapterInfos == FUNC_RET_BUFFER_TOO_SMALL || result_adapterInfos == FUNC_RET_OK) &&
+		adapters.size() > 0) {
+		generate_and_verify_license(LCC_API_IDENTIFICATION_STRATEGY::STRATEGY_ETHERNET, "strategy_mac_address");
+	} else {
+		BOOST_TEST_MESSAGE("No ethernet adapter found skipping testing mac address hardware identifier");
+	}
+}
+
+BOOST_AUTO_TEST_CASE(strategy_ip_address) {
+	vector<os::OsAdapterInfo> adapters;
+	FUNCTION_RETURN result_adapterInfos = os::getAdapterInfos(adapters);
+	if ((result_adapterInfos == FUNC_RET_BUFFER_TOO_SMALL || result_adapterInfos == FUNC_RET_OK) &&
+		adapters.size() > 0) {
+		generate_and_verify_license(LCC_API_IDENTIFICATION_STRATEGY::STRATEGY_IP_ADDRESS, "strategy_ip_address");
+	} else {
+		BOOST_TEST_MESSAGE("No ethernet adapter found skipping testing ip hardware identifier");
+	}
+}
+
+}  // namespace test
+}  // namespace license
diff --git a/test/functional/signature_verifier_test.cpp b/test/functional/signature_verifier_test.cpp
index 709f7fc..631b47d 100644
--- a/test/functional/signature_verifier_test.cpp
+++ b/test/functional/signature_verifier_test.cpp
@@ -1,3 +1,4 @@
+
 /*
  * LicenseVerifier_test.cpp
  *
@@ -10,7 +11,7 @@
 #include <licensecc_properties_test.h>
 #include <licensecc_properties.h>
 
-#include "../../src/library/os/signature_verifier.h"
+#include "../../src/library/os/signature_verifier.hpp"
 #include "generate-license.h"
 
 namespace license {
@@ -21,7 +22,7 @@
 	const string test_data("test_data");
 	const string signature = sign_data(test_data, string("verify_signature"));
 
-	FUNCTION_RETURN result = license::verify_signature(test_data, signature);
+	FUNCTION_RETURN result = license::os::verify_signature(test_data, signature);
 	BOOST_CHECK_MESSAGE(result == FUNC_RET_OK, "signature verified");
 }
 
@@ -29,7 +30,7 @@
 	const string test_data("test_data");
 	const string signature = sign_data(test_data, string("verify_signature"));
 
-	FUNCTION_RETURN result = license::verify_signature(string("other data"), signature);
+	FUNCTION_RETURN result = license::os::verify_signature(string("other data"), signature);
 	BOOST_CHECK_MESSAGE(result == FUNC_RET_ERROR, "signature NOT verified");
 }
 
@@ -37,7 +38,7 @@
 	const string test_data("test_data");
 	string signature = sign_data(test_data, string("verify_signature"));
 	signature[2] = signature[2] + 1;
-	FUNCTION_RETURN result = license::verify_signature(test_data, signature);
+	FUNCTION_RETURN result = license::os::verify_signature(test_data, signature);
 	BOOST_CHECK_MESSAGE(result == FUNC_RET_ERROR, "signature NOT verified");
 }
 
diff --git a/test/functional/standard-license_test.cpp b/test/functional/standard-license_test.cpp
index 669ca46..ac62764 100644
--- a/test/functional/standard-license_test.cpp
+++ b/test/functional/standard-license_test.cpp
@@ -1,3 +1,4 @@
+
 #define BOOST_TEST_MODULE test_standard_license
 
 #include <boost/test/unit_test.hpp>
@@ -9,26 +10,42 @@
 
 #include "../../src/library/ini/SimpleIni.h"
 #include "generate-license.h"
-#include "../../src/library/base/FileUtils.hpp"
+#include "../../src/library/base/file_utils.hpp"
+
+using namespace std;
+namespace fs = boost::filesystem;
 
 namespace license {
 namespace test {
-namespace fs = boost::filesystem;
-using namespace license;
-using namespace std;
 
 /**
- * Test a generic license with no expiry neither client id.
+ * Test a generic license with no expiry neither client id. The license is read from file
  */
-BOOST_AUTO_TEST_CASE(test_generic_license) {
+BOOST_AUTO_TEST_CASE(test_generic_license_read_file) {
 	const vector<string> extraArgs;
 	const string licLocation = generate_license("standard_license", extraArgs);
 	/* */
 	LicenseInfo license;
-	LicenseLocation licenseLocation;
-	licenseLocation.licenseFileLocation = licLocation.c_str();
-	licenseLocation.licenseData = nullptr;
-	const EVENT_TYPE result = acquire_license(nullptr, &licenseLocation, &license);
+	LicenseLocation location = {LICENSE_PATH};
+	std::copy(licLocation.begin(), licLocation.end(), location.licenseData);
+	const LCC_EVENT_TYPE result = acquire_license(nullptr, &location, &license);
+	BOOST_CHECK_EQUAL(result, LICENSE_OK);
+	BOOST_CHECK_EQUAL(license.has_expiry, false);
+	BOOST_CHECK_EQUAL(license.linked_to_pc, false);
+}
+
+/**
+ * Test a generic license with no expiry neither client id. The license is passed in trhough the licenseData structure.
+ */
+BOOST_AUTO_TEST_CASE(test_read_license_data) {
+	const vector<string> extraArgs;
+	const fs::path licLocation = fs::path(generate_license("standard_license1", extraArgs));
+	const string licLocationStr = licLocation.string();
+	string license_data = get_file_contents(licLocationStr.c_str(), 65536);
+	LicenseInfo license;
+	LicenseLocation location = {LICENSE_PLAIN_DATA};
+	std::copy(license_data.begin(), license_data.end(), location.licenseData);
+	const LCC_EVENT_TYPE result = acquire_license(nullptr, &location, &license);
 	BOOST_CHECK_EQUAL(result, LICENSE_OK);
 	BOOST_CHECK_EQUAL(license.has_expiry, false);
 	BOOST_CHECK_EQUAL(license.linked_to_pc, false);
@@ -55,8 +72,8 @@
 //	BOOST_CHECK_EQUAL(license.linked_to_pc, false);
 //}
 //
-// BOOST_AUTO_TEST_CASE( pc_identifier ) {
-//	const string licLocation(PROJECT_TEST_TEMP_DIR "/pc_identifier.lic");
+// BOOST_AUTO_TEST_CASE( hw_identifier ) {
+//	const string licLocation(PROJECT_TEST_TEMP_DIR "/hw_identifier.lic");
 //	const vector<string> extraArgs = { "-s", "Jaaa-aaaa-MG9F-ZhB1" };
 //	generate_license(licLocation, extraArgs);
 //
diff --git a/test/functional/volid_test.cpp b/test/functional/volid_test.cpp
deleted file mode 100644
index 53dfae3..0000000
--- a/test/functional/volid_test.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-#define BOOST_TEST_MODULE test_volid
-
-#include <boost/test/unit_test.hpp>
-#include <fstream>
-#include <iostream>
-#include <stdio.h>
-#include <cstring>
-#include <boost/filesystem.hpp>
-#include <licensecc_properties.h>
-#include <licensecc_properties_test.h>
-
-#include <licensecc/licensecc.h>
-#include "../../src/library/ini/SimpleIni.h"
-#include "../../src/library/pc-identifiers.h"
-#include "../../src/library/os/os.h"
-#include "generate-license.h"
-
-namespace fs = boost::filesystem;
-using namespace license;
-using namespace std;
-
-namespace license {
-namespace test {
-
-BOOST_AUTO_TEST_CASE( default_volid_lic_file ) {
-	PcSignature identifier_out;
-
-	const IDENTIFICATION_STRATEGY strategy = IDENTIFICATION_STRATEGY::STRATEGY_ETHERNET;
-	BOOST_TEST_CHECKPOINT("Before generate");
-	const FUNCTION_RETURN generate_ok = generate_user_pc_signature(identifier_out,
-			strategy);
-	BOOST_TEST_CHECKPOINT("After generate signature");
-	BOOST_ASSERT(generate_ok == FUNCTION_RETURN::FUNC_RET_OK);
-	cout << "Identifier:" << identifier_out << endl;
-	vector<string> extraArgs;
-	extraArgs.push_back("-s");
-	extraArgs.push_back(identifier_out);
-	BOOST_TEST_CHECKPOINT("Before generate license");
-	const string licLocation = generate_license("volid_license", extraArgs);
-
-	LicenseInfo license;
-	LicenseLocation licenseLocation;
-	licenseLocation.licenseFileLocation = licLocation.c_str();
-	licenseLocation.licenseData = "";
-	const EVENT_TYPE result = acquire_license(nullptr, &licenseLocation, &license);
-	BOOST_CHECK_EQUAL(result, LICENSE_OK);
-	BOOST_CHECK_EQUAL(license.has_expiry, false);
-	BOOST_CHECK_EQUAL(license.linked_to_pc, true);
-}
-
-static void generate_reference_file(const string &idfileLocation,
-		IDENTIFICATION_STRATEGY strategies[], int num_strategies) {
-	ofstream idfile(idfileLocation);
-	PcSignature identifier_out;
-	for (int i = 0; i < num_strategies; i++) {
-		FUNCTION_RETURN generate_ok = generate_user_pc_signature(identifier_out,
-				strategies[i]);
-		if (generate_ok != FUNC_RET_OK) {
-			BOOST_ERROR(
-					"Generating identifier for strategy " << strategies[i] << " failed with: " << generate_ok);
-			idfile << "0000-0000-0000-0000" << endl;
-			BOOST_ASSERT(generate_ok == FUNC_RET_OK);
-		} else
-			idfile << identifier_out << endl;
-	}
-	idfile.close();
-}
-
-BOOST_AUTO_TEST_CASE(generated_identifiers_stability) {
-	const string idfileLocation(PROJECT_TEST_TEMP_DIR "/identifiers_file");
-	std::vector<IDENTIFICATION_STRATEGY> strategies;
-	size_t disk_num;
-	getDiskInfos(NULL, &disk_num);
-	if (disk_num >0) {
-		strategies = {STRATEGY_DEFAULT, STRATEGY_DISK_NUM, STRATEGY_DISK_LABEL};
-	} else {
-		BOOST_TEST_CHECKPOINT("if no disk default strategy fails see #49");
-		//strategies = { DEFAULT };
-		strategies = {};
-	}
-	size_t adapters;
-	getAdapterInfos(nullptr, &adapters);
-	if(adapters > 0){
-		strategies.push_back(STRATEGY_ETHERNET);
-	}
-
-	size_t num_strategies = strategies.size();
-	if(num_strategies == 0) {
-		//see issue #49 can't use default
-		return;
-	}
-	std::ifstream test_idfile_exist(idfileLocation);
-	if (!test_idfile_exist.good()) {
-		generate_reference_file(idfileLocation, strategies.data(),
-				strategies.size());
-	} else {
-		std::istream_iterator<string> start(test_idfile_exist), end;
-		std::vector<string> reference_signatures(start, end);
-		test_idfile_exist.close();
-		if (reference_signatures.size() != num_strategies
-				|| std::find(reference_signatures.begin(),
-						reference_signatures.end(), "0000-0000-0000-0000")
-						!= reference_signatures.end())
-			generate_reference_file(idfileLocation, strategies.data(), num_strategies);
-	}
-	std::ifstream is(idfileLocation);
-	std::istream_iterator<string> start(is), end;
-	std::vector<string> reference_signatures(start, end);
-	BOOST_TEST_CHECKPOINT(
-			"Generating current signatures and comparing with past");
-	for (int i = 0; i < num_strategies; i++) {
-		PcSignature generated_identifier;
-		FUNCTION_RETURN generate_ok = generate_user_pc_signature(
-				generated_identifier, strategies[i]);
-		BOOST_ASSERT(generate_ok == FUNCTION_RETURN::FUNC_RET_OK);
-		if (generate_ok != FUNC_RET_OK) {
-			BOOST_ERROR(
-					"Generating identifier for strategy " << strategies[i] << " failed with: " << generate_ok);
-			continue;
-		}
-		if (reference_signatures[i] != generated_identifier) {
-			string message = string("pc signature compare fail: strategy: ")
-					+ to_string(static_cast<long long>(strategies[i]))
-					+ " generated: [" + generated_identifier + "] reference: ["
-					+ reference_signatures[i] + "]";
-			BOOST_ERROR(message);
-		}
-	}
-	BOOST_TEST_CHECKPOINT("Verifying signatures");
-	for (int j = 0; j < 100; j++) {
-		for (unsigned int i = 0; i < reference_signatures.size(); i++) {
-			if (reference_signatures[i] == "0000-0000-0000-0000")
-				continue;
-			PcSignature pcsig;
-			strncpy(pcsig, reference_signatures[i].c_str(),
-					sizeof(PcSignature) - 1);
-			EVENT_TYPE val_result = validate_pc_signature(pcsig);
-			BOOST_TEST_CHECKPOINT("Verifying signature: ");
-			BOOST_CHECK_EQUAL(val_result, LICENSE_OK);
-		}
-	}
-}
-
-}  // namespace test
-}  // namespace license
diff --git a/test/library/CMakeLists.txt b/test/library/CMakeLists.txt
index c04985d..ab9d134 100644
--- a/test/library/CMakeLists.txt
+++ b/test/library/CMakeLists.txt
@@ -1,24 +1,20 @@
-add_executable(
- test_license_reader
+add_executable( test_license_reader
  LicenseReader_test.cpp
 )
 
-target_link_libraries(
- test_license_reader
+target_link_libraries( test_license_reader
  licensecc_static
  Boost::unit_test_framework 
  Boost::filesystem
  Boost::system
 )
 
-ADD_TEST(NAME test_license_reader COMMAND test_license_reader)
-
 IF(WIN32)
 #test windows
 ELSE(WIN32)
     add_executable(
  		test_os_linux
- 		Os_Linux_test.cpp
+ 		os_linux_test.cpp
 	)
 
 	target_link_libraries(
@@ -34,8 +30,8 @@
 
 ### LicenseLocator tests
 add_executable(
- test_license_locator
- LicenseLocator_test.cpp
+	test_license_locator
+ 	LicenseLocator_test.cpp
 )
 
 target_link_libraries(
@@ -46,20 +42,26 @@
  Boost::system
 )
 
-ADD_TEST(NAME test_license_locator COMMAND test_license_locator)
-
 ### LicenseLocator tests
 add_executable(
  test_event_registry
  EventRegistry_test.cpp
+ $<TARGET_OBJECTS:base>
 )
 
 target_link_libraries(
  test_event_registry
- base
  Boost::unit_test_framework 
- Boost::filesystem
  Boost::system
 )
 
+if(CODE_COVERAGE AND UNIX)
+  target_link_libraries(test_event_registry gcov)
+endif(CODE_COVERAGE AND UNIX)
+
+ADD_TEST(NAME test_license_reader COMMAND test_license_reader)
+ADD_TEST(NAME test_license_locator COMMAND test_license_locator)
 ADD_TEST(NAME test_event_registry COMMAND test_event_registry)
+
+ADD_SUBDIRECTORY(os)
+ADD_SUBDIRECTORY(hw_identifier)
\ No newline at end of file
diff --git a/test/library/LicenseLocator_test.cpp b/test/library/LicenseLocator_test.cpp
index 6c83fc0..99032a7 100644
--- a/test/library/LicenseLocator_test.cpp
+++ b/test/library/LicenseLocator_test.cpp
@@ -1,10 +1,11 @@
 #define BOOST_TEST_MODULE "test_license_locator"
+#define __STDC_WANT_LIB_EXT1__ 1
+#include <string.h>
 
 #include <iostream>
 #include <iterator>
 #include <cstdio>
 #include <fstream>
-#include <string>
 #include <vector>
 #include <boost/filesystem.hpp>
 #include <boost/optional.hpp>
@@ -88,13 +89,14 @@
 
 BOOST_AUTO_TEST_CASE(external_definition) {
 	// an application can define multiple license locations separated by ';'
-	const char *applicationDefinedString = MOCK_LICENSE ";/this/one/doesnt/exist";
+	string applicationDefinedString = MOCK_LICENSE ";/this/one/doesnt/exist";
 
 	// read test license
 	std::ifstream src(MOCK_LICENSE, std::ios::binary);
 	std::string referenceContent((std::istreambuf_iterator<char>(src)), std::istreambuf_iterator<char>());
 	license::EventRegistry registry;
-	const LicenseLocation licLocation = {applicationDefinedString, nullptr};
+	LicenseLocation licLocation = {LICENSE_PATH};
+	std::copy(applicationDefinedString.begin(), applicationDefinedString.end(), licLocation.licenseData);
 	ExternalDefinition externalDefinition(&licLocation);
 	vector<string> licenseInfos = externalDefinition.license_locations(registry);
 	BOOST_CHECK(registry.isGood());
@@ -109,9 +111,10 @@
  * The license file doesn't exist. Check that the locator reports the right error
  */
 BOOST_AUTO_TEST_CASE(external_definition_not_found) {
-	const char *applicationDefinedString = PROJECT_TEST_SRC_DIR "/this/file/doesnt/exist";
+	string applicationDefinedString = PROJECT_TEST_SRC_DIR "/this/file/doesnt/exist";
 	license::EventRegistry registry;
-	const LicenseLocation licLocation = {applicationDefinedString, nullptr};
+	LicenseLocation licLocation = {LICENSE_PATH};
+	std::copy(applicationDefinedString.begin(), applicationDefinedString.end(), licLocation.licenseData);
 	ExternalDefinition externalDefinition(&licLocation);
 	vector<string> licenseInfos = externalDefinition.license_locations(registry);
 
@@ -129,9 +132,9 @@
 	// an application can define multiple license locations separated by ';'
 	const char *environment_variable_value = MOCK_LICENSE ";/this/one/doesnt/exist";
 #ifdef _WIN32
-	_putenv_s(LICENSE_LOCATION_ENV_VAR, environment_variable_value);
+	_putenv_s(LCC_LICENSE_LOCATION_ENV_VAR, environment_variable_value);
 #else
-	setenv(LICENSE_LOCATION_ENV_VAR, environment_variable_value, 1);
+	setenv(LCC_LICENSE_LOCATION_ENV_VAR, environment_variable_value, 1);
 #endif
 	// read test license
 	std::ifstream src(MOCK_LICENSE, std::ios::binary);
@@ -146,7 +149,7 @@
 	BOOST_CHECK_MESSAGE(string(MOCK_LICENSE).compare(currentLocation) == 0, "file found at expected location");
 	string licenseRealContent = envVarLocationStrategy.retrieve_license_content(currentLocation);
 	BOOST_CHECK_MESSAGE(referenceContent.compare(licenseRealContent) == 0, "File content is same");
-	UNSETENV(LICENSE_LOCATION_ENV_VAR);
+	UNSETENV(LCC_LICENSE_LOCATION_ENV_VAR);
 }
 
 /**
@@ -154,7 +157,7 @@
  */
 BOOST_AUTO_TEST_CASE(environment_var_location_not_found) {
 	const char *environment_variable_value = PROJECT_TEST_SRC_DIR "/this/file/doesnt/exist";
-	SETENV(LICENSE_LOCATION_ENV_VAR, environment_variable_value);
+	SETENV(LCC_LICENSE_LOCATION_ENV_VAR, environment_variable_value);
 
 	license::EventRegistry registry;
 	EnvironmentVarLocation envVarLocationStrategy;
@@ -164,14 +167,14 @@
 	BOOST_REQUIRE_MESSAGE(!registry.isGood(), "Error detected");
 	BOOST_CHECK_EQUAL(0, licenseInfos.size());
 	BOOST_CHECK_MESSAGE(registry.getLastFailure()->event_type == LICENSE_FILE_NOT_FOUND, "Error detected");
-	UNSETENV(LICENSE_LOCATION_ENV_VAR);
+	UNSETENV(LCC_LICENSE_LOCATION_ENV_VAR);
 }
 
 /**
  * The license file doesn't exist. Check that the locator reports the right error
  */
 BOOST_AUTO_TEST_CASE(environment_var_location_not_defined) {
-	UNSETENV(LICENSE_LOCATION_ENV_VAR);
+	UNSETENV(LCC_LICENSE_LOCATION_ENV_VAR);
 	license::EventRegistry registry;
 	EnvironmentVarLocation environmentVarLocation;
 	vector<string> licenseInfos = environmentVarLocation.license_locations(registry);
diff --git a/test/library/LicenseReader_test.cpp b/test/library/LicenseReader_test.cpp
index 0b16149..f573874 100644
--- a/test/library/LicenseReader_test.cpp
+++ b/test/library/LicenseReader_test.cpp
@@ -1,4 +1,7 @@
 #define BOOST_TEST_MODULE "test_license_reader"
+#define __STDC_WANT_LIB_EXT1__ 1
+
+#include <string>
 
 #include <boost/test/unit_test.hpp>
 #include <iostream>
@@ -22,10 +25,11 @@
  * Read license at application provided location
  */
 BOOST_AUTO_TEST_CASE(read_single_file) {
-	const char *licLocation = PROJECT_TEST_SRC_DIR "/library/test_reader.ini";
+	string location = PROJECT_TEST_SRC_DIR "/library/test_reader.ini";
 
-	const LicenseLocation location = {licLocation, nullptr};
-	LicenseReader licenseReader(&location);
+	LicenseLocation licLocation = {LICENSE_PATH};
+	std::copy(location.begin(), location.end(), licLocation.licenseData);
+	LicenseReader licenseReader(&licLocation);
 	vector<FullLicenseInfo> licenseInfos;
 	const EventRegistry registry = licenseReader.readLicenses("PrODUCT", licenseInfos);
 	BOOST_CHECK(registry.isGood());
@@ -36,9 +40,10 @@
  * Test the error return if the product code is not found in the license
  */
 BOOST_AUTO_TEST_CASE(product_not_licensed) {
-	const char *licLocation = PROJECT_TEST_SRC_DIR "/library/test_reader.ini";
-	const LicenseLocation location = {licLocation, nullptr};
-	LicenseReader licenseReader(&location);
+	string location = PROJECT_TEST_SRC_DIR "/library/test_reader.ini";
+	LicenseLocation licLocation = {LICENSE_PATH};
+	std::copy(location.begin(), location.end(), licLocation.licenseData);
+	LicenseReader licenseReader(&licLocation);
 	vector<FullLicenseInfo> licenseInfos;
 	const EventRegistry registry = licenseReader.readLicenses("PRODUCT-NOT", licenseInfos);
 	BOOST_CHECK(!registry.isGood());
@@ -51,11 +56,12 @@
  * Test the error code if the license file is specified but doesn't exists
  */
 BOOST_AUTO_TEST_CASE(file_not_found) {
-	const char *licLocation = PROJECT_TEST_SRC_DIR "/library/not_found.ini";
+	string licLocation = PROJECT_TEST_SRC_DIR "/library/not_found.ini";
 
 	locate::LocatorFactory::find_license_near_module(false);
 	locate::LocatorFactory::find_license_with_env_var(false);
-	const LicenseLocation location = {licLocation, nullptr};
+	LicenseLocation location = {LICENSE_PATH};
+	std::copy(licLocation.begin(), licLocation.end(), location.licenseData);
 	LicenseReader licenseReader(&location);
 	vector<FullLicenseInfo> licenseInfos;
 	const EventRegistry registry = licenseReader.readLicenses("PRODUCT", licenseInfos);
@@ -69,11 +75,10 @@
  * Test the error code if the license default environment variable isn't specified
  */
 BOOST_AUTO_TEST_CASE(env_var_not_defined) {
-	UNSETENV(LICENSE_LOCATION_ENV_VAR);
-	const LicenseLocation location = {nullptr, nullptr};
+	UNSETENV(LCC_LICENSE_LOCATION_ENV_VAR);
 	locate::LocatorFactory::find_license_near_module(false);
 	locate::LocatorFactory::find_license_with_env_var(true);
-	LicenseReader licenseReader(&location);
+	LicenseReader licenseReader(nullptr);
 	vector<FullLicenseInfo> licenseInfos;
 	const EventRegistry registry = licenseReader.readLicenses("PRODUCT", licenseInfos);
 	BOOST_CHECK(!registry.isGood());
@@ -89,12 +94,11 @@
  */
 BOOST_AUTO_TEST_CASE(env_var_point_to_wrong_file) {
 	const char *environment_variable_value = PROJECT_TEST_SRC_DIR "/this/file/doesnt/exist";
-	SETENV(LICENSE_LOCATION_ENV_VAR, environment_variable_value)
+	SETENV(LCC_LICENSE_LOCATION_ENV_VAR, environment_variable_value)
 	locate::LocatorFactory::find_license_near_module(false);
 	locate::LocatorFactory::find_license_with_env_var(true);
 
-	const LicenseLocation location = {nullptr, nullptr};
-	LicenseReader licenseReader(&location);
+	LicenseReader licenseReader(nullptr);
 	vector<FullLicenseInfo> licenseInfos;
 	const EventRegistry registry = licenseReader.readLicenses("PRODUCT", licenseInfos);
 	cout << registry << endl;
@@ -102,7 +106,7 @@
 	BOOST_CHECK_EQUAL(0, licenseInfos.size());
 	BOOST_ASSERT(registry.getLastFailure() != NULL);
 	BOOST_CHECK_EQUAL(LICENSE_FILE_NOT_FOUND, registry.getLastFailure()->event_type);
-	UNSETENV(LICENSE_LOCATION_ENV_VAR);
+	UNSETENV(LCC_LICENSE_LOCATION_ENV_VAR);
 }
 }  // namespace test
 }  // namespace license
diff --git a/test/library/Os_Linux_test.cpp b/test/library/Os_Linux_test.cpp
deleted file mode 100644
index b7b8c21..0000000
--- a/test/library/Os_Linux_test.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-#define BOOST_TEST_MODULE os_linux_test
-#include <string>
-#include <iostream>
-#include <boost/test/unit_test.hpp>
-
-#include <licensecc_properties.h>
-#include <licensecc_properties_test.h>
-#include "../../src/library/base/StringUtils.h"
-#include "../../src/library/os/os.h"
-namespace license {
-using namespace std;
-namespace test {
-BOOST_AUTO_TEST_CASE(read_disk_id) {
-	VIRTUALIZATION virt = getVirtualization();
-	if (virt == NONE || virt == VM) {
-		DiskInfo *diskInfos = NULL;
-		size_t disk_info_size = 0;
-		FUNCTION_RETURN result = getDiskInfos(NULL, &disk_info_size);
-		BOOST_CHECK_EQUAL(result, FUNC_RET_OK);
-		BOOST_CHECK_GT(disk_info_size, 0);
-		diskInfos = (DiskInfo *)malloc(sizeof(DiskInfo) * disk_info_size);
-		result = getDiskInfos(diskInfos, &disk_info_size);
-		BOOST_CHECK_EQUAL(result, FUNC_RET_OK);
-		BOOST_CHECK_GT(mstrnlen_s(diskInfos[0].device, sizeof(diskInfos[0].device)), 0);
-		BOOST_CHECK_GT(mstrnlen_s(diskInfos[0].label, sizeof diskInfos[0].label), 0);
-		BOOST_CHECK_GT(diskInfos[0].disk_sn[0], 0);
-		free(diskInfos);
-	} else if (virt == CONTAINER) {
-		// docker or lxc diskInfo is not meaningful
-		DiskInfo *diskInfos = NULL;
-		size_t disk_info_size = 0;
-		FUNCTION_RETURN result = getDiskInfos(NULL, &disk_info_size);
-		BOOST_CHECK_EQUAL(result, FUNC_RET_NOT_AVAIL);
-	}
-}
-
-BOOST_AUTO_TEST_CASE(read_network_adapters) {
-	OsAdapterInfo *adapter_info = NULL;
-	size_t adapter_info_size = 0;
-	FUNCTION_RETURN result = getAdapterInfos(NULL, &adapter_info_size);
-	BOOST_CHECK_EQUAL(result, FUNC_RET_OK);
-	BOOST_CHECK_GT(adapter_info_size, 0);
-	adapter_info = (OsAdapterInfo *)malloc(sizeof(OsAdapterInfo) * adapter_info_size);
-	result = getAdapterInfos(adapter_info, &adapter_info_size);
-	BOOST_CHECK_EQUAL(result, FUNC_RET_OK);
-	for (size_t i = 0; i < adapter_info_size; i++) {
-		cout << "Interface found: " << string(adapter_info[i].description) << endl;
-		BOOST_CHECK_GT(strlen(adapter_info[i].description), 0);
-		// lo mac address is always 0 but it has ip
-		// other interfaces may not be connected
-		if (string(adapter_info[i].description) == "lo") {
-			BOOST_CHECK_NE(adapter_info[i].ipv4_address[0], 0);
-		} else {
-			bool mac_is_0 = true;
-			for (int j = 0; j < 6; j++) {
-				mac_is_0 = mac_is_0 && (adapter_info[i].mac_address[j] == 0);
-			}
-			BOOST_CHECK_MESSAGE(!mac_is_0, "Mac address for interface " << adapter_info[i].description << " is 0");
-		}
-	}
-	free(adapter_info);
-}
-
-BOOST_AUTO_TEST_CASE(get_cpuid) { BOOST_CHECK_EQUAL(1, 1); }
-
-// To test if virtualization is detected correctly define an env variable VIRT_ENV
-// otherwise the test is skipped
-BOOST_AUTO_TEST_CASE(test_virtualization) {
-	const char *env = getenv("VIRT_ENV");
-	if (env != NULL) {
-		if (strcmp(env, "CONTAINER") == 0) {
-			VIRTUALIZATION virt = getVirtualization();
-			BOOST_CHECK_EQUAL(virt, CONTAINER);
-		} else if (strcmp(env, "VM") == 0) {
-			BOOST_FAIL("check for vm not implemented");
-		} else if (strcmp(env, "NONE") == 0) {
-			VIRTUALIZATION virt = getVirtualization();
-			BOOST_CHECK_EQUAL(virt, NONE);
-		} else {
-			BOOST_FAIL(string("value ") + env + " not supported: VM,CONTAINER,NONE");
-		}
-	}
-}
-}  // namespace test
-}  // namespace license
diff --git a/test/library/hw_identifier/CMakeLists.txt b/test/library/hw_identifier/CMakeLists.txt
new file mode 100644
index 0000000..0c4df23
--- /dev/null
+++ b/test/library/hw_identifier/CMakeLists.txt
@@ -0,0 +1,16 @@
+add_executable( test_hw_identifier
+ hw_identifier_test.cpp
+)
+
+target_link_libraries( test_hw_identifier
+ licensecc_static
+ Boost::unit_test_framework 
+ Boost::filesystem
+ Boost::system
+)
+
+if(CODE_COVERAGE AND UNIX)
+	  target_compile_options(test_hw_identifier PUBLIC -O0 -g --coverage)
+endif(CODE_COVERAGE AND UNIX)
+
+ADD_TEST(NAME test_hw_identifier COMMAND test_hw_identifier)
diff --git a/test/library/hw_identifier/disk_strategy_test.cpp b/test/library/hw_identifier/disk_strategy_test.cpp
new file mode 100644
index 0000000..8cba3cf
--- /dev/null
+++ b/test/library/hw_identifier/disk_strategy_test.cpp
@@ -0,0 +1,10 @@
+/*
+ * default_strategy_test.cpp
+ *
+ *  Created on: Jan 2, 2020
+ *      Author: devel
+ */
+
+#include "default_strategy.hpp"
+
+namespace license {} /* namespace license */
diff --git a/test/library/hw_identifier/ethernet_test.cpp b/test/library/hw_identifier/ethernet_test.cpp
new file mode 100644
index 0000000..be8bdad
--- /dev/null
+++ b/test/library/hw_identifier/ethernet_test.cpp
@@ -0,0 +1,10 @@
+/*
+ * ethernet_test.cpp
+ *
+ *  Created on: Jan 11, 2020
+ *      Author: devel
+ */
+
+#include "ethernet.hpp"
+
+namespace license {} /* namespace license */
diff --git a/test/library/hw_identifier/hw_identifier_facade_test.cpp b/test/library/hw_identifier/hw_identifier_facade_test.cpp
new file mode 100644
index 0000000..1a47b38
--- /dev/null
+++ b/test/library/hw_identifier/hw_identifier_facade_test.cpp
@@ -0,0 +1,100 @@
+/*
+ * hw_identifier_facade_test.cpp
+ *
+ *  Created on: Dec 26, 2019
+ *      Author: devel
+ */
+
+#include "../../../src/library/hw_identifier/hw_identifier_facade.hpp"
+
+namespace license {
+/*
+ * Test identifier stability:
+ * 1) generate the pc-identifier
+ * 2) save it to disk
+ * 3) every time check that the identifier can still be verified.
+ */
+static void generate_reference_file(const string &idfileLocation, LCC_API_IDENTIFICATION_STRATEGY strategies[],
+									int num_strategies) {
+	ofstream idfile(idfileLocation);
+	PcSignature identifier_out;
+	for (int i = 0; i < num_strategies; i++) {
+		FUNCTION_RETURN generate_ok = generate_user_pc_signature(identifier_out, strategies[i]);
+		if (generate_ok != FUNC_RET_OK) {
+			BOOST_ERROR("Generating identifier for strategy " << strategies[i] << " failed with: " << generate_ok);
+			idfile << "0000-0000-0000-0000" << endl;
+			BOOST_ASSERT(generate_ok == FUNC_RET_OK);
+		} else
+			idfile << identifier_out << endl;
+	}
+	idfile.close();
+}
+
+BOOST_AUTO_TEST_CASE(generated_identifiers_stability) {
+	const string idfileLocation(PROJECT_TEST_TEMP_DIR "/identifiers_file");
+	std::vector<LCC_API_IDENTIFICATION_STRATEGY> strategies;
+	size_t disk_num;
+	getDiskInfos(NULL, &disk_num);
+	if (disk_num > 0) {
+		strategies = {STRATEGY_DEFAULT, STRATEGY_DISK_NUM, STRATEGY_DISK_LABEL};
+	} else {
+		BOOST_TEST_CHECKPOINT("if no disk default strategy fails see #49");
+		// strategies = { DEFAULT };
+		strategies = {};
+	}
+	size_t adapters;
+	getAdapterInfos(nullptr, &adapters);
+	if (adapters > 0) {
+		strategies.push_back(STRATEGY_ETHERNET);
+	}
+
+	size_t num_strategies = strategies.size();
+	if (num_strategies == 0) {
+		// see issue #49 can't use default
+		return;
+	}
+	std::ifstream test_idfile_exist(idfileLocation);
+	if (!test_idfile_exist.good()) {
+		generate_reference_file(idfileLocation, strategies.data(), strategies.size());
+	} else {
+		std::istream_iterator<string> start(test_idfile_exist), end;
+		std::vector<string> reference_signatures(start, end);
+		test_idfile_exist.close();
+		if (reference_signatures.size() != num_strategies ||
+			std::find(reference_signatures.begin(), reference_signatures.end(), "0000-0000-0000-0000") !=
+				reference_signatures.end())
+			generate_reference_file(idfileLocation, strategies.data(), num_strategies);
+	}
+	std::ifstream is(idfileLocation);
+	std::istream_iterator<string> start(is), end;
+	std::vector<string> reference_signatures(start, end);
+	BOOST_TEST_CHECKPOINT("Generating current signatures and comparing with past");
+	for (int i = 0; i < num_strategies; i++) {
+		PcSignature generated_identifier;
+		FUNCTION_RETURN generate_ok = generate_user_pc_signature(generated_identifier, strategies[i]);
+		BOOST_ASSERT(generate_ok == FUNCTION_RETURN::FUNC_RET_OK);
+		if (generate_ok != FUNC_RET_OK) {
+			BOOST_ERROR("Generating identifier for strategy " << strategies[i] << " failed with: " << generate_ok);
+			continue;
+		}
+		if (reference_signatures[i] != generated_identifier) {
+			string message = string("pc signature compare fail: strategy: ") +
+							 to_string(static_cast<long long>(strategies[i])) + " generated: [" + generated_identifier +
+							 "] reference: [" + reference_signatures[i] + "]";
+			BOOST_ERROR(message);
+		}
+	}
+	BOOST_TEST_CHECKPOINT("Verifying signatures");
+	for (int j = 0; j < 100; j++) {
+		for (unsigned int i = 0; i < reference_signatures.size(); i++) {
+			if (reference_signatures[i] == "0000-0000-0000-0000") continue;
+			PcSignature pcsig;
+			strncpy(pcsig, reference_signatures[i].c_str(), sizeof(PcSignature) - 1);
+			LCC_EVENT_TYPE val_result = validate_pc_signature(pcsig);
+			BOOST_TEST_CHECKPOINT("Verifying signature: ");
+			BOOST_CHECK_EQUAL(val_result, LICENSE_OK);
+		}
+	}
+}
+
+} /* namespace license */
diff --git a/test/library/hw_identifier/hw_identifier_test.cpp b/test/library/hw_identifier/hw_identifier_test.cpp
new file mode 100644
index 0000000..1e0062c
--- /dev/null
+++ b/test/library/hw_identifier/hw_identifier_test.cpp
@@ -0,0 +1,65 @@
+/*
+ * Test on class HwIdentifier
+ *
+ *  Created on: Dec 26, 2019
+ *      Author: devel
+ */
+
+#define BOOST_TEST_MODULE test_hw_identifier
+
+#include <boost/test/unit_test.hpp>
+#include <fstream>
+#include <iostream>
+#include <stdio.h>
+#include <cstring>
+#include <boost/filesystem.hpp>
+#include <licensecc_properties.h>
+#include <licensecc_properties_test.h>
+
+#include <licensecc/licensecc.h>
+#include "../../../src/library/hw_identifier/hw_identifier.hpp"
+
+namespace license {
+namespace test {
+using namespace std;
+using namespace license::hw_identifier;
+
+/**
+ * Test get and set and compare hardware identifier data
+ */
+BOOST_AUTO_TEST_CASE(set_and_compare_data) {
+	array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> data = {0xFF, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42};
+	HwIdentifier pc_id;
+	pc_id.set_data(data);
+	data[0] = data[0] & 0x1f;
+	BOOST_CHECK_MESSAGE(pc_id.data_match(data), "Data match");
+}
+/**
+ * Test get and set and compare hardware identifier data
+ */
+BOOST_AUTO_TEST_CASE(compare_wrong_data) {
+	array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> data = {0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42};
+	HwIdentifier pc_id;
+	pc_id.set_data(data);
+	data[4] = 0;
+	BOOST_CHECK_MESSAGE(!pc_id.data_match(data), "Data shouldn't match");
+}
+
+/**
+ * Print a hardware identifier and read it from the same string, check the data matches
+ */
+BOOST_AUTO_TEST_CASE(print_and_read) {
+	array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> data = {0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42};
+	HwIdentifier pc_id;
+	pc_id.set_data(data);
+	pc_id.set_identification_strategy(LCC_API_IDENTIFICATION_STRATEGY::STRATEGY_ETHERNET);
+	string pc_id_str = pc_id.print();
+	cout << pc_id_str << endl;
+	const HwIdentifier id2(pc_id_str);
+	BOOST_CHECK_MESSAGE(id2.get_identification_strategy() == LCC_API_IDENTIFICATION_STRATEGY::STRATEGY_ETHERNET,
+						"Strategy decoded correctly");
+	BOOST_CHECK_MESSAGE(id2.data_match(data), "Data deserialized correctly");
+}
+
+}  // namespace test
+}  // namespace license
diff --git a/test/library/os/CMakeLists.txt b/test/library/os/CMakeLists.txt
new file mode 100644
index 0000000..1af4e92
--- /dev/null
+++ b/test/library/os/CMakeLists.txt
@@ -0,0 +1,29 @@
+add_executable( test_network
+ network_test.cpp
+)
+
+target_link_libraries( test_network
+ licensecc_static
+ Boost::unit_test_framework 
+ Boost::filesystem
+ Boost::system
+)
+
+ADD_TEST(NAME test_network COMMAND test_network)
+
+add_executable( test_execution_environment
+ execution_environment_test.cpp
+)
+
+target_link_libraries( test_execution_environment
+ licensecc_static
+ Boost::unit_test_framework 
+ Boost::filesystem
+ Boost::system
+)
+
+ADD_TEST(NAME test_execution_environment COMMAND test_execution_environment)
+if(CODE_COVERAGE AND UNIX)
+	target_compile_options(test_network PUBLIC -O0 -g --coverage)
+	target_compile_options(test_execution_environment PUBLIC -O0 -g --coverage)
+endif(CODE_COVERAGE AND UNIX)
diff --git a/test/library/os/cpu_info_test.cpp b/test/library/os/cpu_info_test.cpp
new file mode 100644
index 0000000..e04f2fe
--- /dev/null
+++ b/test/library/os/cpu_info_test.cpp
@@ -0,0 +1,10 @@
+/*
+ * cpu_info_test.cpp
+ *
+ *  Created on: Dec 19, 2019
+ *      Author: devel
+ */
+
+#include "cpu_info.hpp"
+
+namespace license {} /* namespace license */
diff --git a/test/library/os/execution_environment_test.cpp b/test/library/os/execution_environment_test.cpp
new file mode 100644
index 0000000..b604d11
--- /dev/null
+++ b/test/library/os/execution_environment_test.cpp
@@ -0,0 +1,48 @@
+#define BOOST_TEST_MODULE network_test
+#include <string>
+#include <iostream>
+#include <boost/test/unit_test.hpp>
+
+#include <licensecc_properties.h>
+#include <licensecc_properties_test.h>
+#include "../../../src/library/base/StringUtils.h"
+#include "../../../src/library/os/network.hpp"
+#include "../../../src/library/os/execution_environment.hpp"
+
+namespace license {
+namespace os {
+namespace test {
+
+using namespace license::os;
+using namespace std;
+
+// To test if virtualization is detected correctly define an env variable VIRT_ENV
+// otherwise the test is skipped
+BOOST_AUTO_TEST_CASE(test_virtualization) {
+	const char *env = getenv("VIRTUAL_ENV");
+	os::ExecutionEnvironment exec_env;
+	bool docker = false;
+	if (env != nullptr) {
+		os::VIRTUALIZATION virt = exec_env.getVirtualization();
+		if (strcmp(env, "CONTAINER") == 0 || (docker = (strcmp(env, "DOCKER") == 0))) {
+			BOOST_CHECK_MESSAGE(virt == VIRTUALIZATION::CONTAINER, "container detected");
+			BOOST_CHECK_MESSAGE(exec_env.is_container(), "container detected");
+			if (docker) {
+				BOOST_CHECK_MESSAGE(exec_env.is_docker(), "docker detected");
+			}
+		} else if (strcmp(env, "VM") == 0) {
+			BOOST_CHECK_MESSAGE(virt == VIRTUALIZATION::VM, "VM detected");
+			BOOST_CHECK_MESSAGE(!exec_env.is_container(), "VM is not a container");
+			BOOST_CHECK_MESSAGE(!exec_env.is_docker(), "VM is not a docker");
+		} else if (strcmp(env, "NONE") == 0) {
+			BOOST_CHECK_EQUAL(virt, VIRTUALIZATION::NONE);
+			BOOST_CHECK_MESSAGE(!exec_env.is_container(), "not a container");
+			BOOST_CHECK_MESSAGE(!exec_env.is_docker(), "not a docker");
+		} else {
+			BOOST_FAIL(string("value ") + env + " not supported: VM,DOCKER,CONTAINER,NONE");
+		}
+	}
+}
+}  // namespace test
+}  // namespace os
+}  // namespace license
diff --git a/test/library/os/network_test.cpp b/test/library/os/network_test.cpp
new file mode 100644
index 0000000..f5a7483
--- /dev/null
+++ b/test/library/os/network_test.cpp
@@ -0,0 +1,50 @@
+#define BOOST_TEST_MODULE network_test
+#include <string>
+#include <iostream>
+#include <boost/test/unit_test.hpp>
+
+#include <licensecc_properties.h>
+#include <licensecc_properties_test.h>
+#include "../../../src/library/base/StringUtils.h"
+#include "../../../src/library/os/network.hpp"
+#include "../../../src/library/os/execution_environment.hpp"
+
+namespace license {
+namespace os {
+namespace test {
+
+using namespace license::os;
+using namespace std;
+
+BOOST_AUTO_TEST_CASE(read_network_adapters) {
+	std::vector<license::os::OsAdapterInfo> adapters;
+	// we can suppose every test environment  other than docker has at least one network interface (it's hard to
+	// download this source code)
+	FUNCTION_RETURN result = getAdapterInfos(adapters);
+	ExecutionEnvironment exec_env;
+	if (result != FUNC_RET_OK && exec_env.is_docker()) {
+		BOOST_TEST_MESSAGE("detected docker environment, not having network interfaces is normal here");
+		return;
+	}
+	BOOST_CHECK_EQUAL(result, FUNC_RET_OK);
+	for (auto& it : adapters) {
+		cout << "Interface found: " << string(it.description) << endl;
+		BOOST_CHECK_GT(strlen(it.description), 0);
+		// lo mac address is always 0 but it has ip
+		// other interfaces may not be connected
+		if (string(it.description) == "lo") {
+			BOOST_FAIL("loopback adapters shouldn't appear");
+		} else {
+			// check mac address are not all zero
+			bool mac_is_0 = true;
+			for (int j = 0; j < 6; j++) {
+				mac_is_0 = mac_is_0 || (it.mac_address[j] != 0);
+			}
+			BOOST_CHECK_MESSAGE(mac_is_0, "Mac address for interface " << it.description << " is 0");
+		}
+	}
+}
+
+}  // namespace test
+}  // namespace os
+}  // namespace license
diff --git a/test/library/os_linux_test.cpp b/test/library/os_linux_test.cpp
new file mode 100644
index 0000000..527da44
--- /dev/null
+++ b/test/library/os_linux_test.cpp
@@ -0,0 +1,43 @@
+#define BOOST_TEST_MODULE os_linux_test
+#include <string>
+#include <iostream>
+#include <boost/test/unit_test.hpp>
+
+#include <licensecc_properties.h>
+#include <licensecc_properties_test.h>
+#include "../../src/library/base/StringUtils.h"
+#include "../../src/library/os/os.h"
+#include "../../src/library/os/execution_environment.hpp"
+
+namespace license {
+namespace test {
+using namespace std;
+using namespace os;
+
+BOOST_AUTO_TEST_CASE(read_disk_id) {
+	os::ExecutionEnvironment exec_env;
+	os::VIRTUALIZATION virt = exec_env.getVirtualization();
+	if (virt == VIRTUALIZATION::NONE || virt == VIRTUALIZATION::VM) {
+		DiskInfo *diskInfos = NULL;
+		size_t disk_info_size = 0;
+		FUNCTION_RETURN result = getDiskInfos(NULL, &disk_info_size);
+		BOOST_CHECK_EQUAL(result, FUNC_RET_OK);
+		BOOST_CHECK_GT(disk_info_size, 0);
+		diskInfos = (DiskInfo *)malloc(sizeof(DiskInfo) * disk_info_size);
+		result = getDiskInfos(diskInfos, &disk_info_size);
+		BOOST_CHECK_EQUAL(result, FUNC_RET_OK);
+		BOOST_CHECK_GT(mstrnlen_s(diskInfos[0].device, sizeof(diskInfos[0].device)), 0);
+		BOOST_CHECK_GT(mstrnlen_s(diskInfos[0].label, sizeof diskInfos[0].label), 0);
+		BOOST_CHECK_GT(diskInfos[0].disk_sn[0], 0);
+		free(diskInfos);
+	} else if (virt == VIRTUALIZATION::CONTAINER) {
+		// docker or lxc diskInfo is not meaningful
+		DiskInfo *diskInfos = NULL;
+		size_t disk_info_size = 0;
+		FUNCTION_RETURN result = getDiskInfos(NULL, &disk_info_size);
+		BOOST_CHECK_EQUAL(result, FUNC_RET_NOT_AVAIL);
+	}
+}
+
+}  // namespace test
+}  // namespace license

--
Gitblit v1.9.1