/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2015 Danny Robson */ #include "registry.hpp" #include "../cast.hpp" #include "except.hpp" #include "debug/panic.hpp" #include #include #include using cruft::win32::key; /////////////////////////////////////////////////////////////////////////////// typedef uint64_t QWORD; //----------------------------------------------------------------------------- template constexpr DWORD type_to_id (void); template <> constexpr DWORD type_to_id (void) { return REG_DWORD; } template <> constexpr DWORD type_to_id (void) { return REG_QWORD; } template <> constexpr DWORD type_to_id (void) { return REG_NONE; } template <> constexpr DWORD type_to_id (void) { return REG_SZ; } //----------------------------------------------------------------------------- template constexpr DWORD restrict_to_id (void); template <> constexpr DWORD restrict_to_id (void) { return RRF_RT_DWORD; } template <> constexpr DWORD restrict_to_id (void) { return RRF_RT_QWORD; } template <> constexpr DWORD restrict_to_id (void) { return RRF_RT_REG_NONE; } template <> constexpr DWORD restrict_to_id (void) { return RRF_RT_REG_SZ; } /////////////////////////////////////////////////////////////////////////////// key::key (key const &parent, char const *path, REGSAM rights) { auto err = RegOpenKeyEx (parent.m_handle, path, 0, rights, &m_handle); win32::error::try_code (err); } //----------------------------------------------------------------------------- key::key (HKEY root, const char *child, REGSAM rights) { auto err = RegOpenKeyEx (root, child, 0, rights, &m_handle); win32::error::try_code (err); } //----------------------------------------------------------------------------- key::~key () { auto err = RegCloseKey (m_handle); win32::error::try_code (err); } /////////////////////////////////////////////////////////////////////////////// cruft::view key::subkeys (void) { DWORD size; auto err = RegQueryInfoKey ( m_handle, nullptr, nullptr, nullptr, &size, nullptr, // longest subkey size nullptr, // longest class string nullptr, // number of values for this key nullptr, // longest value name nullptr, // longest value data nullptr, // security descriptor nullptr // last write time ); error::try_code (err); return { child_iterator (*this), child_iterator (*this, size) }; } //----------------------------------------------------------------------------- key::child_iterator::child_iterator (key const &_parent) : child_iterator (_parent, 0) { ; } //----------------------------------------------------------------------------- key::child_iterator::child_iterator (key const &_parent, int _index) : m_parent (_parent) , m_index (_index) { ; } //----------------------------------------------------------------------------- key key::child_iterator::operator* (void) const { DWORD name_size = strlen ("{00000000-0000-0000-0000-000000000000}"); std::string name (name_size, '\0'); while (1) { auto const err = RegEnumKeyEx( m_parent.m_handle, m_index, name.data(), &name_size, nullptr, nullptr, nullptr, nullptr ); switch (err) { case ERROR_SUCCESS: name.resize (name_size); return key (m_parent, name.c_str ()); case ERROR_MORE_DATA: name_size *= 2; name.resize (name_size); continue; default: error::throw_code (err); } } unreachable (); } //----------------------------------------------------------------------------- key::child_iterator& key::child_iterator::operator++ () { ++m_index; return *this; } //----------------------------------------------------------------------------- bool key::child_iterator::operator== (child_iterator const &rhs) { CHECK_EQ (&m_parent, &rhs.m_parent); return m_index == rhs.m_index; } //----------------------------------------------------------------------------- bool key::child_iterator::operator!= (child_iterator const &rhs) { return !(*this == rhs); } /////////////////////////////////////////////////////////////////////////////// std::string key::name (void) const { // allocate an initial buffer large enough to contain a GUID given that // strings like these are pretty common. DWORD size = strlen ("{00000000-0000-0000-0000-000000000000}"); std::string value (size, '\0'); // keep attempting to read the name of the key. if it fails then we double // the size of the string and try again. while (1) { auto res = RegQueryInfoKey ( m_handle, value.data (), &size, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr ); switch (res) { case ERROR_SUCCESS: value.resize (size); return value; case ERROR_MORE_DATA: size *= 2; continue; default: win32::error::throw_code (res); } } unreachable (); } /////////////////////////////////////////////////////////////////////////////// template T key::data (const char *name) const { T value; DWORD type; DWORD size = sizeof (value); auto err = RegGetValue (m_handle, name, &value, restrict_to_id (), &type, &value, &size); win32::error::try_code (err); return value; } //----------------------------------------------------------------------------- template <> std::string key::data (char const *name) const { DWORD size = strlen ("{00000000-0000-0000-0000-000000000000}"); std::string value (size, '\0'); while (1) { DWORD type; auto const err = RegGetValue( m_handle, nullptr, name, restrict_to_id(), &type, value.data(), &size ); switch (err) { case ERROR_SUCCESS: value.resize (size); return value; case ERROR_MORE_DATA: size *= 2; value.resize (size); continue; default: error::throw_code (err); } } } //----------------------------------------------------------------------------- std::set key::values (void) const { std::set all; for (DWORD i = 0; ; ++i) { std::string name (255, '\0'); DWORD size = cruft::cast::narrow (name.size ()); auto err = RegEnumValue (m_handle, i, &name[0], &size, nullptr, nullptr, nullptr, nullptr); if (ERROR_NO_MORE_ITEMS == err) return all; if (ERROR_SUCCESS != err) win32::error::throw_code (err); CHECK_GT (size, 0u); name.resize (size); all.insert (std::move (name)); } }