2017-09-26 08:59:34 +02:00
|
|
|
// MIT License
|
|
|
|
|
|
|
|
// Copyright (c) 2017 Vadim Grigoruk @nesbox // grigoruk@gmail.com
|
|
|
|
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
|
|
// in the Software without restriction, including without limitation the rights
|
|
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
|
|
// furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
|
|
// copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
// SOFTWARE.
|
|
|
|
|
|
|
|
#include "run.h"
|
|
|
|
#include "console.h"
|
|
|
|
#include "fs.h"
|
|
|
|
#include "ext/md5.h"
|
2017-12-07 15:45:29 +01:00
|
|
|
#include <time.h>
|
2017-09-26 08:59:34 +02:00
|
|
|
|
|
|
|
static void onTrace(void* data, const char* text, u8 color)
|
|
|
|
{
|
|
|
|
Run* run = (Run*)data;
|
|
|
|
|
|
|
|
run->console->trace(run->console, text, color);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onError(void* data, const char* info)
|
|
|
|
{
|
|
|
|
Run* run = (Run*)data;
|
|
|
|
|
|
|
|
setStudioMode(TIC_CONSOLE_MODE);
|
|
|
|
run->console->error(run->console, info);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onExit(void* data)
|
|
|
|
{
|
|
|
|
Run* run = (Run*)data;
|
|
|
|
|
|
|
|
run->exit = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char* data2md5(const void* data, s32 length)
|
|
|
|
{
|
|
|
|
const char *str = data;
|
|
|
|
MD5_CTX c;
|
|
|
|
|
|
|
|
static char out[33];
|
|
|
|
|
|
|
|
MD5_Init(&c);
|
|
|
|
|
|
|
|
while (length > 0)
|
|
|
|
{
|
|
|
|
MD5_Update(&c, str, length > 512 ? 512: length);
|
|
|
|
|
|
|
|
length -= 512;
|
|
|
|
str += 512;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
u8 digest[16];
|
|
|
|
MD5_Final(digest, &c);
|
|
|
|
|
|
|
|
for (s32 n = 0; n < 16; ++n)
|
|
|
|
snprintf(&(out[n*2]), 16*2, "%02x", (u32)digest[n]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2017-12-27 10:51:13 +01:00
|
|
|
static void initPMemName(Run* run)
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
2017-12-14 13:37:05 +01:00
|
|
|
const char* data = strlen(run->tic->saveid) ? run->tic->saveid : run->tic->cart.bank0.code.data;
|
2017-09-26 08:59:34 +02:00
|
|
|
char* md5 = data2md5(data, (s32)strlen(data));
|
2017-12-27 10:51:13 +01:00
|
|
|
strcpy(run->saveid, TIC_LOCAL);
|
|
|
|
strcat(run->saveid, md5);
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void tick(Run* run)
|
|
|
|
{
|
|
|
|
if (getStudioMode() != TIC_RUN_MODE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
run->tic->api.tick(run->tic, &run->tickData);
|
|
|
|
|
|
|
|
enum {Size = sizeof(tic_persistent)};
|
|
|
|
|
2018-02-13 11:38:11 +01:00
|
|
|
// TODO: remove PMEM checking...
|
2018-02-06 20:15:56 +01:00
|
|
|
if(memcmp(&run->tic->persistent, &run->persistent, Size) != 0)
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
2017-12-27 10:51:13 +01:00
|
|
|
fsSaveRootFile(run->console->fs, run->saveid, &run->tic->persistent, Size, true);
|
2018-02-06 20:15:56 +01:00
|
|
|
memcpy(&run->persistent, &run->tic->persistent, Size);
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if(run->exit)
|
|
|
|
setStudioMode(TIC_CONSOLE_MODE);
|
|
|
|
}
|
|
|
|
|
2017-11-27 17:38:10 +01:00
|
|
|
static void processDoFile(void* data, char* dst)
|
|
|
|
{
|
|
|
|
Run* run = (Run*)data;
|
|
|
|
tic_mem* tic = run->tic;
|
|
|
|
|
|
|
|
static const char DoFileTag[] = "dofile(";
|
|
|
|
enum {Size = sizeof DoFileTag - 1};
|
|
|
|
|
2017-12-14 13:37:05 +01:00
|
|
|
if (memcmp(tic->cart.bank0.code.data, DoFileTag, Size) == 0)
|
2017-11-27 17:38:10 +01:00
|
|
|
{
|
2017-12-14 13:37:05 +01:00
|
|
|
const char* start = tic->cart.bank0.code.data + Size;
|
2017-11-27 17:38:10 +01:00
|
|
|
const char* end = strchr(start, ')');
|
|
|
|
|
|
|
|
if(end && *start == *(end-1) && (*start == '"' || *start == '\''))
|
|
|
|
{
|
|
|
|
char filename[FILENAME_MAX] = {0};
|
|
|
|
memcpy(filename, start + 1, end - start - 2);
|
|
|
|
memset(dst, 0, sizeof(tic_code));
|
|
|
|
|
|
|
|
s32 size = 0;
|
|
|
|
void* buffer = fsReadFile(filename, &size);
|
|
|
|
|
|
|
|
if(buffer)
|
|
|
|
{
|
|
|
|
if(size > 0)
|
|
|
|
{
|
|
|
|
if(size > TIC_CODE_SIZE)
|
|
|
|
{
|
|
|
|
char buffer[256];
|
|
|
|
sprintf(buffer, "code is larger than %i symbols", TIC_CODE_SIZE);
|
|
|
|
onError(run, buffer);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2018-02-06 20:15:56 +01:00
|
|
|
else memcpy(dst, buffer, size);
|
2017-11-27 17:38:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char buffer[256];
|
|
|
|
sprintf(buffer, "dofile: file '%s' not found", filename);
|
|
|
|
onError(run, buffer);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-12-07 15:45:29 +01:00
|
|
|
static void preseed()
|
|
|
|
{
|
|
|
|
#if defined(__MACOSX__)
|
|
|
|
srandom(time(NULL));
|
|
|
|
random();
|
|
|
|
#else
|
|
|
|
srand(time(NULL));
|
|
|
|
rand();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-12-12 11:46:05 +01:00
|
|
|
static bool forceExit(void* data)
|
2017-12-12 10:50:39 +01:00
|
|
|
{
|
2017-12-12 11:46:05 +01:00
|
|
|
return getStudioMode() != TIC_RUN_MODE;
|
2017-12-12 10:50:39 +01:00
|
|
|
}
|
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
void initRun(Run* run, Console* console, tic_mem* tic)
|
|
|
|
{
|
|
|
|
*run = (Run)
|
|
|
|
{
|
|
|
|
.tic = tic,
|
|
|
|
.console = console,
|
|
|
|
.tick = tick,
|
|
|
|
.exit = false,
|
|
|
|
.tickData =
|
|
|
|
{
|
|
|
|
.error = onError,
|
|
|
|
.trace = onTrace,
|
2018-02-06 20:15:56 +01:00
|
|
|
.counter = getPerformanceCounter,
|
|
|
|
.freq = getPerformanceFrequency,
|
2017-09-26 08:59:34 +02:00
|
|
|
.start = 0,
|
|
|
|
.data = run,
|
|
|
|
.exit = onExit,
|
2017-11-27 17:38:10 +01:00
|
|
|
.preprocessor = processDoFile,
|
2017-12-12 11:46:05 +01:00
|
|
|
.forceExit = forceExit,
|
2017-09-26 08:59:34 +02:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
{
|
|
|
|
enum {Size = sizeof(tic_persistent)};
|
2018-02-06 20:15:56 +01:00
|
|
|
memset(&run->tic->persistent, 0, Size);
|
2017-12-27 10:51:13 +01:00
|
|
|
|
|
|
|
initPMemName(run);
|
2017-09-26 08:59:34 +02:00
|
|
|
|
|
|
|
s32 size = 0;
|
2017-12-27 10:51:13 +01:00
|
|
|
void* data = fsLoadRootFile(run->console->fs, run->saveid, &size);
|
|
|
|
|
|
|
|
if(size > Size) size = Size;
|
2017-09-26 08:59:34 +02:00
|
|
|
|
2017-12-27 10:51:13 +01:00
|
|
|
if(data)
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
2018-02-06 20:15:56 +01:00
|
|
|
memcpy(&run->tic->persistent, data, size);
|
|
|
|
memcpy(&run->persistent, data, size);
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
2018-02-06 20:15:56 +01:00
|
|
|
if(data) free(data);
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
2017-12-07 15:45:29 +01:00
|
|
|
|
|
|
|
preseed();
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|