mirror of https://github.com/OpenRCT2/OpenRCT2.git
refactor and format old C++ code
This commit is contained in:
parent
36a4cd2fa0
commit
4c1605f268
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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) { }
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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))))
|
||||
|
|
Loading…
Reference in New Issue