Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New 'listWindowsRegistry' OS API method for enumerating content of single registry subkey #1345

Merged
merged 1 commit into from
Oct 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions src/host/os_getWindowsRegistry.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ typedef struct RegKeyInfo
char * value;
} RegKeyInfo;

static HKEY get_key(const char **path)
HKEY getRegistryKey(const char **path)
{
if (_strnicmp(*path, "HKCU:", 5) == 0) {
*path += 5;
Expand All @@ -42,7 +42,7 @@ static HKEY get_key(const char **path)
return NULL;
}

static HKEY get_subkey(HKEY key, const char **path)
static HKEY getSubkey(HKEY key, const char **path)
{
HKEY subkey;
size_t length;
Expand Down Expand Up @@ -84,7 +84,7 @@ static HKEY get_subkey(HKEY key, const char **path)
return subkey;
}

static char * get_value(HKEY key, const char * name)
static char * getValue(HKEY key, const char * name)
{
DWORD length;
char * value;
Expand All @@ -111,14 +111,14 @@ static char * get_value(HKEY key, const char * name)
return value;
}

static void fetch_keyinfo(struct RegKeyInfo *info, const char *path)
static void fetchKeyInfo(struct RegKeyInfo *info, const char *path)
{
info->key = get_key(&path);
info->subkey = get_subkey(info->key, &path);
info->value = get_value(info->subkey, path);
info->key = getRegistryKey(&path);
info->subkey = getSubkey(info->key, &path);
info->value = getValue(info->subkey, path);
}

static void release_keyinfo(struct RegKeyInfo *info)
static void releaseKeyInfo(struct RegKeyInfo *info)
{
free(info->value);
RegCloseKey(info->subkey);
Expand All @@ -127,9 +127,9 @@ static void release_keyinfo(struct RegKeyInfo *info)
int os_getWindowsRegistry(lua_State *L)
{
RegKeyInfo info;
fetch_keyinfo(&info, luaL_checkstring(L, 1));
fetchKeyInfo(&info, luaL_checkstring(L, 1));
lua_pushstring(L, info.value);
release_keyinfo(&info);
releaseKeyInfo(&info);
return 1;
}

Expand Down
252 changes: 252 additions & 0 deletions src/host/os_listWindowsRegistry.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
/**
* \file os_reg.c
* \brief Returns true if the given file exists on the file system.
* \author Copyright (c) 2002-2016 Jason Perkins and the Premake project
*/

#include "premake.h"

#if PLATFORM_WINDOWS

typedef struct RegNodeInfo
{
const char * name;
const char * value;
DWORD valueSize;
DWORD type;
} RegNodeInfo;

typedef void (*ListCallback)(const RegNodeInfo * info, void * user);
extern HKEY getRegistryKey(const char** path);

static const char* getTypeString(DWORD type)
{
switch (type)
{
case REG_NONE: return "REG_NONE";
case REG_SZ: return "REG_SZ";
case REG_EXPAND_SZ: return "REG_EXPAND_SZ";
case REG_BINARY: return "REG_BINARY";
case REG_DWORD: return "REG_DWORD";
case REG_DWORD_BIG_ENDIAN: return "REG_DWORD_BIG_ENDIAN";
case REG_LINK: return "REG_LINK";
case REG_MULTI_SZ: return "REG_MULTI_SZ";
case REG_RESOURCE_LIST: return "REG_RESOURCE_LIST";
case REG_FULL_RESOURCE_DESCRIPTOR: return "REG_FULL_RESOURCE_DESCRIPTOR";
case REG_RESOURCE_REQUIREMENTS_LIST: return "REG_RESOURCE_REQUIREMENTS_LIST";
case REG_QWORD: return "REG_QWORD";
default: return NULL;
}
}

static HKEY openKey(const char *path)
{
HKEY key, subkey;

// check string
if (path == NULL)
return NULL;

// get HKEY
key = getRegistryKey(&path);
if (key == NULL)
return NULL;

// skip the initial path separator
if (path[0] == '\\')
path++;

// open the key for reading
if (RegOpenKeyExA(key, path, 0, KEY_READ, &subkey) != ERROR_SUCCESS)
subkey = NULL;

return subkey;
}

static int listNodes(HKEY key, ListCallback callback, void * user)
{
RegNodeInfo node;
DWORD maxSubkeyLength;
DWORD maxValueLength;
DWORD maxNameLength;
DWORD numSubkeys;
DWORD numValues;
DWORD length;
DWORD index;
char* name;
char* value;
int ok;

if (key == NULL || callback == NULL)
return 0;

// Initialize node structure
node.value = NULL;
node.valueSize = 0;
node.type = REG_NONE;

// Fetch info about key content
if (RegQueryInfoKeyA(key, NULL, NULL, NULL, &numSubkeys, &maxSubkeyLength, NULL, &numValues, &maxNameLength, &maxValueLength, NULL, NULL) != ERROR_SUCCESS)
return 0;

// Allocate name and value buffers
if (maxSubkeyLength > maxNameLength)
maxNameLength = maxSubkeyLength;

maxNameLength++;
maxValueLength++;
name = (char*)malloc((size_t)maxNameLength);
value = (char*)malloc((size_t)maxValueLength + 1);

// Iterate over subkeys
ok = 1;
node.name = name;
for (index = 0; index < numSubkeys; index++) {
length = maxNameLength;
if (RegEnumKeyExA(key, index, name, &length, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
ok = 0;
break;
}
callback(&node, user);
}

// Iterate over values
if (ok) {
node.value = value;
for (index = 0; index < numValues; index++) {
length = maxNameLength;
node.valueSize = maxValueLength;
if (RegEnumValueA(key, index, name, &length, NULL, &node.type, (LPBYTE)value, &node.valueSize) != ERROR_SUCCESS) {
ok = 0;
break;
}

// Ensure proper termination of strings (two terminators for the REG_MULTI_SZ)
value[node.valueSize] = '\0';
value[node.valueSize + 1] = '\0';
callback(&node, user);
}
}

// Free buffers
free(name);
free(value);

return ok;
}

static void listCallback(const RegNodeInfo* info, void* user)
{
lua_State* L = (lua_State*)user;
const char* typeString;

// Insert key into the result table (keys are represented as empty tables)
if (info->value == NULL) {
lua_createtable(L, 0, 0);
lua_setfield(L, -2, info->name);
return;
}

// Values are represented as tables containing "type" and "value" records
typeString = getTypeString(info->type);
lua_createtable(L, 0, 2);
lua_pushstring(L, typeString ? typeString : "Unknown");
lua_setfield(L, -2, "type");

switch (info->type)
{
// Binary encoded values -> size defined string
case REG_NONE:
case REG_BINARY:
case REG_RESOURCE_LIST:
case REG_FULL_RESOURCE_DESCRIPTOR:
case REG_RESOURCE_REQUIREMENTS_LIST: {
lua_pushlstring(L, info->value, info->valueSize);
break;
}

// String encoded values -> zero terminated string
case REG_SZ:
case REG_EXPAND_SZ:
case REG_LINK: {
lua_pushstring(L, info->value);
break;
}

// Numbers
case REG_DWORD: {
lua_pushinteger(L, *(DWORD32*)info->value);
break;
}

case REG_DWORD_BIG_ENDIAN: {
lua_pushinteger(L, (info->value[3] << 0) | (info->value[2] << 8) | (info->value[1] << 16) | (info->value[0] << 24));
break;
}

case REG_QWORD: {
lua_pushinteger(L, *(DWORD64*)info->value);
break;
}

// Multiple strings
case REG_MULTI_SZ: {
DWORD i, j, k;

lua_newtable(L);
for (i = j = 0, k = 1; i < info->valueSize; i++)
{
if (info->value[i] != 0)
continue;

if (i == j)
break;

lua_pushlstring(L, &info->value[j], i - j);
lua_rawseti(L, -2, k);
j = i + 1;
k++;
}
break;
}

// Unknown field -> nil
default: {
lua_pushnil(L);
break;
}
}
lua_setfield(L, -2, "value");

// Complete the value subtable
lua_setfield(L, -2, info->name);
}

int os_listWindowsRegistry(lua_State* L)
starkos marked this conversation as resolved.
Show resolved Hide resolved
{
HKEY key = openKey(luaL_checkstring(L, 1));
if (key == NULL) {
lua_pushnil(L);
return 1;
}

lua_newtable(L);
if (!listNodes(key, listCallback, (void *)L)) {
// Discard table in case of fault and push nil instead
lua_pop(L, 1);
lua_pushnil(L);
}

RegCloseKey(key);
return 1;
}

#else

int os_listWindowsRegistry(lua_State* L)
{
lua_pushnil(L);
return 1;
}

#endif
1 change: 1 addition & 0 deletions src/host/premake.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ static const luaL_Reg os_functions[] = {
{ "getcwd", os_getcwd },
{ "getpass", os_getpass },
{ "getWindowsRegistry", os_getWindowsRegistry },
{ "listWindowsRegistry", os_listWindowsRegistry },
{ "getversion", os_getversion },
{ "host", os_host },
{ "isfile", os_isfile },
Expand Down
1 change: 1 addition & 0 deletions src/host/premake.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ int os_copyfile(lua_State* L);
int os_getcwd(lua_State* L);
int os_getpass(lua_State* L);
int os_getWindowsRegistry(lua_State* L);
int os_listWindowsRegistry(lua_State* L);
int os_getversion(lua_State* L);
int os_host(lua_State* L);
int os_is64bit(lua_State* L);
Expand Down
Loading