⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 appconf.cpp

📁 这是一款2d游戏引擎
💻 CPP
📖 第 1 页 / 共 4 页
字号:

    strncpy(szGroupName, pBegin, len);
    szGroupName[len - 1] = '\0';

    ConfigGroup *pGroup = m_pCurGroup->FindSubgroup(szGroupName);
    
    if ( pGroup == NULL ) {
      // not found: insert new group in the list
      m_pCurGroup = m_pCurGroup->AddSubgroup(szGroupName);
    }
    else {
      m_pCurGroup = pGroup;
    }

    if ( *pEnd == APPCONF_PATH_SEPARATOR ) {
      pBegin = ++pEnd;
    }
  }while ( *pEnd != '\0' );

  if ( szGroupName != NULL )
    delete [] szGroupName;
}

// set value of a key, creating it if doesn't yet exist
Bool FileConfig::writeEntry(const char *szKey, const char *szValue)
{
  ConfigEntry *pEntry = m_pCurGroup->FindEntry(szKey);
  if ( pEntry == NULL ) {
    pEntry = m_pCurGroup->AddEntry(szKey);
  }

  pEntry->SetValue(szValue);

  return TRUE;
}

// delete entry and the parent group if it's the last entry in this group
Bool FileConfig::deleteEntry(const char *szKey)
{
  Bool bDeleted = m_pCurGroup->DeleteEntry(szKey);

  DeleteIfEmpty();

  return bDeleted;
}

// ----------------------------------------------------------------------------
// functions which update data on disk (or wherever...)
// ----------------------------------------------------------------------------

Bool FileConfig::flush(Bool bCurrentOnly)
{
  ConfigGroup *pRootGroup = bCurrentOnly ? m_pCurGroup : m_pRootGroup;

  if ( m_pRootGroup->IsDirty() ) {
    std::fstream outStream(LocalConfigFile(), std::ios::out);

    Bool bOk = pRootGroup->flush(&outStream);
    
    // special case: [comment and blank] lines following the last entry
    // were not yet written to the file, do it now.
    if ( m_szComment != NULL ) {
      outStream << m_szComment;
    }
    
    outStream.sync();

    return bOk;
  }
  else
    return TRUE;
}

Bool FileConfig::flush(std::ostream *oStream, Bool bCurrentOnly)
{
  ConfigGroup *pRootGroup = bCurrentOnly ? m_pCurGroup : m_pRootGroup;

  if ( m_pRootGroup->IsDirty() ) {
    
    Bool bOk = pRootGroup->flush(oStream);
    
    // special case: [comment and blank] lines following the last entry
    // were not yet written to the file, do it now.
    if ( m_szComment != NULL ) {
      *oStream << m_szComment;
    }
    
    return bOk;
  }
  else
    return TRUE;
}

// ----------------------------------------------------------------------------
// Comments management
// ## another kludge: this function is always called, but does nothing when
//    parsing global file (we can't write these comments back anyhow)
// ----------------------------------------------------------------------------
void FileConfig::AppendCommentLine(const char *szComment)
{
  if ( !m_bParsingLocal )
    return;

  size_t len = Strlen(m_szComment) + strlen(szComment) + 1;
    
  char *szNewComment = new char[len + 1];
  if ( m_szComment == NULL ) {
    szNewComment[0] = '\0';
  }
  else {
    strcpy(szNewComment, m_szComment);
    delete [] m_szComment;
  }  
  strcat(szNewComment, szComment);
  strcat(szNewComment, "\n");
  
  m_szComment = szNewComment;
}

// ----------------------------------------------------------------------------
// Enumeration of entries/subgroups
// ----------------------------------------------------------------------------

BaseConfig::Enumerator *FileConfig::enumSubgroups() const
{
  size_t nGroups = 0;
  ConfigGroup *pGroup = m_pCurGroup->Subgroup();
  while ( pGroup != NULL ) {
    nGroups++;
    pGroup = pGroup->Next();
  }

  BaseConfig::Enumerator *pEnum = new Enumerator(nGroups, FALSE);

  pGroup = m_pCurGroup->Subgroup();
  for ( size_t n = 0; n < nGroups; n++ ) {
    pEnum->AddString(pGroup->Name());
    pGroup = pGroup->Next();
  }

  return pEnum;
}

BaseConfig::Enumerator *FileConfig::enumEntries() const
{
  size_t nEntries = 0;
  ConfigEntry *pEntry = m_pCurGroup->Entries();
  while ( pEntry != NULL ) {
    nEntries++;
    pEntry = pEntry->Next();
  }

  BaseConfig::Enumerator *pEnum = new Enumerator(nEntries, FALSE);

  pEntry = m_pCurGroup->Entries();
  for ( size_t n = 0; n < nEntries; n++ ) {
    pEnum->AddString(pEntry->Name());
    pEntry = pEntry->Next();
  }

  return pEnum;
}

// ============================================================================
// implementation of the class RegistryConfig
// ============================================================================
#ifdef  __WIN32__

// ----------------------------------------------------------------------------
// ctor & dtor
// ----------------------------------------------------------------------------

// ctor opens our root key under HKLM
RegistryConfig::RegistryConfig(const char *szRootKey)
{
  static const char szPrefix[] = "Software";

  char *szKey = new char[strlen(szPrefix) + Strlen(szRootKey) + 2];
  strcpy(szKey, szPrefix);
  strcat(szKey, "\\");
  strcat(szKey, szRootKey);

  // don't create if doesn't exist
  LONG lRc = RegOpenKey(HKEY_LOCAL_MACHINE, szKey, &m_hGlobalRootKey);
  m_bOk = lRc == ERROR_SUCCESS;
  if ( !m_bOk )
    m_hGlobalRootKey = NULL;

  m_hGlobalCurKey = m_hGlobalRootKey;

  // create if doesn't exist
  lRc = RegCreateKey(HKEY_CURRENT_USER, szKey, &m_hLocalRootKey);
  m_hLocalCurKey = m_hLocalRootKey;
  if ( !m_bOk )
    m_bOk = lRc;

  m_pLastRead = NULL;

  delete [] szKey;
}

// free resources
RegistryConfig::~RegistryConfig()
{
  if ( m_pLastRead != NULL )
    delete [] m_pLastRead;

  if ( m_hGlobalRootKey != NULL )
    RegCloseKey(m_hGlobalRootKey);
  if ( m_hLocalRootKey != NULL )
    RegCloseKey(m_hLocalRootKey);

  // don't close same key twice
  if ( m_hGlobalCurKey != NULL && m_hGlobalCurKey != m_hGlobalRootKey )
    RegCloseKey(m_hGlobalCurKey);
  if ( m_hLocalCurKey != NULL && m_hLocalCurKey != m_hLocalRootKey )
    RegCloseKey(m_hLocalCurKey);
}

// ----------------------------------------------------------------------------
// read/write entry - no buffering, data goes directly to the registry
// ----------------------------------------------------------------------------

// helper for readEntry which needs to read both the global and local ones
// ### MT unsafe because of m_pLastRead
const char *RegistryConfig::ReadValue(void *hKey, const char *szValue) const
{
  // get size of data first
  DWORD dwSize;
  LONG lRc = RegQueryValueEx(hKey, szValue, 0, NULL, NULL, &dwSize);

  if ( lRc != ERROR_SUCCESS )
    return NULL;

  char *szBuffer = new char[dwSize];
  DWORD dwType;
  lRc = RegQueryValueEx(hKey, szValue, 0, &dwType, 
                        (unsigned char *)szBuffer, &dwSize);

  if ( lRc != ERROR_SUCCESS ) {
    // it's not normal for it to fail now (i.e. after the first call was ok)
    LogWarning(_("can't query the value '%s' (%s)."), szValue, SysError());

    return NULL;
  }

  // always automatically expand strings of this type
  if ( dwType == REG_EXPAND_SZ ) {
    // first get length
    DWORD dwLen = ExpandEnvironmentStrings(szBuffer, NULL, 0);    

    // alloc memory and expand
    char *szBufferExp = new char[dwLen + 1];
    ExpandEnvironmentStrings(szBuffer, szBufferExp, dwLen + 1);

    // copy to the original buffer
    delete [] szBuffer;
    szBuffer = szBufferExp;
  }

  // free old pointer (last thing we returned from here)
  if ( m_pLastRead != NULL )
    delete [] m_pLastRead;

  // const_cast
  ((RegistryConfig *)this)->m_pLastRead = filterIn((const char *)szBuffer);
  delete [] szBuffer;

  return m_pLastRead;
}

// read value from the current key
// first try the user's setting, than the system.
const char *RegistryConfig::readEntry(const char *szKey, 
                                      const char *szDefault) const
{
  const char *pRetValue = ReadValue(m_hLocalCurKey, szKey);

  // if no local value exist and current path exists in global part, try it
  if ( pRetValue == NULL && m_hGlobalCurKey != NULL )
    pRetValue = ReadValue(m_hGlobalCurKey, szKey);

  if(pRetValue != NULL)
     return pRetValue;
  else
  {
     if(m_bRecordDefaults)
	writeEntry(szKey, szDefault);
     return szDefault;
  }
}

// write (or create) value under current key
// NB: only to user's part
Bool RegistryConfig::writeEntry(const char *szKey, const char *szValue)
{
  char *szFiltered = filterOut(szValue);

  long lRc = RegSetValueEx(m_hLocalCurKey, szKey, 0, REG_SZ, 
                           (unsigned char *)szFiltered, 
                           Strlen(szFiltered) + 1);

  delete [] szFiltered;

  return lRc == ERROR_SUCCESS;
}

// delete the key and the key which contains it if this is the last subkey
Bool RegistryConfig::deleteEntry(const char *szKey)
{
  Bool bDeleted = RegDeleteValue(m_hLocalCurKey, szKey) == ERROR_SUCCESS;
  if ( !bDeleted ) {
    // # don't output error message if the key is not found?
    LogWarning(_("can't delete entry '%s': %s"), szKey, SysError());
  }

  // even if there was an error before, still check if the key is not empty:
  // otherwise an attempt to delete a non existing entry would _create_ a
  // new subkey!
  while ( KeyIsEmpty(m_hLocalCurKey) ) {
    // delete this key
    const char *szPath = getCurrentPath();
    const char *szKeyName = strrchr(szPath, APPCONF_PATH_SEPARATOR);
    if ( szKeyName == NULL )
      szKeyName = szPath;
    else
      szKeyName++;  // to skip APPCONF_PATH_SEPARATOR

    // must copy it because the call to changeCurrentPath will change it!
    char *aszSubkey = new char[strlen(szKeyName) + 1];
    strcpy(aszSubkey, szKeyName);

    // don't delete root key
    if ( *szKeyName != '\0' ) {
      changeCurrentPath("..");
      if ( RegDeleteKey(m_hLocalCurKey, aszSubkey) != ERROR_SUCCESS )
        LogWarning(_("can't delete key '%s': %s"), aszSubkey, SysError());
    }

    delete [] aszSubkey;
  }

  return bDeleted;
}

// ----------------------------------------------------------------------------
// Enumeration of entries/subgroups (both system and user)
// ### this code is messy :-( The problem is that we try to enumerate both the
//     global and local keys at once, but we don't want keys common to both
//     branches appear twice, hence we check for each global key that it 
//     doesn't appear locally at the end (very inefficient too).
// ----------------------------------------------------------------------------

BaseConfig::Enumerator *RegistryConfig::enumSubgroups() const
{
  DWORD dwKeysLocal,   dwKeysGlobal,    // number of subkeys
        dwKeyLenLocal, dwKeyLenGlobal;  // length of the longest subkey

  long lRc = RegQueryInfoKey(m_hLocalCurKey, NULL, NULL, NULL, 
                             &dwKeysLocal, &dwKeyLenLocal, 
                             NULL, NULL, NULL, NULL, NULL, NULL);

  assert( lRc == ERROR_SUCCESS );  // it should never fail here

  if ( m_hGlobalCurKey == NULL ) {
    // key doesn't exist
    dwKeysGlobal = dwKeyLenGlobal = 0;
  }
  else {
    lRc = RegQueryInfoKey(m_hGlobalCurKey, NULL, NULL, NULL, &dwKeysGlobal, 
                          &dwKeyLenGlobal, NULL, NULL, NULL, NULL, NULL, NULL);

    assert( lRc == ERROR_SUCCESS );  // it should never fail here
  }

  DWORD dwKeys = dwKeysLocal + dwKeysGlobal;
  DWORD dwKeyLen = max(dwKeyLenLocal, dwKeyLenGlobal);

  BaseConfig::Enumerator *pEnum = new Enumerator((size_t)dwKeys, TRUE);

  char *szKey;
  HKEY hKey = m_hGlobalCurKey;
  for ( DWORD dwKey = 0; dwKeys > 0; dwKey++, dwKeys-- ) {
    if ( dwKeys == dwKeysLocal ) {
      // finished with global keys, now for local ones
      hKey = m_hLocalCurKey;
      dwKey = 0;
    }

    szKey = new char[dwKeyLen + 1];
    if ( RegEnumKey(hKey, dwKey, szKey, dwKeyLen + 1) != ERROR_SUCCESS ) {
      delete [] szKey;
      break;
    }

    pEnum->AddString(szKey);  // enumerator will delete it
  }

  pEnum->MakeUnique();

  return pEnum;
}

BaseConfig::Enumerator *RegistryConfig::enumEntries() const
{
  DWORD dwEntriesLocal, dwEntriesGlobal,    // number of values
        dwEntryLenLocal, dwEntryLenGlobal;  // length of the longest value name

  long lRc = RegQueryInfoKey(m_hLocalCurKey, NULL, NULL, NULL, 
                             NULL, NULL, NULL, 
                             &dwEntriesLocal, &dwEntryLenLocal, 
                             NULL, NULL, NULL);

  assert( lRc == ERROR_SUCCESS );  // it should never fail here

  if ( m_hGlobalCurKey == NULL ) {
    // key doesn't exist
    dwEntriesGlobal = dwEntryLenGlobal = 0;
  }
  else {
    lRc = RegQueryInfoKey(m_hGlobalCurKey, 
                          NULL, NULL, NULL, 
                          NULL, NULL, NULL, 
                          &dwEntriesGlobal, 
                          &dwEntryLenGlobal, 
                          NULL, NULL, NULL);

    assert( lRc == ERROR_SUCCESS );  // it should never fail here
  }

  DWORD dwEntries = dwEntriesLocal + dwEntriesGlobal;
  DWORD dwEntryLen = max(dwEntryLenLocal, dwEntryLenGlobal);

  BaseConfig::Enumerator *pEnum = new Enumerator((size_t)dwEntries, TRUE);

  char *szVal;
  DWORD dwLen;
  HKEY  hKey = m_hGlobalCurKey;
  for ( DWORD dwEntry = 0; dwEntries > 0; dwEntry++, dwEntries-- ) {
    if ( dwEntries == dwEntriesLocal ) {
      // finished with global keys, now for local ones
      hKey = m_hLocalCurKey;
      dwEntry = 0;
    }

    dwLen = dwEntryLen + 1;
    szVal = new char [dwLen];
    lRc = RegEnumValue(hKey, dwEntry, szVal, &dwLen, 0, NULL, NULL, NULL);
    if ( lRc != ERROR_SUCCESS ) {
      delete [] szVal;
      break;
    }

    pEnum->AddString(szVal);    // enumerator will delete it
  }

  pEnum->MakeUnique();

  return pEnum;
}

// ----------------------------------------------------------------------------
// change current key
// ----------------------------------------------------------------------------

// only in user's registry hive (not in global one)
void RegistryConfig::changeCurrentPath(const char *szPath)
{
  // normalize path
  BaseConfig::changeCurrentPath(szPath);
  szPath = getCurrentPath();

  // special case because RegCreateKey(hKey, "") fails!
  if ( *szPath == '\0' ) {
    if ( m_hLocalCurKey != m_hLocalRootKey ) {
      RegCloseKey(m_hLocalCurKey);
      m_hLocalCurKey = m_hLocalRootKey;
    }

    if ( m_hGlobalCurKey != m_hGlobalRootKey ) {
      RegCloseKey(m_hGlobalCurKey);
      m_hGlobalCurKey = m_hGlobalRootKey;
    }

    return;
  }

  char *szRegPath = new char[Strlen(szPath) + 1];
  strcpy(szRegPath, szPath);

  // replace all APPCONF_PATH_SEPARATORs with '\'
  char *pcSeparator = szRegPath;
  while ( pcSeparator != NULL ) {
    pcSeparator = strchr(pcSeparator, APPCONF_PATH_SEPARATOR);
    if ( pcSeparator != NULL )
      *pcSeparator = '\\';
  }

  HKEY hOldKey = m_hLocalCurKey;

  if ( RegCreateKey(m_hLocalRootKey, szRegPath, 
                    &m_hLocalCurKey) == ERROR_SUCCESS ) {
    // at any time, we keep open two keys
    // here we check that we don't close them
    if ( (m_hLocalCurKey != hOldKey) && (hOldKey != m_hLocalRootKey) )
      RegCloseKey(hOldKey);
  }
  else {
    LogWarning(_("can not open key '%s' (%s)."), szPath, SysError());
  }

  if ( m_hGlobalCurKey != 0 ) {
    hOldKey = m_hGlobalCurKey;
    if ( RegOpenKey(m_hGlobalRootKey, szRegPath, 
                    &m_hGlobalCurKey) == ERROR_SUCCESS ) {
      if ( (m_hGlobalCurKey != hOldKey) && (hOldKey != m_hGlobalRootKey) )
        RegCloseKey(hOldKey);
    }
    else {
      // no such key
      if ( m_hGlobalCurKey != m_hGlobalRootKey )
        RegCloseKey(m_hGlobalCurKey);
      m_hGlobalCurKey = NULL;
    }
  }

  delete [] szRegPath;
}

// ----------------------------------------------------------------------------
// helper function: return TRUE if the key has no subkeys/values
// ----------------------------------------------------------------------------
Bool RegistryConfig::KeyIsEmpty(void *hKey)
{
  DWORD dwKeys, dwValues;
  long lRc = RegQueryInfoKey(hKey, NULL, NULL, NULL, &dwKeys, NULL, NULL, 
                             &dwValues, NULL, NULL, NULL, NULL);

  return (lRc == ERROR_SUCCESS) && (dwValues == 0) && (dwKeys == 0);
}

#endif  // WIN32

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -