feat(registry): add basic registry implementation

This commit is contained in:
phaneron 2025-03-31 14:31:31 -04:00
parent 2ffa8217c0
commit f8a7ac7001
20 changed files with 1318 additions and 73 deletions

View file

@ -0,0 +1,27 @@
#ifndef STORM_REGISTRY_REGISTRY_HPP
#define STORM_REGISTRY_REGISTRY_HPP
#include <cstdint>
#define STORM_REGISTRY_MAX_PATH 260
#define STORM_REGISTRY_MAX_VALUE 16384
#define STORM_REGISTRY_BATTLENET 0x02
#define STORM_REGISTRY_CURRENT_USER_ONLY 0x04
#define STORM_REGISTRY_FLUSH_KEY 0x08
#define STORM_REGISTRY_NO_BASE_KEY 0x10
#define STORM_REGISTRY_TYPE_STRING 1
#define STORM_REGISTRY_TYPE_DWORD 4
int32_t SRegLoadString(const char* keyname, const char* valuename, uint32_t flags, char* buffer, uint32_t buffersize);
int32_t SRegLoadValue(const char* keyname, const char* valuename, uint32_t flags, uint32_t* value);
int32_t SRegSaveString(const char* keyname, const char* valuename, uint32_t flags, const char* string);
int32_t SRegSaveValue(const char* keyname, const char* valuename, uint32_t flags, uint32_t value);
void SRegDestroy();
#endif

View file

@ -0,0 +1,373 @@
#include "storm/registry/Registry.hpp"
#include "bc/file/Close.hpp"
#include "bc/file/Defines.hpp"
#include "bc/file/GetFileInfo.hpp"
#include "bc/file/GetPos.hpp"
#include "bc/file/Types.hpp"
#include "bc/memory/Storm.hpp"
#include "storm/String.hpp"
#include "storm/Error.hpp"
#include "storm/List.hpp"
#include "bc/File.hpp"
#include "bc/Memory.hpp"
#include "storm/Thread.hpp"
#include <climits>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>
struct RegistryEntry : public TSLinkedNode<RegistryEntry> {
char* name = nullptr;
char* value = nullptr;
bool ParseLine(const char* line) {
char buffer[STORM_MAX_PATH];
auto b = buffer;
auto end = buffer + sizeof(buffer);
while (b < end && *line && *line != '=') {
*b++ = *line++;
}
if (*line++ != '=') {
return false;
}
if (b >= end) {
return false;
}
*b = '\0';
this->name = SStrDupA(buffer, __FILE__, __LINE__);
b = buffer;
while (b < end && *line) {
auto c = *line++;
if (c == '\\') {
if (*line == 'n') {
*b++ = '\n';
} else if (*line == '\\') {
*b++ = '\\';
} else {
*b++ = *line;
}
line++;
} else {
*b++ = c;
}
}
if (b >= end) {
return false;
}
*b = '\0';
this->value = SStrDupA(buffer, __FILE__, __LINE__);
return true;
}
~RegistryEntry() {
if (this->name) {
SMemFree(this->name, __FILE__, __LINE__, 0x0);
}
if (this->value) {
SMemFree(this->value, __FILE__, __LINE__, 0x0);
}
}
};
static int32_t s_initregistry = 0;
static STORM_LIST(RegistryEntry) s_registry;
static SCritSect s_lockregistry;
Blizzard::File::StreamRecord* RegistryFileCreate(int32_t mode) {
const char* basedir = getenv("XDG_CONFIG_HOME");
if (!basedir) {
basedir = getenv("HOME");
if (!basedir) {
basedir = ".";
}
}
char name[PATH_MAX];
*name = '\0';
SStrPack(name, basedir, sizeof(name));
SStrPack(name, "/.whoa", sizeof(name));
if (!Blizzard::File::IsDirectory(name)) {
if (!Blizzard::File::CreateDirectory(name, false)) {
return nullptr;
}
}
SStrPack(name, "/registry.txt", sizeof(name));
Blizzard::File::StreamRecord* file;
if (!Blizzard::File::Open(name, mode, file)) {
return nullptr;
}
return file;
}
int32_t RegistryFileWriteEntry(Blizzard::File::StreamRecord* file, RegistryEntry* entry) {
char valuebuffer[STORM_REGISTRY_MAX_VALUE];
auto source = reinterpret_cast<const char*>(entry->value);
auto dest = reinterpret_cast<char*>(valuebuffer);
auto sourceend = source + SStrLen(entry->value);
auto destend = dest + sizeof(valuebuffer);
while (dest < destend && source < sourceend) {
auto c = *source++;
if (c == '\n' && (dest+1) < destend) {
*dest++ = '\\';
*dest++ = 'n';
} else {
*dest++ = c;
}
}
valuebuffer[std::min(sizeof(valuebuffer)-1, static_cast<size_t>(dest-valuebuffer))] = '\0';
char linebuffer[STORM_REGISTRY_MAX_PATH + STORM_REGISTRY_MAX_VALUE + 2];
SStrPrintf(linebuffer, sizeof(linebuffer), "%s=%s\n", entry->name, valuebuffer);
auto length = SStrLen(linebuffer);
return Blizzard::File::Write(file, linebuffer, length);
}
int32_t RegistryFileReadLine(Blizzard::File::StreamRecord* file, char* buffer, int32_t buffersize) {
int64_t start;
if (!Blizzard::File::GetPos(file, start)) {
return false;
}
auto size = static_cast<int64_t>(Blizzard::File::GetFileInfo(file)->size);
if (start == size) {
return 0;
}
auto count = static_cast<int32_t>(std::min(static_cast<int64_t>(buffersize), size-start));
if (!Blizzard::File::Read(file, buffer, &count)) {
return 0;
}
auto p = buffer;
auto end = buffer + std::min(buffersize-1, count);
while (p < end && *p && *p != '\n') {
p++;
}
*p = '\0';
auto nextline = start + static_cast<int64_t>(p-buffer) + 1;
Blizzard::File::SetPos(file, nextline, BC_FILE_SEEK_START);
return 1;
}
void RegistryInit() {
s_initregistry = true;
auto file = RegistryFileCreate(Blizzard::File::Mode::mustexist|Blizzard::File::Mode::read);
if (!file) {
return;
}
char buffer[STORM_REGISTRY_MAX_PATH + STORM_REGISTRY_MAX_VALUE + 2];
while (RegistryFileReadLine(file, buffer, sizeof(buffer))) {
if (*buffer) {
auto entry = s_registry.NewNode(1, 0, 0);
if (!entry->ParseLine(buffer)) {
s_registry.DeleteNode(entry);
}
}
}
Blizzard::File::Close(file);
}
void RegistryFlush(bool remove) {
using Mode = Blizzard::File::Mode;
auto file = RegistryFileCreate(Mode::create|Mode::write|Mode::truncate);
if (!file) {
return;
}
auto entry = s_registry.Head();
while (entry) {
auto curentry = entry;
if (!RegistryFileWriteEntry(file, curentry)) {
break;
}
entry = entry->Next();
if (remove) {
s_registry.DeleteNode(curentry);
}
}
Blizzard::File::Close(file);
}
void RegistryShutdown() {
s_initregistry = false;
RegistryFlush(true);
}
void BuildFullKeyName(const char* keyname, const char* valuename, char* buffer, uint32_t buffersize) {
char key[STORM_MAX_PATH];
auto k = key;
auto keyend = (key + sizeof(key)) - 1;
while (k < keyend && *keyname) {
*k = *keyname == '\\' ? ':' : *keyname;
k++;
keyname++;
}
*k = '\0';
SStrPrintf(buffer, buffersize, "%s:%s", key, valuename);
}
int32_t InternalLoadEntry(const char* keyname, const char* valuename, uint32_t flags, char* buffer, uint32_t bytes, uint32_t* bytesread) {
s_lockregistry.Enter();
if (!s_initregistry) {
RegistryInit();
}
char fullkeyname[STORM_MAX_PATH];
*fullkeyname = '\0';
*bytesread = 0;
BuildFullKeyName(keyname, valuename, fullkeyname, STORM_MAX_PATH);
for (auto entry = s_registry.Head(); entry; entry = entry->Next()) {
if (!SStrCmpI(fullkeyname, entry->name, STORM_MAX_PATH)) {
auto valuelength = static_cast<uint32_t>(SStrLen(entry->value));
*bytesread = std::min(valuelength, bytes);
SStrCopy(buffer, entry->value, bytes);
s_lockregistry.Leave();
return 1;
}
}
s_lockregistry.Leave();
return 0;
}
int32_t InternalSaveEntry(const char* keyname, const char* valuename, uint32_t flags, const char* value) {
s_lockregistry.Enter();
if (!s_initregistry) {
RegistryInit();
}
char fullkeyname[STORM_MAX_PATH];
*fullkeyname = '\0';
BuildFullKeyName(keyname, valuename, fullkeyname, STORM_MAX_PATH);
auto entry = s_registry.Head();
while (entry) {
if (!SStrCmpI(fullkeyname, entry->name, STORM_MAX_PATH)) {
auto curentry = entry;
entry = entry->Next();
s_registry.DeleteNode(curentry);
} else {
entry = entry->Next();
}
}
entry = s_registry.NewNode(1, 0, 0);
if (!entry) {
return 0;
}
entry->name = SStrDupA(fullkeyname, __FILE__, __LINE__);
entry->value = SStrDupA(value, __FILE__, __LINE__);
if (flags & STORM_REGISTRY_FLUSH_KEY) {
RegistryFlush(false);
}
s_lockregistry.Leave();
return 1;
}
int32_t SRegLoadString(const char* keyname, const char* valuename, uint32_t flags, char* buffer, uint32_t buffersize) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(keyname);
STORM_VALIDATE(*keyname);
STORM_VALIDATE(valuename);
STORM_VALIDATE(*valuename);
STORM_VALIDATE(buffer);
STORM_VALIDATE_END;
uint32_t bytesread;
if (!InternalLoadEntry(keyname, valuename, flags, buffer, buffersize, &bytesread)) {
return 0;
}
buffer[std::min(buffersize - 1, bytesread)] = '\0';
return 1;
}
int32_t SRegLoadValue(const char* keyname, const char* valuename, uint32_t flags, uint32_t* value) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(keyname);
STORM_VALIDATE(*keyname);
STORM_VALIDATE(valuename);
STORM_VALIDATE(*valuename);
STORM_VALIDATE(value);
STORM_VALIDATE_END;
char valuestring[11];
uint32_t datatype;
uint32_t bytesread;
if (!InternalLoadEntry(keyname, valuename, flags, valuestring, sizeof(valuestring), &bytesread)) {
return 0;
}
*value = SStrToUnsigned(valuestring);
return 1;
}
int32_t SRegSaveString(const char* keyname, const char* valuename, uint32_t flags, const char* string) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(keyname);
STORM_VALIDATE(*keyname);
STORM_VALIDATE(valuename);
STORM_VALIDATE(*valuename);
STORM_VALIDATE(string);
STORM_VALIDATE_END;
if (!InternalSaveEntry(keyname, valuename, flags, string)) {
return 0;
}
return 1;
}
int32_t SRegSaveValue(const char* keyname, const char* valuename, uint32_t flags, uint32_t value) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(keyname);
STORM_VALIDATE(*keyname);
STORM_VALIDATE(valuename);
STORM_VALIDATE(*valuename);
STORM_VALIDATE_END;
char valuestring[11];
SStrPrintf(valuestring, sizeof(valuestring), "%u", value);
if (!InternalSaveEntry(keyname, valuename, flags, valuestring)) {
return 0;
}
return 1;
}
void SRegDestroy() {
s_lockregistry.Enter();
RegistryShutdown();
s_lockregistry.Leave();
}

View file

@ -0,0 +1,161 @@
#include "storm/Error.hpp"
#include "storm/String.hpp"
#include "storm/registry/Registry.hpp"
#include "storm/registry/mac/Static.hpp"
#include <cstring>
const char* NextComponent(const char* path, char* component, size_t size) {
auto sep = SStrChrR(path, '\\');
if (!sep) {
return path + SStrCopy(component, path, size);
} else {
SStrNCopy(component, path, sep - path, size);
return sep + 1;
}
}
bool GetDefaultsAndKeyPath(const char* key, const char* name, uint32_t flags, NSUserDefaults** defaults, char* path, size_t size) {
STORM_ASSERT(key);
STORM_ASSERT(*key);
id nextcomponent = NextComponent(key, path, size);
id prefix = @"com.blizzard";
if ((flags & STORM_REGISTRY_BATTLENET)) {
prefix = @"net.battle";
}
NSString* domain;
if (!size || *path) {
domain = [NSString stringWithFormat: @"%@.%s", prefix, path];
} else {
domain = prefix;
}
id sregstatic = SRegStatic::Get();
id hive = sregstatic->hives[domain];
*defaults = hive;
if (hive == nullptr) {
auto bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
if ([bundleIdentifier isEqualToString: domain]) {
hive = [NSUserDefaults standardUserDefaults];
} else {
hive = [[NSUserDefaults alloc] initWithSuiteName:domain];
}
*defaults = hive;
sregstatic->hives[domain] = hive;
}
int32_t length;
if (name && *name) {
if (key && *key) {
length = SStrPrintf(path, size, "%s/%s", key, name);
} else {
length = SStrCopy(path, name, size);
}
} else {
length = SStrCopy(path, key, size);
}
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(length < size);
STORM_VALIDATE_END;
for (id sep = path; ; *sep = '/') {
sep = SStrChr(sep, '\\');
if (!sep) {
break;
}
}
return false;
}
NSObject* GetObject(const char* keyname, const char* valuename, uint32_t flags) {
NSUserDefaults* defaults;
char path[STORM_MAX_PATH];
if (!GetDefaultsAndKeyPath(keyname, valuename, flags, &defaults, path, STORM_MAX_PATH)) {
return nil;
}
id string = [NSString stringWithUTF8String: path];
return [defaults objectForKey: string];
}
bool SetObject(const char* key, const char* name, uint32_t flags, NSObject* object) {
NSUserDefaults* defaults
char path[STORM_MAX_PATH];
if (!GetDefaultsAndKeyPath(keyname, valuename, flags, &defaults, path, STORM_MAX_PATH)) {
return false;
}
id string = [NSString stringWithUTF8String:path];
[defaults setObject:object forKey:string];
return true;
}
int32_t SRegLoadString(const char* keyname, const char* valuename, uint32_t flags, char* buffer, uint32_t buffersize) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(keyname);
STORM_VALIDATE(*keyname);
STORM_VALIDATE(valuename);
STORM_VALIDATE(*valuename);
STORM_VALIDATE(buffer);
STORM_VALIDATE_END;
@autoreleasepool {
id string = GetObject(keyname, valuename, flags);
if ([string isKindOfClass:[NSString class]) {
return [string getCString buffer:buffer maxLength:buffersize encoding:NSUTF8StringEncoding];
}
}
return 0;
}
int32_t SRegLoadValue(const char* keyname, const char* valuename, uint32_t flags, uint32_t* value) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(keyname);
STORM_VALIDATE(*keyname);
STORM_VALIDATE(valuename);
STORM_VALIDATE(*valuename);
STORM_VALIDATE(value);
STORM_VALIDATE_END;
@autoreleasepool {
id num = GetObject(keyname, valuename, flags);
if ([num isKindOfClass:[NSNumber class]) {
*value = [num unsignedIntValue];
return 1;
}
}
return 0;
}
int32_t SRegSaveString(const char* keyname, const char* valuename, uint32_t flags, const char* string) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(keyname);
STORM_VALIDATE(*keyname);
STORM_VALIDATE(valuename);
STORM_VALIDATE(*valuename);
STORM_VALIDATE(string);
STORM_VALIDATE_END;
@autoreleasepool {
return SetObject(keyname, valuename, flags, [NSString stringWithUTF8String:value]);
}
}
int32_t SRegSaveValue(const char* keyname, const char* valuename, uint32_t flags, uint32_t value) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(keyname);
STORM_VALIDATE(*keyname);
STORM_VALIDATE(valuename);
STORM_VALIDATE(*valuename);
STORM_VALIDATE_END;
@autoreleasepool {
return SetObject(keyname, valuename, flags, [NSNumber numberWithUnsignedInt:value]);
}
}

View file

@ -0,0 +1,21 @@
#ifndef STORM_REGISTRY_MAC_STATIC_HPP
#define STORM_REGISTRY_MAC_STATIC_HPP
#import <Foundation/Foundation.h>
class SRegStatic {
public:
NSMutableDictionary<NSString*, NSUserDefaults*>* hives;
static SRegStatic Get();
SRegStatic() {
this->hives = [NSMutableDictionary init];
}
~SRegStatic() {
this->hives = nil;
}
};
#endif

View file

@ -0,0 +1,14 @@
#include "storm/registry/mac/Static.hpp"
static SRegStatic* SRegStatic::Get() {
static SRegStatic sregstatic;
return &sregstatic;
}
SRegStatic::SRegStatic() {
this->hives = [[NSMutableDictionary alloc] init];
}
SRegStatic::~SRegStatic() {
this->hives = nil;
}

View file

@ -0,0 +1,225 @@
#include "storm/registry/Registry.hpp"
#include "storm/Error.hpp"
#include "storm/String.hpp"
#include "storm/Unicode.hpp"
#include "storm/option/Options.hpp"
#include <algorithm>
#include <cstdlib>
#include <windows.h>
int32_t ILoadValue(HKEY parentKey, const char* subKeyName, const char* valuename, uint32_t* datatype, uint8_t* buffer, uint32_t bytes, uint32_t* bytesread) {
int32_t result;
uint16_t wname[STORM_MAX_PATH];
HKEY key;
if (g_opt.sregunicode) {
SUniConvertUTF8to16(wname, STORM_MAX_PATH, reinterpret_cast<const uint8_t*>(subKeyName), STORM_MAX_STR, nullptr, nullptr);
result = RegOpenKeyExW(parentKey, reinterpret_cast<LPWSTR>(wname), 0, KEY_EXECUTE, &key);
if (result == ERROR_SUCCESS) {
*bytesread = bytes;
SUniConvertUTF8to16(wname, STORM_MAX_PATH, reinterpret_cast<const uint8_t*>(valuename), STORM_MAX_STR, nullptr, nullptr);
auto value = RegQueryValueExW(key, reinterpret_cast<LPWSTR>(wname), nullptr, reinterpret_cast<LPDWORD>(datatype), reinterpret_cast<LPBYTE>(buffer), reinterpret_cast<LPDWORD>(bytesread));
RegCloseKey(key);
return value;
}
} else {
result = RegOpenKeyExA(parentKey, reinterpret_cast<LPCSTR>(subKeyName), 0, KEY_EXECUTE, &key);
if (result == ERROR_SUCCESS) {
*bytesread = bytes;
auto value = RegQueryValueExA(key, reinterpret_cast<LPCSTR>(valuename), nullptr, reinterpret_cast<LPDWORD>(datatype), reinterpret_cast<LPBYTE>(buffer), reinterpret_cast<LPDWORD>(bytesread));
RegCloseKey(key);
return value;
}
}
return result;
}
int32_t SRegGetBaseKey(uint8_t flags, char* buffer, uint32_t buffersize) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(buffer);
STORM_VALIDATE(buffersize);
STORM_VALIDATE_END;
if (flags & STORM_REGISTRY_BATTLENET) {
SStrCopy(buffer, "Software\\Battle.net\\", STORM_MAX_PATH);
} else {
SStrCopy(buffer, "Software\\Blizzard Entertainment\\", STORM_MAX_PATH);
}
return 1;
}
void BuildFullKeyName(const char* keyname, uint8_t flags, char* buffer, uint32_t buffersize) {
*buffer = '\0';
if (!(flags & STORM_REGISTRY_NO_BASE_KEY)) {
SRegGetBaseKey(flags, buffer, buffersize);
}
SStrPack(buffer, keyname, buffersize);
}
int32_t InternalLoadEntry(const char* keyname, const char* valuename, uint32_t flags, uint32_t* datatype, uint8_t* buffer, uint32_t bytes, uint32_t* bytesread) {
char fullkeyname[STORM_MAX_PATH];
*fullkeyname = '\0';
*bytesread = 0;
*datatype = 0;
BuildFullKeyName(keyname, flags, fullkeyname, STORM_MAX_PATH);
auto result = ILoadValue(flags & STORM_REGISTRY_CURRENT_USER_ONLY ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, fullkeyname, valuename, datatype, buffer, bytes, bytesread);
if (result) {
SetLastError(result);
return 0;
}
return 1;
}
int32_t InternalSaveEntry(const char* keyname, const char* valuename, uint32_t flags, uint32_t datatype, const uint8_t* buffer, uint32_t bytes) {
char fullkeyname[STORM_MAX_PATH];
*fullkeyname = '\0';
BuildFullKeyName(keyname, flags, fullkeyname, STORM_MAX_PATH);
HKEY key;
DWORD disposition;
int32_t result;
uint16_t wname[STORM_MAX_PATH] = {0};
if (g_opt.sregunicode) {
SUniConvertUTF8to16(wname, STORM_MAX_PATH, reinterpret_cast<const uint8_t*>(fullkeyname), STORM_MAX_STR, nullptr, nullptr);
result = RegCreateKeyExW(flags & STORM_REGISTRY_CURRENT_USER_ONLY ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, reinterpret_cast<LPCWSTR>(wname), 0, nullptr, 0, KEY_WRITE, nullptr, &key, &disposition);
} else {
result = RegCreateKeyExA(flags & STORM_REGISTRY_CURRENT_USER_ONLY ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, reinterpret_cast<LPCSTR>(fullkeyname), 0, nullptr, 0, KEY_WRITE, nullptr, &key, &disposition);
}
if (result) {
SetLastError(result);
return 0;
}
if (g_opt.sregunicode) {
SUniConvertUTF8to16(wname, STORM_MAX_PATH, reinterpret_cast<const uint8_t*>(valuename), STORM_MAX_STR, nullptr, nullptr);
result = RegSetValueExW(key, reinterpret_cast<LPCWSTR>(wname), 0, datatype, reinterpret_cast<const BYTE*>(buffer), bytes);
} else {
result = RegSetValueExA(key, reinterpret_cast<LPCSTR>(valuename), 0, datatype, reinterpret_cast<const BYTE*>(buffer), bytes);
}
if (!result && (flags & STORM_REGISTRY_FLUSH_KEY) != 0) {
result = RegFlushKey(key);
}
RegCloseKey(key);
if (result) {
SetLastError(result);
return 0;
}
return 1;
}
int32_t SRegLoadString(const char* keyname, const char* valuename, uint32_t flags, char* buffer, uint32_t buffersize) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(keyname);
STORM_VALIDATE(*keyname);
STORM_VALIDATE(valuename);
STORM_VALIDATE(*valuename);
STORM_VALIDATE(buffer);
STORM_VALIDATE_END;
uint32_t datatype;
uint16_t widecharstr[4096];
uint32_t bytesread;
if (g_opt.sregunicode) {
if (!InternalLoadEntry(keyname, valuename, flags, &datatype, reinterpret_cast<uint8_t*>(&widecharstr), sizeof(widecharstr), &bytesread)) {
return 0;
}
if (datatype == REG_SZ) {
uint32_t dstchars;
SUniConvertUTF16to8(reinterpret_cast<uint8_t*>(buffer), buffersize, widecharstr, bytesread / 2, &dstchars, nullptr);
buffer[std::min(buffersize - 1, dstchars)] = '\0';
return 1;
} else if (datatype == REG_DWORD) {
SStrPrintf(buffer, buffersize, "%u", (reinterpret_cast<uint32_t*>(widecharstr))[0]);
return 1;
}
} else {
if (!InternalLoadEntry(keyname, valuename, flags, &datatype, reinterpret_cast<uint8_t*>(buffer), buffersize, &bytesread)) {
return 0;
}
if (datatype == REG_SZ) {
buffer[std::min(buffersize - 1, bytesread)] = '\0';
return 1;
} else if (datatype == REG_DWORD) {
SStrPrintf(buffer, buffersize, "%u", (reinterpret_cast<uint32_t*>(buffer))[0]);
return 1;
}
}
return 0;
}
int32_t SRegLoadValue(const char* keyname, const char* valuename, uint32_t flags, uint32_t* value) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(keyname);
STORM_VALIDATE(*keyname);
STORM_VALIDATE(valuename);
STORM_VALIDATE(*valuename);
STORM_VALIDATE(value);
STORM_VALIDATE_END;
uint8_t buffer[256];
uint32_t bytesread;
uint32_t datatype;
if (!InternalLoadEntry(keyname, valuename, flags, &datatype, buffer, sizeof(buffer), &bytesread)) {
return 0;
}
if (datatype == REG_SZ) {
*value = strtoul(reinterpret_cast<char*>(buffer), 0, 0);
} else if (datatype == REG_DWORD) {
*value = *reinterpret_cast<uint32_t*>(buffer);
}
return 1;
}
int32_t SRegSaveString(const char* keyname, const char* valuename, uint32_t flags, const char* string) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(keyname);
STORM_VALIDATE(*keyname);
STORM_VALIDATE(valuename);
STORM_VALIDATE(*valuename);
STORM_VALIDATE(string);
STORM_VALIDATE_END;
if (g_opt.sregunicode) {
uint16_t widecharstr[STORM_MAX_PATH];
SUniConvertUTF8to16(widecharstr, STORM_MAX_PATH, reinterpret_cast<const uint8_t*>(string), STORM_MAX_STR, nullptr, nullptr);
// ersatz wcslen()
uint32_t length;
auto p = widecharstr;
while (*p) {
++p;
}
length = p - widecharstr;
return InternalSaveEntry(keyname, valuename, flags, REG_SZ, reinterpret_cast<const uint8_t*>(widecharstr), (length + 1) * 2);
} else {
return InternalSaveEntry(keyname, valuename, flags, REG_SZ, reinterpret_cast<const uint8_t*>(string), SStrLen(string) + 1);
}
}
int32_t SRegSaveValue(const char* keyname, const char* valuename, uint32_t flags, uint32_t value) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(keyname);
STORM_VALIDATE(*keyname);
STORM_VALIDATE(valuename);
STORM_VALIDATE(*valuename);
STORM_VALIDATE_END;
return InternalSaveEntry(keyname, valuename, flags, REG_DWORD, reinterpret_cast<const uint8_t*>(&value), 4);
}
void SRegDestroy() {
}