Skip to content

Commit

Permalink
Use wide strings for stringVar buffer to avoid matching multibyte cha…
Browse files Browse the repository at this point in the history
…r components to single byte char, provided that the system locale is setted according to the character set required. Stop gap measure for fixing bug #229, until a more proper solution can be implemented for #235
  • Loading branch information
llde committed Aug 12, 2024
1 parent 1465b7d commit b3c9331
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 36 deletions.
3 changes: 2 additions & 1 deletion obse/obse/CommandTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2998,6 +2998,7 @@ void CommandTable::Init(void)
ADD_CMD(GetBaseAV3);
ADD_CMD(GetBaseAV3C);
ADD_CMD(IsNaked);
g_scriptCommands.RecordReleaseVersion();
//OBSE 22.4
ADD_CMD(SetAltControl2);
//OBSE 22.5
Expand All @@ -3020,7 +3021,7 @@ void CommandTable::Init(void)
newgetDisease.shortName = "GetDisease";
newgetDisease.longName = "GetDisease";
g_scriptCommands.Replace(opcodeGetDisease, &newgetDisease); //Ready for the mapping

ADD_CMD(sv_PrintBytes);
/* to add later if problems can be solved
g_scriptCommands.Add(&kCommandInfo_SetCurrentClimate); // too many problems
g_scriptCommands.Add(&kCommandInfo_SetWorldspaceClimate);
Expand Down
47 changes: 45 additions & 2 deletions obse/obse/Commands_String.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ static bool StringVar_Find_Execute(COMMAND_ARGS, UInt32 mode, CommandInfo* comma
{
case eMode_svFind:
intResult = strVar->Find(toFind, startPos, numChars, bCaseSensitive ? true : false);

break;
case eMode_svCount:
intResult = strVar->Count(toFind, startPos, numChars, bCaseSensitive ? true : false);
Expand All @@ -215,7 +216,6 @@ static bool StringVar_Find_Execute(COMMAND_ARGS, UInt32 mode, CommandInfo* comma

if (intResult != -1)
*result = intResult;

return true;
}

Expand Down Expand Up @@ -898,6 +898,29 @@ static bool Cmd_sv_ToLower_Execute (COMMAND_ARGS)
return ChangeCase_Execute (PASS_COMMAND_ARGS, false);
}

static bool Cmd_sv_PrintBytes_Execute(COMMAND_ARGS) {
UInt32 rhStrID = 0;

if (ExtractArgs(PASS_EXTRACT_ARGS, &rhStrID))
{
StringVar* rhVar = g_StringMap.Get(rhStrID);
Console_Print("Get stringVar key");
if (!rhVar)
return true;
const char* str = rhVar->GetCString();
Console_Print("%s", str);
char buf[3] = {0};
std::string final = "";
for (int i = 0; i < strlen(str); i++) {
snprintf(buf, 3, "%hhX", (unsigned char)str[i]);
final.append(buf);
final.append(" ");
memset(buf, 0, 3);
}
Console_Print_Long(final);
}
return true;
}
#endif

static ParamInfo kParams_sv_Destruct[10] =
Expand Down Expand Up @@ -1403,4 +1426,24 @@ CommandInfo kCommandInfo_sv_ToUpper =
HANDLER(Cmd_sv_ToUpper_Execute),
Cmd_Expression_Parse,
NULL, 0
};
};
static ParamInfo kParams_OneOBSEStringVar[] =
{
{ "stringVar", kParamType_StringVar, 0 },
};


CommandInfo kCommandInfo_sv_PrintBytes =
{
"sv_PrintBytes",
"",
0,
"Print an hex representation of the bytes in the string_var",
0,
1,
kParams_OneOBSEStringVar,
HANDLER(Cmd_sv_PrintBytes_Execute),
Cmd_Default_Parse,
NULL,
0
};
1 change: 1 addition & 0 deletions obse/obse/Commands_String.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,4 @@ extern CommandInfo kCommandInfo_GetRawFormIDString;

extern CommandInfo kCommandInfo_sv_ToUpper;
extern CommandInfo kCommandInfo_sv_ToLower;
extern CommandInfo kCommandInfo_sv_PrintBytes;
8 changes: 7 additions & 1 deletion obse/obse/ExpressionEvaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,13 @@ ScriptToken* ExpressionEvaluator::Evaluate()
case kRetnType_String:
{
StringVar* strVar = g_StringMap.Get(cmdResult);
curToken = ScriptToken::Create(strVar ? strVar->GetCString() : "");
if (strVar) {

curToken = ScriptToken::Create(strVar->GetCString());
}
else {
curToken = ScriptToken::Create("");
}
break;
}
case kRetnType_Array:
Expand Down
12 changes: 11 additions & 1 deletion obse/obse/Hooks_Input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,13 @@ if ( dword_3DAA060[0] )
}
*/

IDirect3DSwapChain9* __stdcall HookSwapChain(IDirect3DDevice9* device) {
IDirect3DSwapChain9* swapchain = nullptr;
device->GetSwapChain(0, &swapchain);
return swapchain;
}


void Hook_Input_Init() {
SafeWrite32(kInputGlobalAllocSize, sizeof(OSInputGlobalsEx));
OSInputGlobalsEx* (__thiscall OSInputGlobalsEx::* InitializeExCall)(IDirectInputDevice8*) = &OSInputGlobalsEx::InitializeEx;
Expand All @@ -575,6 +582,9 @@ void Hook_Input_Init() {
WriteRelJump(kInputObjaHook2Loc, kInputOriginalObjaJumpLoc);
WriteRelJump(kPollEndHook, (UInt32) &PollInputHookObja);

UInt32 lastHook = 0x4780 + obja;
WriteRelJump(lastHook, (UInt32) &HookSwapChain);

}
else if (PluginManager::GetPluginLoaded("OBCN")) {
UInt32 obcn = (UInt32)PluginManager::GetModuleAddressByName("OBCN"); //Assume incompatible with OBJA
Expand All @@ -590,7 +600,7 @@ void Hook_Input_Init() {
WriteRelJump(kInputObjaHook1Loc, kInputOriginalObjaJumpLoc);
WriteRelJump(kInputObjaHook2Loc, kInputOriginalObjaJumpLoc); //Same hook points of OBJA
WriteRelJump(kPollEndHook, (UInt32)&PollInputHookObcn);

WriteRelJump(0x000024A3 + obcn, 0x00024A8 + obcn);
}
else{
WriteRelJump(kPollEndHook, (UInt32) &PollInputHook);
Expand Down
120 changes: 91 additions & 29 deletions obse/obse/StringVar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,59 @@
#include "ScriptUtils.h"
#include "GameData.h"


wchar_t* ConvertToWideString(const char* string) {
int sizeMultibyteBuffer = MultiByteToWideChar(CP_ACP, 0, string, -1, nullptr, 0);
wchar_t* widestring = new wchar_t[sizeMultibyteBuffer];
MultiByteToWideChar(CP_ACP, 0, string, -1, widestring, sizeMultibyteBuffer);
return widestring;
}


char* ConvertToMultibyteString(const wchar_t* widestring) {
int sizeMultibyteBuffer = WideCharToMultiByte(CP_ACP, 0, widestring, -1, nullptr, 0, nullptr,nullptr);
char* string = new char[sizeMultibyteBuffer];
WideCharToMultiByte(CP_ACP, 0, widestring, -1, string, sizeMultibyteBuffer,nullptr,nullptr);
return string;
}

StringVar::StringVar(const char* in_data, UInt32 in_refID)
{
data = std::string(in_data);
wchar_t* widestring = ConvertToWideString(in_data);
data = std::wstring(widestring);
delete[] widestring;
owningModIndex = in_refID >> 24;
}

std::string StringVar::String() {
char* string = ConvertToMultibyteString(data.c_str());
return std::string(string);
}

const char* StringVar::GetCString()
{
return data.c_str();
if (modified == true || multibyte_ptr.get() == nullptr) {
multibyte_ptr = std::unique_ptr<const char[]>(ConvertToMultibyteString(data.c_str()));
}
return multibyte_ptr.get();
}

void StringVar::Set(const char* newString)
{
data = std::string(newString);
wchar_t* widestring = ConvertToWideString(newString);
data = std::wstring(widestring);
delete[] widestring;
modified = true;
}

SInt32 StringVar::Compare(char* rhs, bool caseSensitive)
{
SInt32 cmp = 0;
wchar_t* widecmp = ConvertToWideString(rhs);
if (!caseSensitive)
{
cmp = _stricmp(data.c_str(), rhs);
cmp = _wcsicmp(data.c_str(), widecmp);
delete[] widecmp;
if (cmp > 0)
return -1;
else if (cmp < 0)
Expand All @@ -38,22 +69,35 @@ SInt32 StringVar::Compare(char* rhs, bool caseSensitive)
}
else
{
std::string str2(rhs);
if (data == str2)
return 0;
else if (data > str2)
cmp = wcscmp(data.c_str(), widecmp);
delete[] widecmp;

if (cmp > 0)
return -1;
else if (cmp < 0)
return 1;
else
return 0;

if (cmp > 0)
return -1;
else if (cmp < 0)
return 1;
else
return 0;
}
}

void StringVar::Insert(const char* subString, UInt32 insertionPos)
{
wchar_t* wide = ConvertToWideString(subString);
if (insertionPos < GetLength())
data.insert(insertionPos, subString);
data.insert(insertionPos, wide);
else if (insertionPos == GetLength())
data.append(subString);
data.append(wide);
delete[] wide;
modified = true;

}

#pragma warning(disable : 4996) // disable checked iterator warning for std::transform with char*
Expand All @@ -66,17 +110,19 @@ UInt32 StringVar::Find(char* subString, UInt32 startPos, UInt32 numChars, bool b

if (startPos < GetLength())
{
std::string source = data.substr(startPos, numChars);
std::wstring source = data.substr(startPos, numChars);
wchar_t* wide = ConvertToWideString(subString);
if (!bCaseSensitive)
{
std::transform(source.begin(), source.end(), source.begin(), tolower);
std::transform(subString, subString + strlen(subString), subString, tolower);
std::transform(source.begin(), source.end(), source.begin(), towlower);
std::transform(wide, wide + wcslen(wide), wide, towlower);
}

//pos = data.substr(startPos, numChars).find(subString); //returns -1 if not found
pos = source.find(subString);
pos = source.find(wide);
if (pos != -1)
pos += startPos;
delete[] wide;
}

return pos;
Expand All @@ -90,25 +136,28 @@ UInt32 StringVar::Count(char* subString, UInt32 startPos, UInt32 numChars, bool
if (startPos >= GetLength())
return 0;

std::string source = data.substr(startPos, numChars); //only count occurences beginning before endPos
std::wstring source = data.substr(startPos, numChars); //only count occurences beginning before endPos

UInt32 subStringLen = strlen(subString);
if (!subStringLen)
return 0;

wchar_t* wide = ConvertToWideString(subString);
subStringLen = wcslen(wide);
if (!bCaseSensitive)
{
std::transform(source.begin(), source.end(), source.begin(), tolower);
std::transform(subString, subString + strlen(subString), subString, tolower);
std::transform(source.begin(), source.end(), source.begin(), towlower);
std::transform(wide, wide + subStringLen, wide, towlower);
}

UInt32 strIdx = 0;
UInt32 count = 0;
while (strIdx < GetLength() && ((strIdx = source.find(subString, strIdx)) != -1))
while (strIdx < GetLength() && ((strIdx = source.find(wide, strIdx)) != -1))
{
count++;
strIdx += subStringLen;
}

delete[] wide;
return count;
}
#pragma warning(default : 4996)
Expand All @@ -127,11 +176,14 @@ UInt32 StringVar::Replace(char* toReplace, const char* replaceWith, UInt32 start
numChars = GetLength() - startPos;

UInt32 numReplaced = 0;
UInt32 replacementLen = strlen(replaceWith);
UInt32 toReplaceLen = strlen(toReplace);
wchar_t* toReplaceWide = ConvertToWideString(toReplace);
wchar_t* replaceWithWide = ConvertToWideString(replaceWith);

UInt32 replacementLen = wcslen(replaceWithWide);
UInt32 toReplaceLen = wcslen(toReplaceWide);

// create substring
std::string srcStr = data.substr(startPos, numChars);
std::wstring srcStr = data.substr(startPos, numChars);

// remove substring from original string
data.erase(startPos, numChars);
Expand All @@ -141,14 +193,14 @@ UInt32 StringVar::Replace(char* toReplace, const char* replaceWith, UInt32 start
{
if (bCaseSensitive)
{
strIdx = srcStr.find(toReplace, strIdx);
strIdx = srcStr.find(toReplaceWide, strIdx);
if (strIdx == -1)
break;
}
else
{
std::string strToReplace = toReplace;
std::string::iterator iter = std::search(srcStr.begin() + strIdx, srcStr.end(), strToReplace.begin(), strToReplace.end(), ci_equal);
std::wstring strToReplace = toReplaceWide;
std::wstring::iterator iter = std::search(srcStr.begin() + strIdx, srcStr.end(), strToReplace.begin(), strToReplace.end(), ci_equal);
if (iter != srcStr.end())
strIdx = iter - srcStr.begin();
else
Expand All @@ -159,12 +211,12 @@ UInt32 StringVar::Replace(char* toReplace, const char* replaceWith, UInt32 start
srcStr.erase(strIdx, toReplaceLen);
if (strIdx == srcStr.length())
{
srcStr.append(replaceWith);
srcStr.append(replaceWithWide);
break; // reached end of string so all done
}
else
{
srcStr.insert(strIdx, replaceWith);
srcStr.insert(strIdx, replaceWithWide);
strIdx += replacementLen;
}
}
Expand All @@ -175,7 +227,12 @@ UInt32 StringVar::Replace(char* toReplace, const char* replaceWith, UInt32 start
else
data.insert(startPos, srcStr);

delete[] replaceWithWide;
delete[] toReplaceWide;
modified = true;

return numReplaced;

}

void StringVar::Erase(UInt32 startPos, UInt32 numChars)
Expand All @@ -185,15 +242,20 @@ void StringVar::Erase(UInt32 startPos, UInt32 numChars)

if (startPos < GetLength())
data.erase(startPos, numChars);
modified = true;

}

std::string StringVar::SubString(UInt32 startPos, UInt32 numChars)
{
if (numChars + startPos >= GetLength())
numChars = GetLength() - startPos;

if (startPos < GetLength())
return data.substr(startPos, numChars);
if (startPos < GetLength()) {
std::wstring sub = data.substr(startPos, numChars);
char* string = ConvertToMultibyteString(sub.data());
return std::string(string);
}
else
return "";
}
Expand Down
Loading

0 comments on commit b3c9331

Please sign in to comment.