From 6570f686dc9b8074664387c45d81127141df74dc Mon Sep 17 00:00:00 2001
From: Andy Cedilnik <andy.cedilnik@kitware.com>
Date: Fri, 16 Sep 2005 13:38:25 -0400
Subject: [PATCH] ENH: Modify API a little bit to allow arbitrary length
 values. Encode certain characters. Rename UNIX registry to FILE registry.
 More testing

---
 Registry.cxx     | 181 +++++++++++++++++++++++++++++++++++------------
 Registry.hxx.in  |   6 +-
 testRegistry.cxx |  35 +++++----
 3 files changed, 161 insertions(+), 61 deletions(-)

diff --git a/Registry.cxx b/Registry.cxx
index 9734f88..180762d 100644
--- a/Registry.cxx
+++ b/Registry.cxx
@@ -38,7 +38,7 @@ public:
   virtual ~RegistryHelper();
 
   // Read a value from the registry.
-  virtual bool ReadValue(const char *key, char *value);
+  virtual bool ReadValue(const char *key, const char **value);
 
   // Delete a key from the registry.
   virtual bool DeleteKey(const char *key);
@@ -68,6 +68,10 @@ public:
   void SetGlobalScope(bool b);
   bool GetGlobalScope();
 
+  kwsys_stl::string EncodeKey(const char* str);
+  kwsys_stl::string EncodeValue(const char* str);
+  kwsys_stl::string DecodeValue(const char* str);
+
 protected:
   bool m_Changed;
   kwsys_stl::string m_TopLevel;  
@@ -79,13 +83,14 @@ protected:
   // Strip trailing and ending spaces.
   char *Strip(char *str);
   void SetSubKey(const char* sk);
-  char *CreateKey(const char *key);
+  kwsys_stl::string CreateKey(const char *key);
 
   typedef kwsys_stl::map<kwsys_stl::string, kwsys_stl::string> StringToStringMap;
   StringToStringMap EntriesMap;
   kwsys_stl::string m_SubKey;
   bool m_Empty;
   bool m_SubKeySpecified;
+  kwsys_stl::string m_HomeDirectory;
 
   Registry::RegistryType m_RegistryType;
 };
@@ -191,7 +196,7 @@ bool Registry::Close()
 //----------------------------------------------------------------------------
 bool Registry::ReadValue(const char *subkey, 
   const char *key, 
-  char *value)
+  const char **value)
 {  
   *value = 0;
   bool res = true;
@@ -388,16 +393,21 @@ bool RegistryHelper::Open(const char *toplevel, const char *subkey,
     return (res != 0);
     }
 #endif
-  if ( m_RegistryType == Registry::UNIX_REGISTRY )
+  if ( m_RegistryType == Registry::FILE_REGISTRY )
     {
     bool res = false;
     int cc;
     kwsys_ios::ostringstream str;
-    if ( !getenv("HOME") )
+    const char* homeDirectory;
+    if ( (homeDirectory = getenv("HOME")) == 0 )
       {
-      return false; 
+      if ( (homeDirectory = getenv("USERPROFILE")) == 0 )
+        {
+        return false; 
+        }
       }
-    str << getenv("HOME") << "/." << toplevel << "rc";
+    m_HomeDirectory = homeDirectory;
+    str << m_HomeDirectory << "/." << toplevel << "rc";
     if ( readonly == Registry::READWRITE )
       {
       kwsys_ios::ofstream ofs( str.str().c_str(), kwsys_ios::ios::out|kwsys_ios::ios::app );
@@ -450,7 +460,7 @@ bool RegistryHelper::Open(const char *toplevel, const char *subkey,
           char *value = line + cc + 1;
           char *nkey = this->Strip(key);
           char *nvalue = this->Strip(value);
-          this->EntriesMap[nkey] = nvalue;
+          this->EntriesMap[nkey] = this->DecodeValue(nvalue);
           m_Empty = 0;
           delete [] key;
           found = 1;      
@@ -477,7 +487,7 @@ bool RegistryHelper::Close()
     return (res != 0);
     }
 #endif
-  if ( m_RegistryType == Registry::UNIX_REGISTRY )
+  if ( m_RegistryType == Registry::FILE_REGISTRY )
     {
     if ( !m_Changed )
       {
@@ -490,11 +500,7 @@ bool RegistryHelper::Close()
       }
 
     kwsys_ios::ostringstream str;
-    if ( !getenv("HOME") )
-      {
-      return false;
-      }
-    str << getenv("HOME") << "/." << this->GetTopLevel() << "rc";
+    str << m_HomeDirectory << "/." << this->GetTopLevel() << "rc";
     kwsys_ios::ofstream *ofs = new kwsys_ios::ofstream(str.str().c_str(), kwsys_ios::ios::out);
     if ( !ofs )
       {
@@ -507,7 +513,7 @@ bool RegistryHelper::Close()
       }
     *ofs << "# This file is automatically generated by the application" << kwsys_ios::endl
       << "# If you change any lines or add new lines, note that all" << kwsys_ios::endl
-      << "# coments and empty lines will be deleted. Every line has" << kwsys_ios::endl
+      << "# comments and empty lines will be deleted. Every line has" << kwsys_ios::endl
       << "# to be in format: " << kwsys_ios::endl
       << "# key = value" << kwsys_ios::endl
       << "#" << kwsys_ios::endl;
@@ -535,58 +541,76 @@ bool RegistryHelper::Close()
 }
 
 //----------------------------------------------------------------------------
-bool RegistryHelper::ReadValue(const char *skey, char *value)
+bool RegistryHelper::ReadValue(const char *skey, const char **value)
 
 {
 #ifdef _WIN32
   if ( m_RegistryType == Registry::WIN32_REGISTRY)
     {
+    kwsys_stl::string key = this->CreateKey( skey );
+    if ( key.empty() )
+      {
+      return false;
+      }
     int res = 1;
     DWORD dwType, dwSize;  
     dwType = REG_SZ;
     dwSize = Registry_BUFFER_SIZE;
+    char buffer[1024]; // Replace with RegQueryInfoKey
     res = ( RegQueryValueEx(this->HKey, skey, NULL, &dwType, 
-        (BYTE *)value, &dwSize) == ERROR_SUCCESS );
-    return (res != 0);
+        (BYTE *)buffer, &dwSize) == ERROR_SUCCESS );
+    if ( !res )
+      {
+      return false;
+      }
+    this->EntriesMap[key] = buffer;
+    RegistryHelper::StringToStringMap::iterator it
+      = this->EntriesMap.find(key);
+    *value = it->second.c_str();
+    return true;
     }
 #endif
-  if ( m_RegistryType == Registry::UNIX_REGISTRY )
+  if ( m_RegistryType == Registry::FILE_REGISTRY )
     {
     bool res = false;
-    char *key = this->CreateKey( skey );
-    if ( !key )
+    kwsys_stl::string key = this->CreateKey( skey );
+    if ( key.empty() )
       {
       return false;
       }
+
     RegistryHelper::StringToStringMap::iterator it
       = this->EntriesMap.find(key);
     if ( it != this->EntriesMap.end() )
       {
-      strcpy(value, it->second.c_str());
+      *value = it->second.c_str();
       res = true;
       }
-    delete [] key;
     return res;
     }
   return false;
 }
 
 //----------------------------------------------------------------------------
-bool RegistryHelper::DeleteKey(const char* key)
+bool RegistryHelper::DeleteKey(const char* skey)
 {
 #ifdef _WIN32
   if ( m_RegistryType == Registry::WIN32_REGISTRY)
     {
     int res = 1;
-    res = ( RegDeleteKey( this->HKey, key ) == ERROR_SUCCESS );
+    res = ( RegDeleteKey( this->HKey, skey ) == ERROR_SUCCESS );
     return (res != 0);
     }
 #endif
-  if ( m_RegistryType == Registry::UNIX_REGISTRY )
+  if ( m_RegistryType == Registry::FILE_REGISTRY )
     {
-    (void)key;
-    bool res = false;
-    return res;
+    kwsys_stl::string key = this->CreateKey( skey );
+    if ( key.empty() )
+      {
+      return false;
+      }
+    this->EntriesMap.erase(key);
+    return true;
     }
   return false;
 }
@@ -602,15 +626,14 @@ bool RegistryHelper::DeleteValue(const char *skey)
     return (res != 0);
     }
 #endif
-  if ( m_RegistryType == Registry::UNIX_REGISTRY )
+  if ( m_RegistryType == Registry::FILE_REGISTRY )
     {
-    char *key = this->CreateKey( skey );
-    if ( !key )
+    kwsys_stl::string key = this->CreateKey( skey );
+    if ( key.empty() )
       {
       return false;
       }
     this->EntriesMap.erase(key);
-    delete [] key;
     return true;
     }
   return false;
@@ -630,34 +653,32 @@ bool RegistryHelper::SetValue(const char *skey, const char *value)
     return (res != 0);
     }
 #endif
-  if ( m_RegistryType == Registry::UNIX_REGISTRY )
+  if ( m_RegistryType == Registry::FILE_REGISTRY )
     {
-    char *key = this->CreateKey( skey );
-    if ( !key )
+    kwsys_stl::string key = this->CreateKey( skey );
+    if ( key.empty() )
       {
       return 0;
       }
-    this->EntriesMap[key] = value;
-    delete [] key;
+    this->EntriesMap[key] = this->EncodeValue(value);
     return 1;
     }
   return false;
 }
 
 //----------------------------------------------------------------------------
-char *RegistryHelper::CreateKey( const char *key )
+kwsys_stl::string RegistryHelper::CreateKey( const char *key )
 {
-  char *newkey;
   if ( !m_SubKeySpecified || m_SubKey.empty() || !key )
     {
-    return 0;
+    return "";
     }
-  int len = strlen(this->m_SubKey.c_str()) + strlen(key) + 1;
-  newkey = new char[ len+1 ] ;
-  ::sprintf(newkey, "%s\\%s", this->m_SubKey.c_str(), key);
-  return newkey;
+  kwsys_ios::ostringstream ostr;
+  ostr << this->EncodeKey(this->m_SubKey.c_str()) << "\\" << this->EncodeKey(key);
+  return ostr.str();
 }
 
+//----------------------------------------------------------------------------
 void RegistryHelper::SetSubKey(const char* sk)
 {
   if ( !sk )
@@ -715,4 +736,74 @@ bool RegistryHelper::GetGlobalScope()
   return m_GlobalScope;
 }
 
+//----------------------------------------------------------------------------
+kwsys_stl::string RegistryHelper::EncodeKey(const char* str)
+{
+  kwsys_ios::ostringstream ostr;
+  while ( *str )
+    {
+    switch ( *str )
+      {
+    case '%': case '=': case '\n': case '\r': case '\t': case ' ':
+      char buffer[4];
+      sprintf(buffer, "%%%02X", *str);
+      ostr << buffer;
+      break;
+    default:
+      ostr << *str;
+      }
+    str ++;
+    }
+  return ostr.str();
+}
+
+//----------------------------------------------------------------------------
+kwsys_stl::string RegistryHelper::EncodeValue(const char* str)
+{
+  kwsys_ios::ostringstream ostr;
+  while ( *str )
+    {
+    switch ( *str )
+      {
+    case '%': case '=': case '\n': case '\r': case '\t': 
+      char buffer[4];
+      sprintf(buffer, "%%%02X", *str);
+      ostr << buffer;
+      break;
+    default:
+      ostr << *str;
+      }
+    str ++;
+    }
+  return ostr.str();
+}
+
+//----------------------------------------------------------------------------
+kwsys_stl::string RegistryHelper::DecodeValue(const char* str)
+{
+  kwsys_ios::ostringstream ostr;
+  while ( *str )
+    {
+    int val;
+    switch ( *str )
+      {
+    case '%':
+      if ( *(str+1) && *(str+2) && sscanf(str+1, "%x", &val) == 1 )
+        {
+        ostr << (char)val;
+        str += 2;
+        }
+      else
+        {
+        ostr << *str;
+        }
+      break;
+    default:
+      ostr << *str;
+      }
+    str ++;
+    }
+  return ostr.str();
+}
+
 } // namespace KWSYS_NAMESPACE
diff --git a/Registry.hxx.in b/Registry.hxx.in
index c6feaaf..980b61b 100644
--- a/Registry.hxx.in
+++ b/Registry.hxx.in
@@ -39,19 +39,19 @@ public:
 #ifdef _WIN32
     WIN32_REGISTRY,
 #endif
-    UNIX_REGISTRY
+    FILE_REGISTRY
     };
 
 #ifdef _WIN32
   Registry(RegistryType registryType = WIN32_REGISTRY);
 #else
-  Registry(RegistryType registryType = UNIX_REGISTRY);
+  Registry(RegistryType registryType = FILE_REGISTRY);
 #endif
 
   virtual ~Registry();
 
   //! Read a value from the registry.
-  bool ReadValue(const char *subkey, const char *key, char *value);
+  bool ReadValue(const char *subkey, const char *key, const char **value);
 
   //! Delete a key from the registry.
   bool DeleteKey(const char *subkey, const char *key);
diff --git a/testRegistry.cxx b/testRegistry.cxx
index 386b09b..f0d7e32 100644
--- a/testRegistry.cxx
+++ b/testRegistry.cxx
@@ -53,14 +53,14 @@ int main(int, char**)
   IFT(reg.SetValue("TestSubkey",  "TestKey3", "Test Value 3"), res);
   IFT(reg.SetValue("TestSubkey2", "TestKey4", "Test Value 4"), res);
 
-  char buffer[1024];
-  IFT(reg.ReadValue("TestSubkey",  "TestKey1", buffer), res);
+  const char *buffer;
+  IFT(reg.ReadValue("TestSubkey",  "TestKey1", &buffer), res);
   CHE(buffer, "Test Value 1", res);
-  IFT(reg.ReadValue("TestSubkey1", "TestKey2", buffer), res);
+  IFT(reg.ReadValue("TestSubkey1", "TestKey2", &buffer), res);
   CHE(buffer, "Test Value 2", res);
-  IFT(reg.ReadValue("TestSubkey",  "TestKey3", buffer), res);
+  IFT(reg.ReadValue("TestSubkey",  "TestKey3", &buffer), res);
   CHE(buffer, "Test Value 3", res);
-  IFT(reg.ReadValue("TestSubkey2", "TestKey4", buffer), res);
+  IFT(reg.ReadValue("TestSubkey2", "TestKey4", &buffer), res);
   CHE(buffer, "Test Value 4", res);
  
   IFT(reg.SetValue("TestSubkey",  "TestKey1", "New Test Value 1"), res);
@@ -68,23 +68,32 @@ int main(int, char**)
   IFT(reg.SetValue("TestSubkey",  "TestKey3", "New Test Value 3"), res);
   IFT(reg.SetValue("TestSubkey2", "TestKey4", "New Test Value 4"), res);
 
-  IFT(reg.ReadValue("TestSubkey",  "TestKey1", buffer), res);
+  IFT(reg.ReadValue("TestSubkey",  "TestKey1", &buffer), res);
   CHE(buffer, "New Test Value 1", res);
-  IFT(reg.ReadValue("TestSubkey1", "TestKey2", buffer), res);
+  IFT(reg.ReadValue("TestSubkey1", "TestKey2", &buffer), res);
   CHE(buffer, "New Test Value 2", res);
-  IFT(reg.ReadValue("TestSubkey",  "TestKey3", buffer), res);
+  IFT(reg.ReadValue("TestSubkey",  "TestKey3", &buffer), res);
   CHE(buffer, "New Test Value 3", res);
-  IFT(reg.ReadValue("TestSubkey2", "TestKey4", buffer), res);
+  IFT(reg.ReadValue("TestSubkey2", "TestKey4", &buffer), res);
   CHE(buffer, "New Test Value 4", res);
 
   IFT( reg.DeleteValue("TestSubkey",  "TestKey1"), res);
-  IFNT(reg.ReadValue(  "TestSubkey",  "TestKey1", buffer), res);
+  IFNT(reg.ReadValue(  "TestSubkey",  "TestKey1", &buffer), res);
   IFT( reg.DeleteValue("TestSubkey1", "TestKey2"), res);
-  IFNT(reg.ReadValue(  "TestSubkey1", "TestKey2", buffer), res);
+  IFNT(reg.ReadValue(  "TestSubkey1", "TestKey2", &buffer), res);
   IFT( reg.DeleteValue("TestSubkey",  "TestKey3"), res);
-  IFNT(reg.ReadValue(  "TestSubkey",  "TestKey3", buffer), res);
+  IFNT(reg.ReadValue(  "TestSubkey",  "TestKey3", &buffer), res);
   IFT( reg.DeleteValue("TestSubkey2", "TestKey4"), res);
-  IFNT(reg.ReadValue(  "TestSubkey2", "TestKey5", buffer), res);  
+  IFNT(reg.ReadValue(  "TestSubkey2", "TestKey5", &buffer), res);  
+
+  const char* longStringWithNewLines = "Value with embedded CR and LF characters CR='\015' LF='\012' CRLF='\015\012'";
+  IFT(reg.SetValue("TestSubkeyWithVeryLongInFactSoLongItsHardToImagineAnybodyWouldReallyDoItLongName",  "TestKey1", longStringWithNewLines), res);
+  IFT(reg.ReadValue("TestSubkeyWithVeryLongInFactSoLongItsHardToImagineAnybodyWouldReallyDoItLongName", "TestKey1", &buffer), res);
+  CHE(buffer, longStringWithNewLines, res);
+
+  IFT(reg.SetValue("TestSubkeyWith = EqualSignChar",  "TestKey = 1", "Some value"), res);
+  IFT(reg.ReadValue("TestSubkeyWith = EqualSignChar",  "TestKey = 1", &buffer), res);
+  CHE(buffer, "Some value", res);
 
   if ( res )
     {
-- 
GitLab