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

File related opcodes fixes. More tests. #88

Merged
merged 5 commits into from
Mar 5, 2024
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
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
69 changes: 39 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,20 @@ 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);
return OR_CONTINUE;
}

std::vector<char> tmpBuff;
tmpBuff.resize(size);
auto data = tmpBuff.data();

bool ok = File::readString(handle, data, size) != nullptr;
if(!ok)
{
OPCODE_CONDITION_RESULT(false);
OPCODE_CONDITION_RESULT(true);
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
// use caller's size argument, ignoring actual target type size. Intended for legacy reasons.
bool ok = File::readString(handle, buffer, size) != nullptr;

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

Expand Down Expand Up @@ -686,8 +671,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 +692,42 @@ 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);

OPCODE_CONDITION_RESULT(readCount == size);
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>
46 changes: 46 additions & 0 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,6 +85,51 @@ bool File::flush(DWORD handle)

DWORD File::open(const char* filename, const char* mode, bool legacy)
{
// validate the mode argument
if (!legacy)
{
static char modeUpdated[12];
const std::string allowed = "+abcnrtwxDRST"; // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fopen-wfopen?view=msvc-170

bool valid = false;
bool binary = false;
bool text = false;
auto modeLen = mode != nullptr ? strlen(mode) : 0;
if (modeLen > 0 && modeLen < (sizeof(modeUpdated) - 1)) // keep space for extra binary mode char
{
valid = true;

for (auto ch : std::string_view(mode))
{
if (allowed.find(ch) == std::string_view::npos)
{
valid = false;
break; // invalid character
}

if (ch == 'b') binary = true;
if (ch == 't') text = true;
}

if (binary && text) valid = false;

// By default open as binary mode.
// Generally text mode is not well documented in C and many file related functions has undefined behavior. For example 'ftell' returns invalid values.
if (valid && !binary)
{
strcpy(modeUpdated, mode);
strcat(modeUpdated, "b");
mode = modeUpdated;
}
}

if (!valid)
{
LOG_WARNING(0, "Invalid mode argument '%s' while opening file \"%s\" stream!", mode, filename);
return 0; // invalid handle
}
}

FILE* file = nullptr;
if (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