new file from hooples.
authorChris Koeritz <fred@gruntose.com>
Sun, 15 Apr 2012 20:20:22 +0000 (16:20 -0400)
committerChris Koeritz <fred@gruntose.com>
Sun, 15 Apr 2012 20:20:22 +0000 (16:20 -0400)
nucleus/library/application/makefile
nucleus/library/application/registry_config.cpp [new file with mode: 0644]
nucleus/library/application/registry_config.h [new file with mode: 0644]

index 758240c58def7d4146313b8dc94cc43b1992daea..c2548b55e2280c7f0fc4dad7272b1c598857f13b 100644 (file)
@@ -3,8 +3,8 @@ include cpp/variables.def
 PROJECT = application
 TYPE = library
 SOURCE = application_shell.cpp callstack_tracker.cpp command_line.cpp dll_root.cpp \
-  hoople_service.cpp launch_manager.cpp memory_checker.cpp redirecter.cpp shared_memory.cpp \
-  singleton_application.cpp windoze_helper.cpp
+  hoople_service.cpp launch_manager.cpp memory_checker.cpp redirecter.cpp \
+  registry_config.cpp shared_memory.cpp singleton_application.cpp windoze_helper.cpp
 TARGETS = application.lib
 LOCAL_LIBS_USED = basis
 
diff --git a/nucleus/library/application/registry_config.cpp b/nucleus/library/application/registry_config.cpp
new file mode 100644 (file)
index 0000000..96f9fc9
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+*  Name   : registry_configurator                                             *
+*  Author : Chris Koeritz                                                     *
+**
+* Copyright (c) 2004-$now By Author.  This program is free software; you can  *
+* redistribute it and/or modify it under the terms of the GNU General Public  *
+* License as published by the Free Software Foundation; either version 2 of   *
+* the License or (at your option) any later version.  This is online at:      *
+*     http://www.fsf.org/copyleft/gpl.html                                    *
+* Please send any updates to: fred@gruntose.com                               *
+*/
+
+#include "registry_config.h"
+
+#include <basis/astring.h>
+#include <basis/functions.h>
+#include <basis/utf_conversion.h>
+#include <structures/static_memory_gremlin.h>
+#include <structures/string_array.h>
+#include <structures/string_table.h>
+
+using namespace basis;
+using namespace filesystem;
+using namespace structures;
+
+#ifdef __WIN32__
+
+  // this implementation only works on windows currently.
+//hmmm: i suppose we could fake it with an ini file.
+
+  #include <shlwapi.h>
+#endif
+
+#undef LOG
+#ifdef DEBUG_REGISTRY_CONFIGURATOR
+  #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
+#else
+  #define LOG(s) {}
+#endif
+
+//#define DEBUG_REGISTRY_CONFIGURATOR
+  // uncomment for noisy version.
+
+namespace configuration {
+
+const int MAXIMUM_ENTRY_SIZE = 256 * KILOBYTE;
+  // arbitrary maximum for entries we'll read.
+
+const int MAXIMUM_NAME_SIZE = 16384;
+  // the longest that value names can be in the registry.
+
+// a default we hope never to see in the registry.
+//SAFE_STATIC_CONST(astring, registry_configurator::reg_str_fake_default,
+ //   ("bogus_never_should_see"));
+const astring &registry_configurator::reg_str_fake_default()
+{
+  static astring _hidden = "bogus_never_should_see";
+  return _hidden;
+}
+
+registry_configurator::registry_configurator(registry_hives hive,
+      treatment_of_defaults behavior)
+: configurator(behavior),
+  _hive(hive)
+{}
+
+registry_configurator::~registry_configurator()
+{}
+
+#ifndef __WIN32__
+// fake the platform dependent names.
+void *HKEY_CLASSES_ROOT = NULL;
+void *HKEY_CURRENT_USER = NULL;
+void *HKEY_LOCAL_MACHINE = NULL;
+void *HKEY_USERS = NULL;
+void *HKEY_CURRENT_CONFIG = NULL;
+#endif
+
+void *registry_configurator::translate_hive(registry_hives hive)
+{
+  switch (hive) {
+    case hkey_classes_root: return HKEY_CLASSES_ROOT;
+    case hkey_current_user: return HKEY_CURRENT_USER;
+    case hkey_local_machine: return HKEY_LOCAL_MACHINE;
+    case hkey_users: return HKEY_USERS;
+    case hkey_current_config: return HKEY_CURRENT_CONFIG;
+    default: return 0;
+  }
+}
+
+astring registry_configurator::fix_section(const astring &section)
+{
+  astring to_return = section;
+  for (int i = 0; i < to_return.length(); i++) {
+    if (to_return[i] == '/')
+      to_return[i] = '\\';
+  }
+  return to_return;
+}
+
+bool registry_configurator::put(const astring &section_in, const astring &entry,
+    const astring &to_store)
+{
+  FUNCDEF("put");
+  astring section = fix_section(section_in);
+  if (!to_store.length()) return delete_entry(section, entry);
+  else if (!section.length()) return false;
+
+#ifdef __WIN32__
+  HKEY key;
+  long ret = RegOpenKeyEx((HKEY)translate_hive(_hive),
+      to_unicode_temp(section), 0, KEY_WRITE, &key);
+  if (ret != ERROR_SUCCESS) {
+    LOG("failed to open the key, trying to create it.");
+    DWORD dispose;  // the disposition of the call (created or existing).
+    ret = RegCreateKeyEx((HKEY)translate_hive(_hive),
+        to_unicode_temp(section), 0, NIL, REG_OPTION_NON_VOLATILE,
+        KEY_ALL_ACCESS, NIL, &key, &dispose);
+    if (ret != ERROR_SUCCESS) {
+      LOG("failed to create the key!!");
+      return false;
+    }
+  }
+
+  bool to_return = true;
+  ret = RegSetValueEx(key, to_unicode_temp(entry), 0, REG_SZ,
+      (byte *)to_store.s(), to_store.length() + 1);
+  if (ret != ERROR_SUCCESS) {
+    LOG(astring("failed to write the entry!"));
+    to_return = false;
+  }
+
+  RegCloseKey(key);
+  return to_return;
+#else
+  return false;
+#endif
+}
+
+bool registry_configurator::get(const astring &section_in, const astring &entry,
+    astring &found)
+{
+  FUNCDEF("get");
+  found = "";
+  if (!section_in) return false;
+  if (!entry) {}  // not a problem.
+  astring section = fix_section(section_in);
+#ifdef __WIN32__
+  HKEY key;
+  long ret = RegOpenKeyEx((HKEY)translate_hive(_hive),
+      to_unicode_temp(section), 0, KEY_QUERY_VALUE, &key);
+  if (ret != ERROR_SUCCESS) {
+    LOG("failed to open the key!");
+    return false;
+  }
+
+  DWORD type_seen;
+  byte *data_seen = new byte[MAXIMUM_ENTRY_SIZE];
+  DWORD length = MAXIMUM_ENTRY_SIZE - 1;
+  ret = RegQueryValueEx(key, to_unicode_temp(entry), 0, &type_seen, data_seen,
+      &length);
+  if (ret != ERROR_SUCCESS) {
+    LOG(astring("failed to read the entry!"));
+    return false;
+  }
+
+  if (type_seen != REG_SZ) {
+    LOG(astring("entry found was not of string type!"));
+    RegCloseKey(key);
+    return false;
+  }
+
+  data_seen[MAXIMUM_ENTRY_SIZE - 1] = '\0';
+    // force last character to be null if data happened to be too big.
+  found = astring((char *)data_seen);
+
+  delete [] data_seen;
+
+  RegCloseKey(key);
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool registry_configurator::get_section(const astring &section_in,
+    string_table &info)
+{
+  FUNCDEF("get_section");
+  info.reset();
+  if (!section_in.length()) return false;
+  astring section = fix_section(section_in);
+#ifdef __WIN32__
+  HKEY key;
+  long ret = RegOpenKeyEx((HKEY)translate_hive(_hive),
+      to_unicode_temp(section), 0, KEY_QUERY_VALUE, &key);
+  if (ret != ERROR_SUCCESS) {
+    LOG("failed to open the key!");
+    return false;
+  }
+
+  DWORD type_seen;
+  byte *data_seen = new byte[MAXIMUM_ENTRY_SIZE];
+  flexichar *name_seen = new flexichar[MAXIMUM_NAME_SIZE];
+  DWORD name_length;
+  for (DWORD index = 0; true; index++) {
+    DWORD length = MAXIMUM_ENTRY_SIZE - 1;
+    name_length = MAXIMUM_NAME_SIZE - 1;
+    LONG ret = RegEnumValue(key, index, name_seen, &name_length, 0,
+        &type_seen, data_seen, &length);
+    if (ret != ERROR_SUCCESS) break;  // no entry at that index.
+    if (type_seen == REG_SZ) {
+      // found an entry successfully and it's the right type.
+      astring name = from_unicode_temp(name_seen);
+      astring content = from_unicode_temp((flexichar *)data_seen);
+      info.add(name, content);
+    }
+  }
+
+  delete [] data_seen;
+  delete [] name_seen;
+
+  RegCloseKey(key);
+
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool registry_configurator::section_exists(const astring &section_in)
+{
+  FUNCDEF("section_exists");
+  if (!section_in.length()) return false;
+  astring section = fix_section(section_in);
+#ifdef __WIN32__
+  HKEY key;
+  long ret = RegOpenKeyEx((HKEY)translate_hive(_hive),
+      to_unicode_temp(section), 0, KEY_QUERY_VALUE, &key);
+  if (ret != ERROR_SUCCESS) {
+    LOG("failed to open the key!");
+    return false;
+  }
+  RegCloseKey(key);
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool registry_configurator::delete_section(const astring &section_in)
+{
+  FUNCDEF("delete_section");
+  if (!section_in.length()) return false;
+  astring section = fix_section(section_in);
+//if the key doesn't exist, should that be a failure?
+#ifdef __WIN32__
+  long ret = SHDeleteKey((HKEY)translate_hive(_hive),
+      to_unicode_temp(section));
+  if (ret != ERROR_SUCCESS) {
+    LOG("failed to delete the key!");
+    return false;
+  }
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool registry_configurator::delete_entry(const astring &section_in,
+    const astring &entry)
+{
+  FUNCDEF("delete_entry");
+  if (!section_in.length()) return false;
+  astring section = fix_section(section_in);
+  if (!entry) {}  // no problem.
+
+#ifdef __WIN32__
+  HKEY key;
+  long ret = RegOpenKeyEx((HKEY)translate_hive(_hive),
+      to_unicode_temp(section), 0, KEY_SET_VALUE, &key);
+  if (ret != ERROR_SUCCESS) {
+    LOG("failed to open the key!");
+    return false;
+  }
+
+  bool to_return = true;
+  ret = RegDeleteValue(key, to_unicode_temp(entry));
+  if (ret != ERROR_SUCCESS) {
+    LOG(astring("failed to delete the entry!"));
+    to_return = false;
+  }
+
+  RegCloseKey(key);
+  return to_return;
+#else
+  return false;
+#endif
+}
+
+bool registry_configurator::put_section(const astring &section_in,
+    const string_table &info)
+{
+  if (!section_in) return false;
+  astring section = fix_section(section_in);
+  bool failures = false;
+  for (int i = 0; i < info.symbols(); i++) {
+    bool worked = put(section, info.name(i), info[i]);
+    if (!worked) failures = true;
+  }
+  return !failures;
+}
+
+} // namespace
+
diff --git a/nucleus/library/application/registry_config.h b/nucleus/library/application/registry_config.h
new file mode 100644 (file)
index 0000000..f68cc86
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef REGISTRY_CONFIGURATOR_CLASS
+#define REGISTRY_CONFIGURATOR_CLASS
+
+/*
+*  Name   : registry_configurator                                             *
+*  Author : Chris Koeritz                                                     *
+**
+* Copyright (c) 2004-$now By Author.  This program is free software; you can  *
+* redistribute it and/or modify it under the terms of the GNU General Public  *
+* License as published by the Free Software Foundation; either version 2 of   *
+* the License or (at your option) any later version.  This is online at:      *
+*     http://www.fsf.org/copyleft/gpl.html                                    *
+* Please send any updates to: fred@gruntose.com                               *
+*/
+
+#include <basis/contracts.h>
+#include <configuration/configurator.h>
+#include <filesystem/byte_filer.h>
+#include <filesystem/filename.h>
+
+namespace configuration {
+
+//! Supports the configurator class interface on the windows registry.
+
+class registry_configurator : public configurator
+{
+public:
+  //! the hives are major partitions of the registry.
+  enum registry_hives {
+    hkey_classes_root,
+    hkey_current_user,
+    hkey_local_machine,
+    hkey_users,
+    hkey_current_config,
+    // abbreviations for the above sections...
+    HKCR = hkey_classes_root,
+    HKCU = hkey_current_user,
+    HKLM = hkey_local_machine,
+    HKU = hkey_users,
+    HKCC = hkey_current_config
+  };
+
+  registry_configurator(registry_hives hive, treatment_of_defaults behavior);
+    //!< creates a registry_configurator that stores entries into the "hive".
+    /*!< applies the "behavior" to items that are not found. */
+
+  virtual ~registry_configurator();
+
+  DEFINE_CLASS_NAME("registry_configurator");
+
+  virtual bool get(const basis::astring &section, const basis::astring &entry,
+          basis::astring &found);
+    //!< implements the configurator retrieval function.
+    /*!< note that for registry based retrieval, an empty "entry" is allowed,
+    and that specifies the default item in the "section". */
+
+  virtual bool section_exists(const basis::astring &section);
+    //!< returns true if the "section" was found in the file.
+
+  virtual bool put(const basis::astring &section, const basis::astring &entry,
+          const basis::astring &to_store);
+    //!< implements the configurator storage function.
+    /*!< put interprets an empty string for "entry" as pointing at the
+    default item in the "section". */
+
+  virtual bool delete_section(const basis::astring &section);
+    //!< removes the entire "section" specified.
+
+  virtual bool delete_entry(const basis::astring &section, const basis::astring &entry);
+    //!< removes the entry specified by the "section" and "entry" name.
+
+  virtual bool get_section(const basis::astring &section, structures::string_table &info);
+    //!< reads the entire "section" into a table called "info".
+    /*!< on win-9x, this will fail if the section's data exceeds 32K. */
+
+  virtual bool put_section(const basis::astring &section, const structures::string_table &info);
+    //!< writes a table called "info" into the "section" in the INI file.
+    /*!< any existing data for that section is wiped out.  on win-9x, this will
+    fail if the section's data exceeds 32K. */
+
+  void *translate_hive(registry_hives hive);
+    //!< translates from our enum to the windows specific type for hives.
+
+  basis::astring fix_section(const basis::astring &section);
+    //!< repairs malformed section names.
+    /*!< translates a section name that might use forward slashes into the
+    form required for windows that uses backslashes. */
+
+private:
+  registry_hives _hive;  //!< which hive our entries are stored in.
+
+  // not to be called.
+  registry_configurator(const registry_configurator &);
+  registry_configurator &operator =(const registry_configurator &);
+
+  static const basis::astring &reg_str_fake_default();
+};
+
+}
+
+#endif
+