mirror of
https://github.com/apache/cloudstack.git
synced 2025-12-21 04:53:37 +01:00
315 lines
9.2 KiB
C++
315 lines
9.2 KiB
C++
// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
|
//
|
|
// This file is part of the VNC system.
|
|
//
|
|
// The VNC system 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 program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
// USA.
|
|
//
|
|
// If the source code for the VNC system is not available from the place
|
|
// whence you received this file, check http://www.uk.research.att.com/vnc or contact
|
|
// the authors on vnc@uk.research.att.com for information on obtaining it.
|
|
|
|
//
|
|
// MRU maintains a list of 'Most Recently Used' strings in the registry
|
|
//
|
|
|
|
#include "MRU.h"
|
|
|
|
static const TCHAR * INDEX_VAL_NAME = _T("index");
|
|
static const int MRU_MAX_ITEM_LENGTH = 256;
|
|
|
|
MRU::MRU(LPTSTR keyname, unsigned int maxnum)
|
|
{
|
|
DWORD dispos;
|
|
// Create the registry key. If unsuccessful all other methods will be no-ops.
|
|
if ( RegCreateKeyEx(HKEY_CURRENT_USER, keyname, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &m_hRegKey, &dispos) != ERROR_SUCCESS ) {
|
|
m_hRegKey = NULL;
|
|
}
|
|
m_index[0] = _T('\0');
|
|
m_maxnum = maxnum;
|
|
|
|
// Read the index entry
|
|
ReadIndex();
|
|
|
|
Tidy();
|
|
}
|
|
|
|
// Add the item specified at the front of the list
|
|
// Move it there if not already. If this makes the
|
|
// list longer than the maximum, older ones are deleted.
|
|
void MRU::AddItem(LPTSTR txt)
|
|
{
|
|
if (m_hRegKey == NULL) return;
|
|
|
|
// We don't add empty items.
|
|
if (_tcslen(txt) == 0) return;
|
|
|
|
// Read each value in index,
|
|
// noting which is the first unused id
|
|
TCHAR id = _T('\0');
|
|
TCHAR firstUnusedId = _T('A');
|
|
TCHAR itembuf[MRU_MAX_ITEM_LENGTH+1];
|
|
|
|
// Find first unused letter.
|
|
while (_tcschr(m_index, firstUnusedId) != NULL)
|
|
firstUnusedId++;
|
|
|
|
for (int i = 0; i < (int) _tcslen(m_index); i++) {
|
|
|
|
// Does this entry already contain the item we're adding
|
|
if (GetItem(i, itembuf, MRU_MAX_ITEM_LENGTH) != 0) {
|
|
|
|
// If a value matches the txt specified, move it to the front.
|
|
if (_tcscmp(itembuf, txt) == 0) {
|
|
id = m_index[i];
|
|
for (int j = i; j > 0; j--)
|
|
m_index[j] = m_index[j-1];
|
|
m_index[0] = id;
|
|
WriteIndex();
|
|
// That's all we need to do.
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we haven't found it, then we need to create a new entry and put it
|
|
// at the front of the index.
|
|
TCHAR valname[2];
|
|
valname[0] = firstUnusedId;
|
|
valname[1] = _T('\0');
|
|
RegSetValueEx(m_hRegKey, valname, NULL, REG_SZ,
|
|
(CONST BYTE *) txt, (_tcslen(txt) + 1) * sizeof(TCHAR));
|
|
|
|
// move all the current ids up one
|
|
for (int j = _tcslen(m_index); j >= 0; j--)
|
|
m_index[j] = m_index[j-1];
|
|
|
|
// and insert this one at the front
|
|
m_index[0] = firstUnusedId;
|
|
|
|
WriteIndex();
|
|
|
|
// Tidy, to truncate index if too long.
|
|
Tidy();
|
|
}
|
|
|
|
// How many items are on the list?
|
|
int MRU::NumItems()
|
|
{
|
|
if (m_hRegKey == NULL) return 0;
|
|
|
|
// return the length of index
|
|
return _tcslen(m_index);
|
|
}
|
|
|
|
// Return them in order. 0 is the newest.
|
|
// NumItems()-1 is the oldest.
|
|
// Returns length, or 0 if unsuccessful.
|
|
int MRU::GetItem(int index, LPTSTR buf, int buflen)
|
|
{
|
|
if (m_hRegKey == NULL) return 0;
|
|
if (index > NumItems() - 1) return 0;
|
|
|
|
TCHAR valname[2];
|
|
valname[0] = m_index[index];
|
|
valname[1] = _T('\0');
|
|
|
|
DWORD valtype;
|
|
DWORD dwbuflen = buflen;
|
|
if ( RegQueryValueEx( m_hRegKey, valname,
|
|
NULL, &valtype,
|
|
(LPBYTE) buf, &dwbuflen) != ERROR_SUCCESS)
|
|
return 0;
|
|
|
|
if (valtype != REG_SZ)
|
|
return 0; // should really be an assert
|
|
|
|
// May not be one byte per char, so we won't use dwbuflen
|
|
return _tcslen(buf);
|
|
}
|
|
|
|
// Remove the specified item if it exists.
|
|
// Only one copy will be removed, but nothing should occur more than once.
|
|
void MRU::RemoveItem(LPTSTR txt)
|
|
{
|
|
if (m_hRegKey == NULL) return;
|
|
|
|
TCHAR itembuf[MRU_MAX_ITEM_LENGTH+1];
|
|
|
|
for (int i = 0; i < NumItems(); i++) {
|
|
GetItem(i, itembuf, MRU_MAX_ITEM_LENGTH);
|
|
if (_tcscmp(itembuf, txt) == 0) {
|
|
RemoveItem(i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// Remove the item with the given index.
|
|
// If this is greater than NumItems()-1 it will be ignored.
|
|
void MRU::RemoveItem(int index)
|
|
{
|
|
if (m_hRegKey == NULL) return;
|
|
if (index > NumItems()-1) return;
|
|
|
|
TCHAR valname[2];
|
|
valname[0] = m_index[index];
|
|
valname[1] = _T('\0');
|
|
RegDeleteValue(m_hRegKey, valname);
|
|
|
|
for (unsigned int i = index; i <= _tcslen(m_index); i++)
|
|
m_index[i] = m_index[i+1];
|
|
|
|
WriteIndex();
|
|
}
|
|
|
|
// Load the index string from the registry
|
|
void MRU::ReadIndex()
|
|
{
|
|
if (m_hRegKey == NULL) return;
|
|
|
|
// read the index
|
|
DWORD valtype;
|
|
DWORD dwindexlen = sizeof(m_index);
|
|
if (RegQueryValueEx( m_hRegKey, INDEX_VAL_NAME,
|
|
NULL, &valtype, (LPBYTE) m_index, &dwindexlen) == ERROR_SUCCESS) {
|
|
} else {
|
|
// If index entry doesn't exist, create it
|
|
WriteIndex();
|
|
}
|
|
}
|
|
|
|
// Save the index string to the registry
|
|
void MRU::WriteIndex()
|
|
{
|
|
if (m_hRegKey == NULL) return;
|
|
|
|
RegSetValueEx(m_hRegKey, INDEX_VAL_NAME, NULL, REG_SZ,
|
|
(CONST BYTE *)m_index, (_tcslen(m_index) + 1) * sizeof(TCHAR));
|
|
}
|
|
|
|
// Tidy is called from time to time to preserve the integrity of the MRU
|
|
// list. It does three things:
|
|
// * Check the length and integrity of the index
|
|
// * Check that all other values in the registry key have an
|
|
// entry in the index and delete them from registry if not.
|
|
// * Check that all entries in the index have a corresponding
|
|
// value in the registry key and delete them from index if not.
|
|
|
|
void MRU::Tidy()
|
|
{
|
|
if (m_hRegKey == NULL) return;
|
|
int i;
|
|
|
|
// First some checks on the index itself.
|
|
// Truncate the index.
|
|
m_index[m_maxnum] = _T('\0');
|
|
// Check that no entry occurs more than once.
|
|
DWORD seenCharMask = 0;
|
|
for (i = 0; m_index[i] != _T('\0'); i++) {
|
|
DWORD mask = 1 << (m_index[i]-_T('A'));
|
|
if (seenCharMask & mask) {
|
|
// The current character has been used before.
|
|
// Delete it and move everything up.
|
|
for (int j = i; m_index[j] != _T('\0'); j++)
|
|
m_index[j] = m_index[j+1];
|
|
// Start next check at new current character
|
|
i--;
|
|
}
|
|
seenCharMask |= mask;
|
|
}
|
|
|
|
|
|
// Then check that all entries in registry have entry in index.
|
|
TCHAR valname[256];
|
|
DWORD valtype;
|
|
DWORD valnamelen;
|
|
DWORD numValues;
|
|
|
|
RegQueryInfoKey ( m_hRegKey,
|
|
NULL, NULL,
|
|
NULL, NULL,
|
|
NULL, NULL,
|
|
&numValues,
|
|
NULL, NULL,
|
|
NULL, NULL);
|
|
|
|
// We're being good here. The documentation says we shouldn't
|
|
// modify a key while enumerating its values. So this array will
|
|
// hold the names of keys which should be deleted
|
|
TCHAR **dudValues = new TCHAR* [numValues];
|
|
for (i = 0; i < (int) numValues; i++)
|
|
dudValues[i] = NULL;
|
|
unsigned int numDudValues = 0;
|
|
|
|
i = 0;
|
|
while (1) {
|
|
valnamelen = 255;
|
|
|
|
if (RegEnumValue(m_hRegKey, i,
|
|
valname, &valnamelen, NULL,
|
|
&valtype, NULL, NULL) == ERROR_NO_MORE_ITEMS)
|
|
break;
|
|
|
|
i++;
|
|
|
|
// ignore the index
|
|
if (_tcscmp(valname, INDEX_VAL_NAME) == 0)
|
|
continue;
|
|
// Record as invalid other non-single-char entries
|
|
if (_tcslen(valname) > 1) {
|
|
dudValues[numDudValues++] = _tcsdup(valname);
|
|
continue;
|
|
}
|
|
// Record as invalid if not in the index
|
|
if (_tcschr(m_index, valname[0]) == 0) {
|
|
dudValues[numDudValues++] = _tcsdup(valname);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Now delete the invalid ones
|
|
for (i = 0; i < (int) numDudValues; i++) {
|
|
RegDeleteValue(m_hRegKey, dudValues[i]);
|
|
free(dudValues[i]);
|
|
}
|
|
delete[] dudValues;
|
|
|
|
// Lastly, check that all entries in the index have a corresponding
|
|
// entry in registry and delete them if not.
|
|
for (i = _tcslen(m_index)-1; i >= 0; i--) {
|
|
TCHAR itembuf[MRU_MAX_ITEM_LENGTH+1];
|
|
if (GetItem(i, itembuf, MRU_MAX_ITEM_LENGTH) == 0) {
|
|
for (unsigned int j = i; j <= _tcslen(m_index)-1; j++)
|
|
m_index[j] = m_index[j+1];
|
|
}
|
|
}
|
|
|
|
// Save any changes to the index.
|
|
WriteIndex();
|
|
}
|
|
|
|
|
|
MRU::~MRU()
|
|
{
|
|
if (m_hRegKey != NULL) {
|
|
Tidy();
|
|
RegCloseKey(m_hRegKey);
|
|
m_hRegKey = NULL;
|
|
}
|
|
}
|