From 52ffd5b521fcc53f221c000b41e1964004dcf78e Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 13 Nov 2016 13:15:01 +0000 Subject: [PATCH] Reinstate support for title sequence folders --- src/core/FileScanner.cpp | 7 ++ src/core/FileScanner.h | 1 + src/core/Path.cpp | 10 +++ src/core/Path.hpp | 1 + src/title/TitleSequence.cpp | 136 +++++++++++++++++++++++------ src/title/TitleSequence.h | 6 ++ src/title/TitleSequenceManager.cpp | 23 +++-- src/title/TitleSequenceManager.h | 1 + 8 files changed, 151 insertions(+), 34 deletions(-) diff --git a/src/core/FileScanner.cpp b/src/core/FileScanner.cpp index 1f6b6d8ecb..e5cdc3a933 100644 --- a/src/core/FileScanner.cpp +++ b/src/core/FileScanner.cpp @@ -124,6 +124,12 @@ public: return _currentPath; } + const utf8 * GetPathRelative() const override + { + // +1 to remove the path separator + return _currentPath + String::SizeOf(_rootPath) + 1; + } + void Reset() override { _started = false; @@ -155,6 +161,7 @@ public: utf8 childPath[MAX_PATH]; String::Set(childPath, sizeof(childPath), state->Path.c_str()); Path::Append(childPath, sizeof(childPath), child->Name.c_str()); + PushState(childPath); } else if (PatternMatch(child->Name.c_str())) diff --git a/src/core/FileScanner.h b/src/core/FileScanner.h index c7fd41cad9..54d525eeef 100644 --- a/src/core/FileScanner.h +++ b/src/core/FileScanner.h @@ -31,6 +31,7 @@ interface IFileScanner virtual const FileInfo * GetFileInfo() const abstract; virtual const utf8 * GetPath() const abstract; + virtual const utf8 * GetPathRelative() const abstract; virtual void Reset() abstract; virtual bool Next() abstract; diff --git a/src/core/Path.cpp b/src/core/Path.cpp index ad729785c1..d36c4bd4ee 100644 --- a/src/core/Path.cpp +++ b/src/core/Path.cpp @@ -34,6 +34,16 @@ namespace Path return safe_strcat_path(buffer, src, bufferSize); } + utf8 * GetDirectory(const utf8 * path) + { + size_t maxSize = String::SizeOf(path) + 1; + utf8 * result = Memory::Allocate(maxSize); + GetDirectory(result, maxSize, path); + size_t reducedSize = String::SizeOf(path) + 1; + result = Memory::Reallocate(result, reducedSize); + return result; + } + utf8 * GetDirectory(utf8 * buffer, size_t bufferSize, const utf8 * path) { size_t lastPathSepIndex = String::LastIndexOf(path, *PATH_SEPARATOR); diff --git a/src/core/Path.hpp b/src/core/Path.hpp index ef0ca98fc6..9d72aef2d2 100644 --- a/src/core/Path.hpp +++ b/src/core/Path.hpp @@ -24,6 +24,7 @@ extern "C" namespace Path { utf8 * Append(utf8 * buffer, size_t bufferSize, const utf8 * src); + utf8 * GetDirectory(const utf8 * path); utf8 * GetDirectory(utf8 * buffer, size_t bufferSize, const utf8 * path); const utf8 * GetFileName(const utf8 * path); utf8 * GetFileNameWithoutExtension(const utf8 * path); diff --git a/src/title/TitleSequence.cpp b/src/title/TitleSequence.cpp index d211756a7b..b097794015 100644 --- a/src/title/TitleSequence.cpp +++ b/src/title/TitleSequence.cpp @@ -20,6 +20,8 @@ #include #include "../core/Collections.hpp" #include "../core/Console.hpp" +#include "../core/FileScanner.h" +#include "../core/FileStream.hpp" #include "../core/Guard.hpp" #include "../core/Math.hpp" #include "../core/Memory.hpp" @@ -27,34 +29,61 @@ #include "../core/String.hpp" #include "TitleSequence.h" +static std::vector GetSaves(const utf8 * path); static std::vector GetSaves(zip_t * zip); static std::vector LegacyScriptRead(utf8 * script, size_t scriptLength, std::vector saves); static void LegacyScriptGetLine(SDL_RWops * file, char * parts); +static void * ReadScriptFile(const utf8 * path, size_t * outSize); static void * GetZipFileData(zip_t * zip, const char * name, size_t * outSize); extern "C" { TitleSequence * LoadTitleSequence(const utf8 * path) { - int error; - zip_t * zip = zip_open(path, ZIP_RDONLY, &error); - if (zip == nullptr) - { - Console::Error::WriteLine("Unable to open '%s'", path); - return nullptr; - } - size_t scriptLength; - char * script = (char *)GetZipFileData(zip, "script.txt", &scriptLength); - if (script == nullptr) - { - Console::Error::WriteLine("Unable to open script.txt in '%s'", path); + char * script; + std::vector saves; + bool isZip; - zip_close(zip); - return nullptr; + const utf8 * ext = Path::GetExtension(path); + if (String::Equals(ext, TITLE_SEQUENCE_EXTENSION)) + { + int error; + zip_t * zip = zip_open(path, ZIP_RDONLY, &error); + if (zip == nullptr) + { + Console::Error::WriteLine("Unable to open '%s'", path); + return nullptr; + } + + script = (char *)GetZipFileData(zip, "script.txt", &scriptLength); + if (script == nullptr) + { + Console::Error::WriteLine("Unable to open script.txt in '%s'", path); + + zip_close(zip); + return nullptr; + } + + saves = GetSaves(zip); + isZip = true; + } + else + { + utf8 scriptPath[260]; + String::Set(scriptPath, sizeof(scriptPath), path); + Path::Append(scriptPath, sizeof(scriptPath), "script.txt"); + script = (char *)ReadScriptFile(scriptPath, &scriptLength); + if (script == nullptr) + { + Console::Error::WriteLine("Unable to open '%s'", scriptPath); + return nullptr; + } + + saves = GetSaves(path); + isZip = false; } - std::vector saves = GetSaves(zip); std::vector commands = LegacyScriptRead(script, scriptLength, saves); TitleSequence * seq = Memory::Allocate(); @@ -64,6 +93,7 @@ extern "C" seq->Saves = Collections::ToArray(saves); seq->NumCommands = commands.size(); seq->Commands = Collections::ToArray(commands); + seq->IsZip = isZip; return seq; } @@ -85,18 +115,30 @@ extern "C" TitleSequenceParkHandle * TitleSequenceGetParkHandle(TitleSequence * seq, size_t index) { TitleSequenceParkHandle * handle = nullptr; - - int error; - zip_t * zip = zip_open(seq->Path, ZIP_RDONLY, &error); - if (zip != nullptr) + if (index <= seq->NumSaves) { - if (index <= seq->NumSaves) + const utf8 * filename = seq->Saves[index]; + if (seq->IsZip) { - utf8 * filename = seq->Saves[index]; + int error; + zip_t * zip = zip_open(seq->Path, ZIP_RDONLY, &error); + if (zip != nullptr) + { + handle = Memory::Allocate(); + handle->Data = GetZipFileData(zip, filename, &handle->DataSize); + handle->RWOps = SDL_RWFromMem(handle->Data, (int)handle->DataSize); + handle->IsScenario = String::Equals(Path::GetExtension(filename), ".sc6", true); + } + } + else + { + utf8 absolutePath[260]; + String::Set(absolutePath, sizeof(absolutePath), seq->Path); + Path::Append(absolutePath, sizeof(absolutePath), filename); handle = Memory::Allocate(); - handle->Data = GetZipFileData(zip, filename, &handle->DataSize); - handle->RWOps = SDL_RWFromMem(handle->Data, (int)handle->DataSize); + handle->Data = nullptr; + handle->RWOps = SDL_RWFromFile(absolutePath, "rb"); handle->IsScenario = String::Equals(Path::GetExtension(filename), ".sc6", true); } } @@ -105,12 +147,32 @@ extern "C" void TitleSequenceCloseParkHandle(TitleSequenceParkHandle * handle) { - SDL_RWclose(handle->RWOps); - Memory::Free(handle->Data); - Memory::Free(handle); + if (handle != nullptr) + { + SDL_RWclose(handle->RWOps); + Memory::Free(handle->Data); + Memory::Free(handle); + } } } +static std::vector GetSaves(const utf8 * directory) +{ + std::vector saves; + + utf8 pattern[260]; + String::Set(pattern, sizeof(pattern), directory); + Path::Append(pattern, sizeof(pattern), "*.sc6;*.sv6"); + + IFileScanner * scanner = Path::ScanDirectory(pattern, true); + while (scanner->Next()) + { + const utf8 * path = scanner->GetPathRelative(); + saves.push_back(String::Duplicate(path)); + } + return saves; +} + static std::vector GetSaves(zip_t * zip) { std::vector saves; @@ -270,6 +332,28 @@ static void LegacyScriptGetLine(SDL_RWops * file, char * parts) } } +static void * ReadScriptFile(const utf8 * path, size_t * outSize) +{ + void * buffer = nullptr; + size_t size = 0; + try + { + auto fs = FileStream(path, FILE_MODE_OPEN); + size = (size_t)fs.GetLength(); + buffer = Memory::Allocate(size); + fs.Read(buffer, size); + } + catch (Exception) + { + Memory::Free(buffer); + buffer = nullptr; + size = 0; + } + + *outSize = size; + return buffer; +} + static void * GetZipFileData(zip_t * zip, const char * name, size_t * outSize) { void * data = nullptr; diff --git a/src/title/TitleSequence.h b/src/title/TitleSequence.h index ff29b50343..b2843ba278 100644 --- a/src/title/TitleSequence.h +++ b/src/title/TitleSequence.h @@ -47,6 +47,8 @@ typedef struct TitleSequence size_t NumSaves; utf8 * * Saves; + + bool IsZip; } TitleSequence; typedef struct TitleSequenceParkHandle @@ -74,6 +76,10 @@ enum TITLE_SCRIPT TITLE_SCRIPT_LOADRCT1, }; +#ifdef __cplusplus +constexpr const utf8 * TITLE_SEQUENCE_EXTENSION = ".parkseq"; +#endif + #ifdef __cplusplus extern "C" { diff --git a/src/title/TitleSequenceManager.cpp b/src/title/TitleSequenceManager.cpp index 0cc6304992..b8b2d84925 100644 --- a/src/title/TitleSequenceManager.cpp +++ b/src/title/TitleSequenceManager.cpp @@ -50,7 +50,7 @@ namespace TitleSequenceManager std::vector _items; static void Scan(const utf8 * directory); - static std::string GetNameFromSequencePath(const utf8 * path); + static std::string GetNameFromSequencePath(const std::string &path); static void GetDataSequencesPath(utf8 * buffer, size_t bufferSize); static void GetUserSequencesPath(utf8 * buffer, size_t bufferSize); @@ -64,9 +64,9 @@ namespace TitleSequenceManager return &_items[i]; } - static const uint16 GetPredefinedIndex(const utf8 * path) + static const uint16 GetPredefinedIndex(const std::string &path) { - const utf8 * filename = Path::GetFileName(path); + const utf8 * filename = Path::GetFileName(path.c_str()); for (uint16 i = 0; i < Util::CountOf(PredefinedSequences); i++) { if (String::Equals(filename, PredefinedSequences[i].Filename, true)) @@ -111,16 +111,22 @@ namespace TitleSequenceManager { utf8 pattern[MAX_PATH]; String::Set(pattern, sizeof(pattern), directory); - Path::Append(pattern, sizeof(pattern), "*.parkseq"); + Path::Append(pattern, sizeof(pattern), "script.txt;*.parkseq"); IFileScanner * fileScanner = Path::ScanDirectory(pattern, true); while (fileScanner->Next()) { - const utf8 * path = fileScanner->GetPath(); + std::string path = std::string(fileScanner->GetPath()); + bool isZip = true; + if (String::Equals(Path::GetExtension(path.c_str()), ".txt", true)) + { + path = std::string(Path::GetDirectory(path.c_str())); + isZip = false; + } TitleSequenceManagerItem item; item.PredefinedIndex = GetPredefinedIndex(path); - item.Path = std::string(path); + item.Path = path; if (item.PredefinedIndex != PREDEFINED_INDEX_CUSTOM) { rct_string_id stringId = PredefinedSequences[item.PredefinedIndex].StringId; @@ -130,14 +136,15 @@ namespace TitleSequenceManager { item.Name = GetNameFromSequencePath(path); } + item.IsZip = isZip; _items.push_back(item); } delete fileScanner; } - static std::string GetNameFromSequencePath(const utf8 * path) + static std::string GetNameFromSequencePath(const std::string &path) { - utf8 * name = Path::GetFileNameWithoutExtension(path); + utf8 * name = Path::GetFileNameWithoutExtension(path.c_str()); std::string result = std::string(name); Memory::Free(name); return result; diff --git a/src/title/TitleSequenceManager.h b/src/title/TitleSequenceManager.h index 005c016a56..3841b5fb3e 100644 --- a/src/title/TitleSequenceManager.h +++ b/src/title/TitleSequenceManager.h @@ -27,6 +27,7 @@ struct TitleSequenceManagerItem std::string Name; std::string Path; uint16 PredefinedIndex; + bool IsZip; }; namespace TitleSequenceManager