Skip to content

Commit

Permalink
Fixes in file operations plugin. New opcodes and unit tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
MiranDMC committed Mar 4, 2024
1 parent a77505c commit 5777977
Show file tree
Hide file tree
Showing 11 changed files with 1,195 additions and 34 deletions.
7 changes: 5 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@
- added/fixed support of all file stream opcodes in legacy mode (Cleo3)
- new opcode **2300 ([get_file_position](https://library.sannybuilder.com/#/sa/file/2300))**
- new opcode **2301 ([read_block_from_file](https://library.sannybuilder.com/#/sa/file/2301))**
- **2302 ([resolve_filepath](https://library.sannybuilder.com/#/sa/file/2302))**
- **2303 ([get_script_filename](https://library.sannybuilder.com/#/sa/file/2303))**
- new opcode **2302 ([write_block_to_file](https://library.sannybuilder.com/#/sa/file/2302))**
- new opcode **2303 ([resolve_filepath](https://library.sannybuilder.com/#/sa/file/2303))**
- new opcode **2304 ([get_script_filename](https://library.sannybuilder.com/#/sa/file/2304))**
- new [MemoryOperations](https://github.com/cleolibrary/CLEO5/tree/master/cleo_plugins/MemoryOperations) plugin
- memory related opcodes moved from CLEO core into separated plugin
- validation of input and output parameters for all opcodes
Expand All @@ -43,6 +44,7 @@
- new opcode **2404 ([get_script_struct_just_created](https://library.sannybuilder.com/#/sa/memory/2404))**
- new opcode **2405 ([is_script_running](https://library.sannybuilder.com/#/sa/memory/2405))**
- new opcode **2406 ([get_script_struct_from_filename](https://library.sannybuilder.com/#/sa/memory/2406))**
- new opcode **2407 ([is_memory_equal](https://library.sannybuilder.com/#/sa/memory/2407))**
- new and updated opcodes
- **0B1E ([sign_extend](https://library.sannybuilder.com/#/sa/bitwise/0B1E))**
- **0DD5 ([get_game_platform](https://library.sannybuilder.com/#/sa/CLEO/0DD5))**
Expand Down Expand Up @@ -102,6 +104,7 @@


#### CLEO internal
- introduced unit test scripts
- project migrated to VS 2022
- configured game debugging settings
- plugins moved into single solution
Expand Down
73 changes: 43 additions & 30 deletions cleo_plugins/FileSystemOperations/FileSystemOperations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,9 @@ class FileSystemOperations

CLEO_RegisterOpcode(0x2300, opcode_2300); // get_file_position
CLEO_RegisterOpcode(0x2301, opcode_2301); // read_block_from_file
CLEO_RegisterOpcode(0x2302, opcode_2302); // resolve_filepath
CLEO_RegisterOpcode(0x2303, opcode_2303); // get_script_filename
CLEO_RegisterOpcode(0x2302, opcode_2302); // write_block_to_file
CLEO_RegisterOpcode(0x2303, opcode_2303); // resolve_filepath
CLEO_RegisterOpcode(0x2304, opcode_2304); // get_script_filename

// register event callbacks
CLEO_RegisterCallback(eCallbackId::ScriptsFinalize, OnFinalizeScriptObjects);
Expand Down Expand Up @@ -209,6 +210,7 @@ class FileSystemOperations

if (size == 0)
{
OPCODE_SKIP_PARAMS(1); // from
return OR_CONTINUE; // done
}

Expand Down Expand Up @@ -298,37 +300,19 @@ class FileSystemOperations

if (size < 0)
{
auto info = ScriptInfoStr(thread);
SHOW_ERROR("Invalid size argument (%d) in script %s\nScript suspended.", size, info.c_str());
SHOW_ERROR("Invalid size argument (%d) in script %s\nScript suspended.", size, ScriptInfoStr(thread).c_str());
return thread->Suspend();
}

if (size == 0)
{
if (bufferSize > 0) buffer[0] = '\0';
OPCODE_CONDITION_RESULT(false);
OPCODE_CONDITION_RESULT(true);
return OR_CONTINUE;
}

std::vector<char> tmpBuff;
tmpBuff.resize(size);
auto data = tmpBuff.data();
bool ok = File::readString(handle, buffer, size) != nullptr;

bool ok = File::readString(handle, data, size) != nullptr;
if(!ok)
{
OPCODE_CONDITION_RESULT(false);
return OR_CONTINUE;
}

// copy into result param
int len = strlen(data);
int resultSize = min(len, bufferSize - (int)needsTerminator);

memcpy(buffer, data, resultSize);
if(resultSize < bufferSize) buffer[resultSize] = '\0'; // terminate string whenever possible

OPCODE_CONDITION_RESULT(true);
OPCODE_CONDITION_RESULT(ok);
return OR_CONTINUE;
}

Expand Down Expand Up @@ -686,8 +670,7 @@ class FileSystemOperations

if (size < 0)
{
auto info = ScriptInfoStr(thread);
SHOW_ERROR("Invalid size argument (%d) in script %s\nScript suspended.", size, info.c_str());
SHOW_ERROR("Invalid size argument (%d) in script %s\nScript suspended.", size, ScriptInfoStr(thread).c_str());
return thread->Suspend();
}

Expand All @@ -708,17 +691,47 @@ class FileSystemOperations
return OR_CONTINUE;
}

//2302=2,%2s% = resolve_filepath %1s%
static OpcodeResult __stdcall opcode_2302(CRunningScript* thread)
//2302=3,write_block_to_file %1d% size %2d% address %3d% // IF and SET
static OpcodeResult WINAPI opcode_2302(CRunningScript* thread)
{
auto handle = READ_FILE_HANDLE_PARAM();
auto size = OPCODE_READ_PARAM_INT();
auto source = OPCODE_READ_PARAM_PTR();

if (size < 0)
{
SHOW_ERROR("Invalid size argument (%d) in script %s\nScript suspended.", size, ScriptInfoStr(thread).c_str());
return thread->Suspend();
}

if (size == 0)
{
OPCODE_CONDITION_RESULT(true);
return OR_CONTINUE;
}

auto readCount = File::write(handle, source, size);
if (readCount != size)
{
OPCODE_CONDITION_RESULT(false);
return OR_CONTINUE;
}

OPCODE_CONDITION_RESULT(true);
return OR_CONTINUE;
}

//2303=2,%2s% = resolve_filepath %1s%
static OpcodeResult __stdcall opcode_2303(CRunningScript* thread)
{
OPCODE_READ_PARAM_FILEPATH(path); // it also resolves the path to absolute form

OPCODE_WRITE_PARAM_STRING(path);
return OR_CONTINUE;
}

//2303=3,%3s% = get_script_filename %1d% full_path %2d% // IF and SET
static OpcodeResult __stdcall opcode_2303(CRunningScript* thread)
//2304=3,%3s% = get_script_filename %1d% full_path %2d% // IF and SET
static OpcodeResult __stdcall opcode_2304(CRunningScript* thread)
{
auto script = OPCODE_READ_PARAM_INT();
auto fullPath = OPCODE_READ_PARAM_BOOL();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ if defined GTA_SA_DIR (
<ClCompile Include="FileUtils.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\cleo_sdk\CLEO.h" />
<ClInclude Include="..\..\cleo_sdk\CLEO_Utils.h" />
<ClInclude Include="FileUtils.h" />
<ClInclude Include="Utils.h" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,16 @@
<ItemGroup>
<ClInclude Include="FileUtils.h" />
<ClInclude Include="Utils.h" />
<ClInclude Include="..\..\cleo_sdk\CLEO.h">
<Filter>cleo_sdk</Filter>
</ClInclude>
<ClInclude Include="..\..\cleo_sdk\CLEO_Utils.h">
<Filter>cleo_sdk</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="cleo_sdk">
<UniqueIdentifier>{a2c39c52-f49e-4ffe-bb0a-661ab07131b9}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>
42 changes: 40 additions & 2 deletions cleo_plugins/FileSystemOperations/FileUtils.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "FileUtils.h"
#include "CLEO_Utils.h"
#include <string>

DWORD File::FUNC_fopen = 0;
Expand Down Expand Up @@ -84,20 +85,57 @@ bool File::flush(DWORD handle)

DWORD File::open(const char* filename, const char* mode, bool legacy)
{
char modeParsed[8] = { 0 };

// validate the mode argument
bool modeValid = false;
bool modeBin = false;
auto modeLen = mode != nullptr ? strlen(mode) : 0;
if (modeLen > 0 && modeLen < (sizeof(modeParsed) - 1)) // keep space for extra binary mode char
{
modeValid = true;

size_t i = 0;
while (i < modeLen)
{
auto& ch = mode[i];
if (ch == '+' || ch == 'a' || ch == 'b' || ch == 'r' || ch == 'w')
{
modeParsed[i] = ch;
modeBin = modeBin || ch == 'b';
}
else
{
modeValid = false;
break; // invalid character
}

i++;
}

if (!modeBin) modeParsed[i] = 'b'; // always open as binary mode, as text mode does not behave as expected in multiple scenarios
}
if (!modeValid)
{
LOG_WARNING(0, "Invalid mode argument '%s' while opening file \"%s\" stream!", mode, filename);
return 0; // invalid handle
}

FILE* file = nullptr;
if (legacy)
{
_asm
{
push mode
lea eax, modeParsed
push eax
push filename
call FUNC_fopen
add esp, 8
mov file, eax
}
}
else
file = fopen(filename, mode);
file = fopen(filename, modeParsed);

return fileToHandle(file, legacy);
}
Expand Down
25 changes: 25 additions & 0 deletions cleo_plugins/MemoryOperations/MemoryOperations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class MemoryOperations
CLEO_RegisterOpcode(0x2404, opcode_2404); // get_script_struct_just_created
CLEO_RegisterOpcode(0x2405, opcode_2405); // is_script_running
CLEO_RegisterOpcode(0x2406, opcode_2406); // get_script_struct_from_filename
CLEO_RegisterOpcode(0x2407, opcode_2407); // is_memory_equal


// register event callbacks
Expand Down Expand Up @@ -788,6 +789,30 @@ class MemoryOperations
OPCODE_CONDITION_RESULT(address != nullptr);
return OR_CONTINUE;
}

//2407=3, is_memory_equal address_a %1d% address_b %2d% size %d3%
static OpcodeResult __stdcall opcode_2407(CLEO::CScriptThread* thread)
{
auto addressA = OPCODE_READ_PARAM_PTR();
auto addressB = OPCODE_READ_PARAM_PTR();
auto size = OPCODE_READ_PARAM_INT();

if (size == 0)
{
OPCODE_CONDITION_RESULT(true);
return OR_CONTINUE;
}
if (size < 0)
{
SHOW_ERROR("Invalid '%d' size argument in script %s\nScript suspended.", size, ScriptInfoStr(thread).c_str());
return thread->Suspend();
}

auto result = memcmp(addressA, addressB, size);

OPCODE_CONDITION_RESULT(result == 0);
return OR_CONTINUE;
}
} Memory;

std::set<void*> MemoryOperations::m_allocations;
Expand Down
Loading

0 comments on commit 5777977

Please sign in to comment.