refactor and format old C++ code

This commit is contained in:
IntelOrca 2016-01-23 18:58:31 +00:00
parent 36a4cd2fa0
commit 4c1605f268
15 changed files with 1107 additions and 864 deletions

View File

@ -1,19 +1,24 @@
#pragma once
#include <exception>
#include "../common.h"
class Exception : public std::exception {
#include <exception>
class Exception : public std::exception
{
public:
Exception() : std::exception() { }
Exception(const char *message) : std::exception() {
Exception() : Exception(nullptr) { }
Exception(const char * message) : std::exception()
{
_message = message;
}
virtual ~Exception() { }
const char *what() const throw() override { return _message; }
const char *GetMessage() const { return _message; }
const char * what() const throw() override { return _message; }
const char * GetMessage() const { return _message; }
private:
const char *_message;
const char * _message;
};

View File

@ -1,10 +1,12 @@
#pragma once
#include <SDL.h>
#include "../common.h"
#include <SDL.h>
#include "IStream.hpp"
enum {
enum
{
FILE_MODE_OPEN,
FILE_MODE_WRITE
};
@ -12,16 +14,18 @@ enum {
/**
* A stream for reading and writing to files. Wraps an SDL_RWops, SDL2's cross platform file stream.
*/
class FileStream : public IStream {
class FileStream : public IStream
{
private:
SDL_RWops *_file;
SDL_RWops * _file;
bool _canRead;
bool _canWrite;
bool _disposed;
public:
FileStream(const utf8 *path, int fileMode) {
const char *mode;
FileStream(const utf8 * path, int fileMode)
{
const char * mode;
switch (fileMode) {
case FILE_MODE_OPEN:
mode = "rb";
@ -38,19 +42,23 @@ public:
}
_file = SDL_RWFromFile(path, mode);
if (_file == NULL) {
if (_file == nullptr)
{
throw IOException(SDL_GetError());
}
_disposed = false;
}
~FileStream() {
~FileStream()
{
Dispose();
}
void Dispose() override {
if (!_disposed) {
void Dispose() override
{
if (!_disposed)
{
_disposed = true;
SDL_RWclose(_file);
}
@ -59,14 +67,16 @@ public:
bool CanRead() const override { return _canRead; }
bool CanWrite() const override { return _canWrite; }
sint64 GetLength() const override { return SDL_RWsize(_file); }
sint64 GetPosition() const override { return SDL_RWtell(_file); }
uint64 GetLength() const override { return SDL_RWsize(_file); }
uint64 GetPosition() const override { return SDL_RWtell(_file); }
void SetPosition(sint64 position) override {
void SetPosition(uint64 position) override
{
Seek(position, STREAM_SEEK_BEGIN);
}
void Seek(sint64 offset, int origin) override {
void Seek(sint64 offset, int origin) override
{
switch (origin) {
case STREAM_SEEK_BEGIN:
SDL_RWseek(_file, offset, RW_SEEK_SET);
@ -80,14 +90,18 @@ public:
}
}
void Read(void *buffer, int length) override {
if (SDL_RWread(_file, buffer, length, 1) != 1) {
void Read(void * buffer, uint64 length) override
{
if (SDL_RWread(_file, buffer, (size_t)length, 1) != 1)
{
throw IOException("Attempted to read past end of file.");
}
}
void Write(const void *buffer, int length) override {
if (SDL_RWwrite(_file, buffer, length, 1) != 1) {
void Write(const void * buffer, uint64 length) override
{
if (SDL_RWwrite(_file, buffer, (size_t)length, 1) != 1)
{
throw IOException("Unable to write to file.");
}
}

View File

@ -5,6 +5,7 @@
/**
* Represents an object that can be disposed. So things can explicitly close resources before the destructor kicks in.
*/
interface IDisposable {
interface IDisposable
{
virtual void Dispose() abstract;
};

View File

@ -1,6 +1,7 @@
#pragma once
#include "../common.h"
#include "Exception.hpp"
#include "IDisposable.hpp"
@ -13,7 +14,8 @@ enum {
/**
* Represents a stream that can be read or written to. Implemented by types such as FileStream, NetworkStream or MemoryStream.
*/
interface IStream : public IDisposable {
interface IStream : public IDisposable
{
///////////////////////////////////////////////////////////////////////////
// Interface methods
///////////////////////////////////////////////////////////////////////////
@ -22,13 +24,13 @@ interface IStream : public IDisposable {
virtual bool CanRead() const abstract;
virtual bool CanWrite() const abstract;
virtual sint64 GetLength() const abstract;
virtual sint64 GetPosition() const abstract;
virtual void SetPosition(sint64 position) abstract;
virtual uint64 GetLength() const abstract;
virtual uint64 GetPosition() const abstract;
virtual void SetPosition(uint64 position) abstract;
virtual void Seek(sint64 offset, int origin) abstract;
virtual void Read(void *buffer, int length) abstract;
virtual void Write(const void *buffer, int length) abstract;
virtual void Read(void * buffer, uint64 length) abstract;
virtual void Write(const void * buffer, uint64 length) abstract;
///////////////////////////////////////////////////////////////////////////
// Helper methods
@ -38,7 +40,8 @@ interface IStream : public IDisposable {
* Reads the size of the given type from the stream directly into the given address.
*/
template<typename T>
void Read(T *value) {
void Read(T * value)
{
Read(value, sizeof(T));
}
@ -46,7 +49,8 @@ interface IStream : public IDisposable {
* Writes the size of the given type to the stream directly from the given address.
*/
template<typename T>
void Write(const T *value) {
void Write(const T * value)
{
Write(value, sizeof(T));
}
@ -54,7 +58,8 @@ interface IStream : public IDisposable {
* Reads the given type from the stream. Use this only for small types (e.g. sint8, sint64, double)
*/
template<typename T>
T ReadValue() {
T ReadValue()
{
T buffer;
Read(&buffer);
return buffer;
@ -64,12 +69,14 @@ interface IStream : public IDisposable {
* Writes the given type to the stream. Use this only for small types (e.g. sint8, sint64, double)
*/
template<typename T>
void WriteValue(const T value) {
void WriteValue(const T value)
{
Write(&value);
}
};
class IOException : public Exception {
class IOException : public Exception
{
public:
IOException(const char *message) : Exception(message) { }
IOException(const char * message) : Exception(message) { }
};

View File

@ -5,21 +5,23 @@
/**
* Common mathematical functions.
*/
namespace Math {
namespace Math
{
template<typename T>
T Min(T a, T b) {
T Min(T a, T b)
{
return (std::min)(a, b);
}
template<typename T>
T Max(T a, T b) {
T Max(T a, T b)
{
return (std::max)(a, b);
}
template<typename T>
T Clamp(T low, T x, T high) {
T Clamp(T low, T x, T high)
{
return (std::min)((std::max)(low, x), high);
}
}

View File

@ -1,70 +1,96 @@
#pragma once
extern "C" {
#include "../common.h"
extern "C"
{
#include "../common.h"
}
/**
* Utility methods for memory management. Typically helpers and wrappers around the C standard library.
*/
namespace Memory {
namespace Memory
{
template<typename T>
T *Allocate() {
T * Allocate()
{
return (T*)malloc(sizeof(T));
}
template<typename T>
T *Allocate(size_t size) {
T * Allocate(size_t size)
{
return (T*)malloc(size);
}
template<typename T>
T *AllocateArray(size_t count) {
T * AllocateArray(size_t count)
{
return (T*)malloc(count * sizeof(T));
}
template<typename T>
T *Reallocate(T *ptr, size_t size) {
T * Reallocate(T * ptr, size_t size)
{
if (ptr == NULL)
{
return (T*)malloc(size);
}
else
{
return (T*)realloc((void*)ptr, size);
}
template<typename T>
T *ReallocateArray(T *ptr, size_t count) {
if (ptr == NULL)
return (T*)malloc(count * sizeof(T));
else
return (T*)realloc((void*)ptr, count * sizeof(T));
}
template<typename T>
void Free(T *ptr) {
T * ReallocateArray(T * ptr, size_t count)
{
if (ptr == NULL)
{
return (T*)malloc(count * sizeof(T));
}
else
{
return (T*)realloc((void*)ptr, count * sizeof(T));
}
}
template<typename T>
void Free(T * ptr)
{
free((void*)ptr);
}
template<typename T>
T *Copy(T *dst, const T *src, size_t size) {
T * Copy(T * dst, const T * src, size_t size)
{
if (size == 0) return (T*)dst;
return (T*)memcpy((void*)dst, (const void*)src, size);
}
template<typename T>
T *CopyArray(T *dst, const T *src, size_t count) {
T * CopyArray(T *dst, const T * src, size_t count)
{
if (count == 0) return (T*)dst;
return (T*)memcpy((void*)dst, (const void*)src, count * sizeof(T));
}
template<typename T>
T *Duplicate(const T *src, size_t size) {
T * Duplicate(const T * src, size_t size)
{
T *result = Allocate<T>(size);
return Copy(result, src, size);
}
template<typename T>
T *DuplicateArray(const T *src, size_t count) {
T * DuplicateArray(const T * src, size_t count)
{
T *result = AllocateArray<T>(count);
return CopyArray(result, src, count);
}
template<typename T>
T * Set(T * dst, uint8 value, size_t size)
{
return (T*)memset((void*)dst, (int)value, size);
}
}

View File

@ -9,7 +9,7 @@ Stopwatch::Stopwatch()
Reset();
}
uint64 Stopwatch::GetElapsedTicks()
uint64 Stopwatch::GetElapsedTicks() const
{
uint64 result = _total;
if (_isRunning)
@ -23,7 +23,7 @@ uint64 Stopwatch::GetElapsedTicks()
return _total;
}
uint64 Stopwatch::GetElapsedMilliseconds()
uint64 Stopwatch::GetElapsedMilliseconds() const
{
if (Frequency == 0)
{
@ -65,7 +65,8 @@ void Stopwatch::Restart()
void Stopwatch::Stop()
{
uint64 ticks = QueryCurrentTicks();
if (ticks != 0) {
if (ticks != 0)
{
_total += QueryCurrentTicks() - _last;
}
_isRunning = false;
@ -81,52 +82,53 @@ uint64 Stopwatch::QueryCurrentTicks()
return SDL_GetPerformanceCounter();
}
extern "C" {
extern "C"
{
#include "stopwatch.h"
void stopwatch_create(stopwatch *stopwatch)
void stopwatch_create(stopwatch * stopwatch)
{
stopwatch->context = new Stopwatch();
}
void stopwatch_dispose(stopwatch *stopwatch)
void stopwatch_dispose(stopwatch * stopwatch)
{
delete ((Stopwatch*)stopwatch->context);
}
uint64 stopwatch_GetElapsedTicks(stopwatch *stopwatch)
uint64 stopwatch_GetElapsedTicks(stopwatch * stopwatch)
{
Stopwatch *ctx = (Stopwatch*)stopwatch->context;
Stopwatch * ctx = (Stopwatch*)stopwatch->context;
return ctx->GetElapsedTicks();
}
uint64 stopwatch_GetElapsedMilliseconds(stopwatch *stopwatch)
uint64 stopwatch_GetElapsedMilliseconds(stopwatch * stopwatch)
{
Stopwatch *ctx = (Stopwatch*)stopwatch->context;
Stopwatch * ctx = (Stopwatch*)stopwatch->context;
return ctx->GetElapsedMilliseconds();
}
void stopwatch_Reset(stopwatch *stopwatch)
void stopwatch_Reset(stopwatch * stopwatch)
{
Stopwatch *ctx = (Stopwatch*)stopwatch->context;
Stopwatch * ctx = (Stopwatch*)stopwatch->context;
return ctx->Reset();
}
void stopwatch_Start(stopwatch *stopwatch)
void stopwatch_Start(stopwatch * stopwatch)
{
Stopwatch *ctx = (Stopwatch*)stopwatch->context;
Stopwatch * ctx = (Stopwatch*)stopwatch->context;
return ctx->Start();
}
void stopwatch_Restart(stopwatch *stopwatch)
void stopwatch_Restart(stopwatch * stopwatch)
{
Stopwatch *ctx = (Stopwatch*)stopwatch->context;
Stopwatch * ctx = (Stopwatch*)stopwatch->context;
return ctx->Restart();
}
void stopwatch_Stop(stopwatch *stopwatch)
void stopwatch_Stop(stopwatch * stopwatch)
{
Stopwatch *ctx = (Stopwatch*)stopwatch->context;
Stopwatch * ctx = (Stopwatch*)stopwatch->context;
return ctx->Stop();
}
}

View File

@ -1,7 +1,8 @@
#pragma once
extern "C" {
#include "../common.h"
extern "C"
{
#include "../common.h"
}
/**
@ -21,12 +22,12 @@ private:
static uint64 QueryCurrentTicks();
public:
bool IsRunning() { return _isRunning; }
bool IsRunning() const { return _isRunning; }
Stopwatch();
uint64 GetElapsedTicks();
uint64 GetElapsedMilliseconds();
uint64 GetElapsedTicks() const;
uint64 GetElapsedMilliseconds() const;
void Reset();
void Start();

View File

@ -141,4 +141,38 @@ namespace String
{
return DiscardUse(ptr, String::Duplicate(replacement));
}
utf8 * SkipBOM(utf8 * buffer)
{
return (utf8*)SkipBOM(buffer);
}
const utf8 * SkipBOM(const utf8 * buffer)
{
if (buffer[0] == 0xEF && buffer[1] == 0xBB && buffer[2] == 0xBF)
{
return buffer + 3;
}
return buffer;
}
size_t GetCodepointLength(codepoint_t codepoint)
{
return utf8_get_codepoint_length(codepoint);
}
codepoint_t GetNextCodepoint(utf8 * ptr, utf8 * * nextPtr)
{
return GetNextCodepoint((const utf8 *)ptr, (const utf8 * *)nextPtr);
}
codepoint_t GetNextCodepoint(const utf8 * ptr, const utf8 * * nextPtr)
{
return utf8_get_next(ptr, nextPtr);
}
utf8 * WriteCodepoint(utf8 * dst, codepoint_t codepoint)
{
return utf8_write_codepoint(dst, codepoint);
}
}

View File

@ -9,8 +9,17 @@ namespace String
{
bool Equals(const utf8 * a, const utf8 * b, bool ignoreCase = false);
bool StartsWith(const utf8 * str, const utf8 * match, bool ignoreCase = false);
/**
* Gets the length of the given string in codepoints.
*/
size_t LengthOf(const utf8 * str);
/**
* Gets the size of the given string in bytes excluding the null terminator.
*/
size_t SizeOf(const utf8 * str);
utf8 * Set(utf8 * buffer, size_t bufferSize, const utf8 * src);
utf8 * Set(utf8 * buffer, size_t bufferSize, const utf8 * src, size_t srcSize);
utf8 * Append(utf8 * buffer, size_t bufferSize, const utf8 * src);
@ -27,4 +36,12 @@ namespace String
* Helper method to free the string a string pointer points to and set it to a copy of a replacement string.
*/
utf8 * DiscardDuplicate(utf8 * * ptr, utf8 * replacement);
utf8 * SkipBOM(utf8 * buffer);
const utf8 * SkipBOM(const utf8 * buffer);
size_t GetCodepointLength(codepoint_t codepoint);
codepoint_t GetNextCodepoint(utf8 * ptr, utf8 * * nextPtr = nullptr);
codepoint_t GetNextCodepoint(const utf8 * ptr, const utf8 * * nextPtr = nullptr);
utf8 * WriteCodepoint(utf8 * dst, codepoint_t codepoint);
}

View File

@ -1,37 +1,49 @@
#pragma once
#include "../common.h"
#include "../localisation/localisation.h"
#include "Math.hpp"
#include "Memory.hpp"
#include "String.hpp"
/**
* Class for constructing strings efficiently. A buffer is automatically allocated and reallocated when characters or strings
* are appended. Use GetString to copy the current state of the string builder to a new fire-and-forget string.
*/
class StringBuilder final {
class StringBuilder final
{
public:
StringBuilder() {
_buffer = NULL;
StringBuilder()
{
_buffer = nullptr;
_capacity = 0;
_length = 0;
}
StringBuilder(int capacity) : StringBuilder() {
StringBuilder(size_t capacity) : StringBuilder()
{
EnsureCapacity(capacity);
}
~StringBuilder() {
if (_buffer != NULL) Memory::Free(_buffer);
~StringBuilder()
{
Memory::Free(_buffer);
}
void Append(int codepoint)
{
Append((codepoint_t)codepoint);
}
/**
* Appends the given character to the current string.
*/
void Append(int codepoint) {
int codepointLength = utf8_get_codepoint_length(codepoint);
void Append(codepoint_t codepoint)
{
codepoint_t codepointLength = String::GetCodepointLength(codepoint);
EnsureCapacity(_length + codepointLength + 1);
utf8_write_codepoint(_buffer + _length, codepoint);
String::WriteCodepoint(_buffer + _length, codepoint);
_length += codepointLength;
_buffer[_length] = 0;
}
@ -39,8 +51,9 @@ public:
/**
* Appends the given string to the current string.
*/
void Append(const utf8 *text) {
int textLength = strlen(text);
void Append(const utf8 * text)
{
size_t textLength = String::SizeOf(text);
Append(text, textLength);
}
@ -50,7 +63,8 @@ public:
* @param text Pointer to the UTF-8 text to append.
* @param textLength Number of bytes to copy. (Can be used to append single bytes rather than codepoints)
*/
void Append(const utf8 *text, int textLength) {
void Append(const utf8 * text, size_t textLength)
{
EnsureCapacity(_length + textLength + 1);
Memory::Copy(_buffer + _length, text, textLength);
_length += textLength;
@ -60,16 +74,19 @@ public:
/**
* Appends the string of a given StringBuilder to the current string.
*/
void Append(const StringBuilder *sb) {
void Append(const StringBuilder * sb)
{
Append(sb->GetBuffer(), sb->GetLength());
}
/**
* Clears the current string, but preserves the allocated memory for another string.
*/
void Clear() {
void Clear()
{
_length = 0;
if (_capacity >= 1) {
if (_capacity >= 1)
{
_buffer[_length] = 0;
}
}
@ -77,20 +94,24 @@ public:
/**
* Like Clear, only will guarantee freeing of the underlying buffer.
*/
void Reset() {
void Reset()
{
_length = 0;
_capacity = 0;
if (_buffer != NULL) {
if (_buffer != nullptr)
{
Memory::Free(_buffer);
_buffer = nullptr;
}
}
/**
* Returns the current string buffer as a new fire-and-forget string.
*/
utf8 *GetString() const {
utf8 * GetString() const
{
// If buffer is null, length should be 0 which will create a new one byte memory block containing a null terminator
utf8 *result = Memory::AllocateArray<utf8>(_length + 1);
utf8 * result = Memory::AllocateArray<utf8>(_length + 1);
Memory::CopyArray(result, _buffer, _length);
result[_length] = 0;
return result;
@ -100,9 +121,10 @@ public:
* Gets the current state of the StringBuilder. Warning: this represents the StringBuilder's current working buffer and will
* be deallocated when the StringBuilder is destructed.
*/
const utf8 *GetBuffer() const {
const utf8 * GetBuffer() const
{
// buffer may be null, so return an immutable empty string
if (_buffer == NULL) return "";
if (_buffer == nullptr) return "";
return _buffer;
}
@ -117,7 +139,7 @@ public:
size_t GetLength() const { return _length; }
private:
utf8 *_buffer;
utf8 * _buffer;
size_t _capacity;
size_t _length;
@ -126,7 +148,8 @@ private:
if (_capacity > capacity) return;
_capacity = Math::Max((size_t)8, _capacity);
while (_capacity < capacity) {
while (_capacity < capacity)
{
_capacity *= 2;
}

View File

@ -3,53 +3,59 @@
#include "../common.h"
#include "../localisation/localisation.h"
#include "../util/util.h"
#include "String.hpp"
interface IStringReader {
virtual bool TryPeek(int *outCodepoint) abstract;
virtual bool TryRead(int *outCodepoint) abstract;
interface IStringReader
{
virtual bool TryPeek(codepoint_t * outCodepoint) abstract;
virtual bool TryRead(codepoint_t * outCodepoint) abstract;
virtual void Skip() abstract;
virtual bool CanRead() const abstract;
};
class UTF8StringReader final : public IStringReader {
class UTF8StringReader final : public IStringReader
{
public:
UTF8StringReader(const utf8 *text) {
// Skip UTF-8 byte order mark
if (strlen(text) >= 3 && utf8_is_bom(text)) {
text += 3;
}
UTF8StringReader(const utf8 * text)
{
text = String::SkipBOM(text);
_text = text;
_current = text;
}
bool TryPeek(int *outCodepoint) override {
if (_current == NULL) return false;
bool TryPeek(codepoint_t * outCodepoint) override
{
if (_current == nullptr) return false;
int codepoint = utf8_get_next(_current, NULL);
codepoint_t codepoint = String::GetNextCodepoint(_current);
*outCodepoint = codepoint;
return true;
}
bool TryRead(int *outCodepoint) override {
if (_current == NULL) return false;
bool TryRead(codepoint_t * outCodepoint) override
{
if (_current == nullptr) return false;
int codepoint = utf8_get_next(_current, &_current);
codepoint_t codepoint = String::GetNextCodepoint(_current, &_current);
*outCodepoint = codepoint;
if (codepoint == 0) {
_current = NULL;
if (codepoint == 0)
{
_current = nullptr;
return false;
}
return true;
}
void Skip() override {
int codepoint;
void Skip() override
{
codepoint_t codepoint;
TryRead(&codepoint);
}
bool CanRead() const override {
return _current != NULL;
bool CanRead() const override
{
return _current != nullptr;
}
private:

View File

@ -1,8 +1,9 @@
extern "C" {
extern "C"
{
#include "../common.h"
#include "../platform/platform.h"
#include "../util/util.h"
#include "localisation.h"
#include "../platform/platform.h"
}
#include "../core/FileStream.hpp"
@ -12,48 +13,55 @@ extern "C" {
#include "LanguagePack.h"
#include <SDL.h>
// Don't try to load more than language files that exceed 64 MiB
constexpr uint64 MAX_LANGUAGE_SIZE = 64 * 1024 * 1024;
constexpr rct_string_id ObjectOverrideBase = 0x6000;
constexpr int ObjectOverrideMaxStringCount = 4;
constexpr rct_string_id ScenarioOverrideBase = 0x7000;
constexpr int ScenarioOverrideMaxStringCount = 3;
LanguagePack *LanguagePack::FromFile(int id, const utf8 *path)
LanguagePack * LanguagePack::FromFile(uint16 id, const utf8 * path)
{
assert(path != nullptr);
uint32 fileLength;
utf8 *fileData = nullptr;
// Load file directly into memory
try {
utf8 * fileData = nullptr;
try
{
FileStream fs = FileStream(path, FILE_MODE_OPEN);
fileLength = (uint32)fs.GetLength();
size_t fileLength = (size_t)fs.GetLength();
if (fileLength > MAX_LANGUAGE_SIZE)
{
throw IOException("Language file too large.");
}
fileData = Memory::Allocate<utf8>(fileLength + 1);
fs.Read(fileData, fileLength);
fileData[fileLength] = '\0';
fs.Dispose();
} catch (Exception ex) {
}
catch (Exception ex)
{
Memory::Free(fileData);
log_error("Unable to open %s: %s", path, ex.GetMessage());
return nullptr;
}
// Parse the memory as text
LanguagePack *result = FromText(id, fileData);
LanguagePack * result = FromText(id, fileData);
Memory::Free(fileData);
return result;
}
LanguagePack *LanguagePack::FromText(int id, const utf8 *text)
LanguagePack * LanguagePack::FromText(uint16 id, const utf8 * text)
{
return new LanguagePack(id, text);
}
LanguagePack::LanguagePack(int id, const utf8 *text)
LanguagePack::LanguagePack(uint16 id, const utf8 * text)
{
assert(text != nullptr);
@ -64,29 +72,39 @@ LanguagePack::LanguagePack(int id, const utf8 *text)
_currentScenarioOverride = nullptr;
auto reader = UTF8StringReader(text);
while (reader.CanRead()) {
while (reader.CanRead())
{
ParseLine(&reader);
}
_stringData = _stringDataSB.GetString();
size_t stringDataBaseAddress = (size_t)_stringData;
for (size_t i = 0; i < _strings.size(); i++) {
for (size_t i = 0; i < _strings.size(); i++)
{
if (_strings[i] != nullptr)
{
_strings[i] = (utf8*)(stringDataBaseAddress + (size_t)_strings[i]);
}
for (size_t i = 0; i < _objectOverrides.size(); i++) {
for (int j = 0; j < ObjectOverrideMaxStringCount; j++) {
const utf8 **strPtr = &(_objectOverrides[i].strings[j]);
if (*strPtr != nullptr) {
}
for (size_t i = 0; i < _objectOverrides.size(); i++)
{
for (int j = 0; j < ObjectOverrideMaxStringCount; j++)
{
const utf8 * * strPtr = &(_objectOverrides[i].strings[j]);
if (*strPtr != nullptr)
{
*strPtr = (utf8*)(stringDataBaseAddress + (size_t)*strPtr);
}
}
}
for (size_t i = 0; i < _scenarioOverrides.size(); i++) {
for (int j = 0; j < ScenarioOverrideMaxStringCount; j++) {
for (size_t i = 0; i < _scenarioOverrides.size(); i++)
{
for (int j = 0; j < ScenarioOverrideMaxStringCount; j++)
{
const utf8 **strPtr = &(_scenarioOverrides[i].strings[j]);
if (*strPtr != nullptr) {
if (*strPtr != nullptr)
{
*strPtr = (utf8*)(stringDataBaseAddress + (size_t)*strPtr);
}
}
@ -98,49 +116,67 @@ LanguagePack::LanguagePack(int id, const utf8 *text)
LanguagePack::~LanguagePack()
{
SafeFree(_stringData);
SafeFree(_currentGroup);
Memory::Free(_stringData);
Memory::Free(_currentGroup);
}
const utf8 *LanguagePack::GetString(int stringId) const {
if (stringId >= ScenarioOverrideBase) {
const utf8 * LanguagePack::GetString(rct_string_id stringId) const
{
if (stringId >= ScenarioOverrideBase)
{
int offset = stringId - ScenarioOverrideBase;
int ooIndex = offset / ScenarioOverrideMaxStringCount;
int ooStringIndex = offset % ScenarioOverrideMaxStringCount;
if (_scenarioOverrides.size() > (size_t)ooIndex) {
if (_scenarioOverrides.size() > (size_t)ooIndex)
{
return _scenarioOverrides[ooIndex].strings[ooStringIndex];
} else {
}
else
{
return nullptr;
}
}else if (stringId >= ObjectOverrideBase) {
}
else if (stringId >= ObjectOverrideBase)
{
int offset = stringId - ObjectOverrideBase;
int ooIndex = offset / ObjectOverrideMaxStringCount;
int ooStringIndex = offset % ObjectOverrideMaxStringCount;
if (_objectOverrides.size() > (size_t)ooIndex) {
if (_objectOverrides.size() > (size_t)ooIndex)
{
return _objectOverrides[ooIndex].strings[ooStringIndex];
} else {
}
else
{
return nullptr;
}
} else {
if (_strings.size() > (size_t)stringId) {
}
else
{
if (_strings.size() > (size_t)stringId)
{
return _strings[stringId];
} else {
}
else
{
return nullptr;
}
}
}
rct_string_id LanguagePack::GetObjectOverrideStringId(const char *objectIdentifier, int index)
rct_string_id LanguagePack::GetObjectOverrideStringId(const char * objectIdentifier, uint8 index)
{
assert(objectIdentifier != nullptr);
assert(index < ObjectOverrideMaxStringCount);
int ooIndex = 0;
for (const ObjectOverride &objectOverride : _objectOverrides) {
if (strncmp(objectOverride.name, objectIdentifier, 8) == 0) {
if (objectOverride.strings[index] == nullptr) {
for (const ObjectOverride &objectOverride : _objectOverrides)
{
if (strncmp(objectOverride.name, objectIdentifier, 8) == 0)
{
if (objectOverride.strings[index] == nullptr)
{
return STR_NONE;
}
return ObjectOverrideBase + (ooIndex * ObjectOverrideMaxStringCount) + index;
@ -151,15 +187,18 @@ rct_string_id LanguagePack::GetObjectOverrideStringId(const char *objectIdentifi
return STR_NONE;
}
rct_string_id LanguagePack::GetScenarioOverrideStringId(const utf8 *scenarioFilename, int index)
rct_string_id LanguagePack::GetScenarioOverrideStringId(const utf8 * scenarioFilename, uint8 index)
{
assert(scenarioFilename != nullptr);
assert(index < ScenarioOverrideMaxStringCount);
int ooIndex = 0;
for (const ScenarioOverride &scenarioOverride : _scenarioOverrides) {
if (_stricmp(scenarioOverride.filename, scenarioFilename) == 0) {
if (scenarioOverride.strings[index] == nullptr) {
for (const ScenarioOverride &scenarioOverride : _scenarioOverrides)
{
if (_stricmp(scenarioOverride.filename, scenarioFilename) == 0)
{
if (scenarioOverride.strings[index] == nullptr)
{
return STR_NONE;
}
return ScenarioOverrideBase + (ooIndex * ScenarioOverrideMaxStringCount) + index;
@ -170,29 +209,33 @@ rct_string_id LanguagePack::GetScenarioOverrideStringId(const utf8 *scenarioFile
return STR_NONE;
}
LanguagePack::ObjectOverride *LanguagePack::GetObjectOverride(const char *objectIdentifier)
LanguagePack::ObjectOverride * LanguagePack::GetObjectOverride(const char * objectIdentifier)
{
assert(objectIdentifier != nullptr);
for (size_t i = 0; i < _objectOverrides.size(); i++) {
for (size_t i = 0; i < _objectOverrides.size(); i++)
{
ObjectOverride *oo = &_objectOverrides[i];
if (strncmp(oo->name, objectIdentifier, 8) == 0) {
if (strncmp(oo->name, objectIdentifier, 8) == 0)
{
return oo;
}
}
return nullptr;
}
LanguagePack::ScenarioOverride *LanguagePack::GetScenarioOverride(const utf8 *scenarioIdentifier)
LanguagePack::ScenarioOverride * LanguagePack::GetScenarioOverride(const utf8 * scenarioIdentifier)
{
assert(scenarioIdentifier != nullptr);
for (size_t i = 0; i < _scenarioOverrides.size(); i++) {
for (size_t i = 0; i < _scenarioOverrides.size(); i++)
{
ScenarioOverride *so = &_scenarioOverrides[i];
// At this point ScenarioOverrides were not yet rewritten to point at
// strings, but rather still hold offsets from base.
const utf8 *name = _stringDataSB.GetBuffer() + (size_t)so->name;
if (_stricmp(name, scenarioIdentifier) == 0) {
if (_stricmp(name, scenarioIdentifier) == 0)
{
return so;
}
}
@ -214,47 +257,58 @@ LanguagePack::ScenarioOverride *LanguagePack::GetScenarioOverride(const utf8 *sc
// Use # at the beginning of a line to leave a comment.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static bool IsWhitespace(int codepoint)
static bool IsWhitespace(codepoint_t codepoint)
{
return codepoint == '\t' || codepoint == ' ' || codepoint == '\r' || codepoint == '\n';
}
static bool IsNewLine(int codepoint)
static bool IsNewLine(codepoint_t codepoint)
{
return codepoint == '\r' || codepoint == '\n';
}
static void SkipWhitespace(IStringReader *reader)
static void SkipWhitespace(IStringReader * reader)
{
int codepoint;
while (reader->TryPeek(&codepoint)) {
if (IsWhitespace(codepoint)) {
codepoint_t codepoint;
while (reader->TryPeek(&codepoint))
{
if (IsWhitespace(codepoint))
{
reader->Skip();
} else {
}
else
{
break;
}
}
}
static void SkipNewLine(IStringReader *reader)
static void SkipNewLine(IStringReader * reader)
{
int codepoint;
while (reader->TryPeek(&codepoint)) {
if (IsNewLine(codepoint)) {
codepoint_t codepoint;
while (reader->TryPeek(&codepoint))
{
if (IsNewLine(codepoint))
{
reader->Skip();
} else {
}
else
{
break;
}
}
}
static void SkipToEndOfLine(IStringReader *reader)
static void SkipToEndOfLine(IStringReader * reader)
{
int codepoint;
codepoint_t codepoint;
while (reader->TryPeek(&codepoint)) {
if (codepoint != '\r' && codepoint != '\n') {
if (codepoint != '\r' && codepoint != '\n')
{
reader->Skip();
} else {
}
else
{
break;
}
}
@ -264,8 +318,9 @@ void LanguagePack::ParseLine(IStringReader *reader)
{
SkipWhitespace(reader);
int codepoint;
if (reader->TryPeek(&codepoint)) {
codepoint_t codepoint;
if (reader->TryPeek(&codepoint))
{
switch (codepoint) {
case '#':
SkipToEndOfLine(reader);
@ -288,38 +343,44 @@ void LanguagePack::ParseLine(IStringReader *reader)
}
}
void LanguagePack::ParseGroupObject(IStringReader *reader)
void LanguagePack::ParseGroupObject(IStringReader * reader)
{
auto sb = StringBuilder();
int codepoint;
codepoint_t codepoint;
// Should have already deduced that the next codepoint is a [
reader->Skip();
// Read string up to ] or line end
bool closedCorrectly = false;
while (reader->TryPeek(&codepoint)) {
while (reader->TryPeek(&codepoint))
{
if (IsNewLine(codepoint)) break;
reader->Skip();
if (codepoint == ']') {
if (codepoint == ']')
{
closedCorrectly = true;
break;
}
sb.Append(codepoint);
}
if (closedCorrectly) {
if (closedCorrectly)
{
SafeFree(_currentGroup);
while (sb.GetLength() < 8) {
while (sb.GetLength() < 8)
{
sb.Append(' ');
}
if (sb.GetLength() == 8) {
if (sb.GetLength() == 8)
{
_currentGroup = sb.GetString();
_currentObjectOverride = GetObjectOverride(_currentGroup);
_currentScenarioOverride = nullptr;
if (_currentObjectOverride == nullptr) {
if (_currentObjectOverride == nullptr)
{
_objectOverrides.push_back(ObjectOverride());
_currentObjectOverride = &_objectOverrides[_objectOverrides.size() - 1];
memset(_currentObjectOverride, 0, sizeof(ObjectOverride));
@ -329,37 +390,41 @@ void LanguagePack::ParseGroupObject(IStringReader *reader)
}
}
void LanguagePack::ParseGroupScenario(IStringReader *reader)
void LanguagePack::ParseGroupScenario(IStringReader * reader)
{
auto sb = StringBuilder();
int codepoint;
codepoint_t codepoint;
// Should have already deduced that the next codepoint is a <
reader->Skip();
// Read string up to > or line end
bool closedCorrectly = false;
while (reader->TryPeek(&codepoint)) {
while (reader->TryPeek(&codepoint))
{
if (IsNewLine(codepoint)) break;
reader->Skip();
if (codepoint == '>') {
if (codepoint == '>')
{
closedCorrectly = true;
break;
}
sb.Append(codepoint);
}
if (closedCorrectly) {
if (closedCorrectly)
{
SafeFree(_currentGroup);
_currentGroup = sb.GetString();
_currentObjectOverride = nullptr;
_currentScenarioOverride = GetScenarioOverride(_currentGroup);
if (_currentScenarioOverride == nullptr) {
if (_currentScenarioOverride == nullptr)
{
_scenarioOverrides.push_back(ScenarioOverride());
_currentScenarioOverride = &_scenarioOverrides[_scenarioOverrides.size() - 1];
memset(_currentScenarioOverride, 0, sizeof(ScenarioOverride));
Memory::Set(_currentScenarioOverride, 0, sizeof(ScenarioOverride));
_currentScenarioOverride->filename = sb.GetString();
}
}
@ -368,17 +433,23 @@ void LanguagePack::ParseGroupScenario(IStringReader *reader)
void LanguagePack::ParseString(IStringReader *reader)
{
auto sb = StringBuilder();
int codepoint;
codepoint_t codepoint;
// Parse string identifier
while (reader->TryPeek(&codepoint)) {
if (IsNewLine(codepoint)) {
while (reader->TryPeek(&codepoint))
{
if (IsNewLine(codepoint))
{
// Unexpected new line, ignore line entirely
return;
} else if (!IsWhitespace(codepoint) && codepoint != ':') {
}
else if (!IsWhitespace(codepoint) && codepoint != ':')
{
reader->Skip();
sb.Append(codepoint);
} else {
}
else
{
break;
}
}
@ -386,7 +457,8 @@ void LanguagePack::ParseString(IStringReader *reader)
SkipWhitespace(reader);
// Parse a colon
if (!reader->TryPeek(&codepoint) || codepoint != ':') {
if (!reader->TryPeek(&codepoint) || codepoint != ':')
{
// Expected a colon, ignore line entirely
return;
}
@ -396,12 +468,16 @@ void LanguagePack::ParseString(IStringReader *reader)
const utf8 *identifier = sb.GetBuffer();
int stringId;
if (_currentGroup == nullptr) {
if (sscanf(identifier, "STR_%4d", &stringId) != 1) {
if (_currentGroup == nullptr)
{
if (sscanf(identifier, "STR_%4d", &stringId) != 1)
{
// Ignore line entirely
return;
}
} else {
}
else
{
if (strcmp(identifier, "STR_NAME") == 0) { stringId = 0; }
else if (strcmp(identifier, "STR_DESC") == 0) { stringId = 1; }
else if (strcmp(identifier, "STR_CPTY") == 0) { stringId = 2; }
@ -417,43 +493,60 @@ void LanguagePack::ParseString(IStringReader *reader)
// Rest of the line is the actual string
sb.Clear();
while (reader->TryPeek(&codepoint) && !IsNewLine(codepoint)) {
if (codepoint == '{') {
while (reader->TryPeek(&codepoint) && !IsNewLine(codepoint))
{
if (codepoint == '{')
{
uint32 token;
bool isByte;
if (ParseToken(reader, &token, &isByte)) {
if (isByte) {
if (ParseToken(reader, &token, &isByte))
{
if (isByte)
{
sb.Append((const utf8*)&token, 1);
} else {
}
else
{
sb.Append((int)token);
}
} else {
}
else
{
// Syntax error or unknown token, ignore line entirely
return;
}
} else {
}
else
{
reader->Skip();
sb.Append(codepoint);
}
}
// Append a null terminator for the benefit of the last string
_stringDataSB.Append(0);
_stringDataSB.Append('\0');
// Get the relative offset to the string (add the base offset when we extract the string properly)
utf8 *relativeOffset = (utf8*)_stringDataSB.GetLength();
utf8 * relativeOffset = (utf8*)_stringDataSB.GetLength();
if (_currentGroup == nullptr) {
if (_currentGroup == nullptr)
{
// Make sure the list is big enough to contain this string id
while (_strings.size() <= (size_t)stringId) {
while (_strings.size() <= (size_t)stringId)
{
_strings.push_back(nullptr);
}
_strings[stringId] = relativeOffset;
} else {
if (_currentObjectOverride != nullptr) {
}
else
{
if (_currentObjectOverride != nullptr)
{
_currentObjectOverride->strings[stringId] = relativeOffset;
} else {
}
else
{
_currentScenarioOverride->strings[stringId] = relativeOffset;
}
}
@ -461,15 +554,16 @@ void LanguagePack::ParseString(IStringReader *reader)
_stringDataSB.Append(&sb);
}
bool LanguagePack::ParseToken(IStringReader *reader, uint32 *token, bool *isByte)
bool LanguagePack::ParseToken(IStringReader * reader, uint32 * token, bool * isByte)
{
auto sb = StringBuilder();
int codepoint;
codepoint_t codepoint;
// Skip open brace
reader->Skip();
while (reader->TryPeek(&codepoint)) {
while (reader->TryPeek(&codepoint))
{
if (IsNewLine(codepoint)) return false;
if (IsWhitespace(codepoint)) return false;
@ -480,14 +574,16 @@ bool LanguagePack::ParseToken(IStringReader *reader, uint32 *token, bool *isByte
sb.Append(codepoint);
}
const utf8 *tokenName = sb.GetBuffer();
const utf8 * tokenName = sb.GetBuffer();
*token = format_get_code(tokenName);
*isByte = false;
// Handle explicit byte values
if (*token == 0) {
if (*token == 0)
{
int number;
if (sscanf(tokenName, "%d", &number) == 1) {
if (sscanf(tokenName, "%d", &number) == 1)
{
*token = Math::Clamp(0, number, 255);
*isByte = true;
}

View File

@ -2,7 +2,8 @@
#include <vector>
extern "C" {
extern "C"
{
#include "../common.h"
#include "../util/util.h"
#include "localisation.h"
@ -13,65 +14,71 @@ extern "C" {
class LanguagePack final {
public:
static LanguagePack *FromFile(int id, const utf8 *path);
static LanguagePack *FromText(int id, const utf8 *text);
static LanguagePack * FromFile(uint16 id, const utf8 * path);
static LanguagePack * FromText(uint16 id, const utf8 * text);
~LanguagePack();
int GetId() const { return _id; }
int GetCount() const { return _strings.size(); }
uint16 GetId() const { return _id; }
uint32 GetCount() const { return _strings.size(); }
const utf8 *GetString(int stringId) const;
const utf8 * GetString(rct_string_id stringId) const;
void SetString(int stringId, const utf8 *str) {
if (_strings.size() >= (size_t)stringId) {
void SetString(rct_string_id stringId, const utf8 * str)
{
if (_strings.size() >= (size_t)stringId)
{
_strings[stringId] = str;
}
}
rct_string_id GetObjectOverrideStringId(const char *objectIdentifier, int index);
rct_string_id GetScenarioOverrideStringId(const utf8 *scenarioFilename, int index);
rct_string_id GetObjectOverrideStringId(const char * objectIdentifier, uint8 index);
rct_string_id GetScenarioOverrideStringId(const utf8 * scenarioFilename, uint8 index);
private:
struct ObjectOverride {
struct ObjectOverride
{
char name[8];
const utf8 *strings[4];
const utf8 * strings[4];
};
struct ScenarioOverride {
const utf8 *filename;
struct ScenarioOverride
{
const utf8 * filename;
union {
const utf8 *strings[3];
const utf8 * strings[3];
struct {
const utf8 *name;
const utf8 *park;
const utf8 *details;
const utf8 * name;
const utf8 * park;
const utf8 * details;
};
};
};
int _id;
utf8 *_stringData;
uint16 _id;
utf8 * _stringData;
std::vector<const utf8*> _strings;
std::vector<ObjectOverride> _objectOverrides;
std::vector<ScenarioOverride> _scenarioOverrides;
LanguagePack(int id, const utf8 *text);
ObjectOverride *GetObjectOverride(const char *objectIdentifier);
ScenarioOverride *GetScenarioOverride(const utf8 *scenarioFilename);
LanguagePack(uint16 id, const utf8 * text);
ObjectOverride * GetObjectOverride(const char * objectIdentifier);
ScenarioOverride * GetScenarioOverride(const utf8 * scenarioFilename);
///////////////////////////////////////////////////////////////////////////
// Parsing
///////////////////////////////////////////////////////////////////////////
StringBuilder _stringDataSB;
utf8 *_currentGroup;
ObjectOverride *_currentObjectOverride;
ScenarioOverride *_currentScenarioOverride;
utf8 * _currentGroup;
ObjectOverride * _currentObjectOverride;
ScenarioOverride * _currentScenarioOverride;
void ParseLine(IStringReader *reader);
void ParseGroupObject(IStringReader *reader);
void ParseGroupScenario(IStringReader *reader);
void ParseString(IStringReader *reader);
void ParseLine(IStringReader * reader);
void ParseGroupObject(IStringReader * reader);
void ParseGroupScenario(IStringReader * reader);
void ParseString(IStringReader * reader);
bool ParseToken(IStringReader *reader, uint32 *token, bool *isByte);
bool ParseToken(IStringReader * reader, uint32 * token, bool * isByte);
};

View File

@ -58,6 +58,8 @@ typedef const utf8* const_utf8string;
typedef wchar_t utf16;
typedef utf16* utf16string;
typedef uint32 codepoint_t;
#define rol8(x, shift) (((uint8)(x) << (shift)) | ((uint8)(x) >> (8 - (shift))))
#define ror8(x, shift) (((uint8)(x) >> (shift)) | ((uint8)(x) << (8 - (shift))))
#define rol16(x, shift) (((uint16)(x) << (shift)) | ((uint16)(x) >> (16 - (shift))))