This commit is contained in:
Misaki
2025-12-04 19:11:29 +08:00
commit bb600bbbc4
2741 changed files with 364700 additions and 0 deletions
@@ -0,0 +1,9 @@
target_sources(${LIB_NAME}
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/CubismDebug.cpp
${CMAKE_CURRENT_SOURCE_DIR}/CubismDebug.hpp
${CMAKE_CURRENT_SOURCE_DIR}/CubismJson.cpp
${CMAKE_CURRENT_SOURCE_DIR}/CubismJson.hpp
${CMAKE_CURRENT_SOURCE_DIR}/CubismString.cpp
${CMAKE_CURRENT_SOURCE_DIR}/CubismString.hpp
)
+54
View File
@@ -0,0 +1,54 @@
/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
#include "CubismDebug.hpp"
#include "CubismFramework.hpp"
#include <stdio.h>
#include <stdarg.h>
//------------ LIVE2D NAMESPACE ------------
namespace Live2D { namespace Cubism { namespace Framework { namespace Utils {
void CubismDebug::Print(CubismFramework::Option::LogLevel logLevel, const csmChar* format, ...)
{
// オプションで設定されたログ出力レベルを下回る場合はログに出さない
if (logLevel < CubismFramework::GetLoggingLevel())
return;
const Core::csmLogFunction logPrint = CubismFramework::CoreLogFunction;
if (!logPrint)
return;
csmChar buffer[256];
va_list va;
va_start(va, format);
#ifdef _WINDOWS
vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, format, va);
#else
vsnprintf(buffer, sizeof(buffer), format, va);
#endif
va_end(va);
logPrint(buffer);
}
void CubismDebug::DumpBytes(CubismFramework::Option::LogLevel logLevel, const csmUint8* data, csmInt32 length)
{
for (csmInt32 i = 0; i < length; i++)
{
if (i % 16 == 0 && i > 0) Print(logLevel, "\n");
else if (i % 8 == 0 && i > 0) Print(logLevel, " ");
Print(logLevel, "%02X ", (data[i] & 0xFF));
}
Print(logLevel, "\n");
}
}}}}
//------------ LIVE2D NAMESPACE ------------
+107
View File
@@ -0,0 +1,107 @@
/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
#pragma once
#include "CubismFramework.hpp"
#ifdef CSM_DEBUG
#include "assert.h"
#define CSM_ASSERT(expr) assert(expr)
#else
#define CSM_ASSERT(expr)
#endif
#define CubismLogPrint(level, fmt, ...) Live2D::Cubism::Framework::Utils::CubismDebug::Print(level, "[CSM]" fmt, ## __VA_ARGS__)
#define CubismLogPrintln(level, fmt, ...) CubismLogPrint(level, fmt "\n", ## __VA_ARGS__)
#if CSM_LOG_LEVEL <= CSM_LOG_LEVEL_VERBOSE
#define CubismLogVerbose(fmt, ...) CubismLogPrintln(Live2D::Cubism::Framework::CubismFramework::Option::LogLevel_Verbose, "[V]" fmt, ## __VA_ARGS__)
#define CubismLogDebug(fmt, ...) CubismLogPrintln(Live2D::Cubism::Framework::CubismFramework::Option::LogLevel_Debug, "[D]" fmt, ## __VA_ARGS__)
#define CubismLogInfo(fmt, ...) CubismLogPrintln(Live2D::Cubism::Framework::CubismFramework::Option::LogLevel_Info, "[I]" fmt, ## __VA_ARGS__)
#define CubismLogWarning(fmt, ...) CubismLogPrintln(Live2D::Cubism::Framework::CubismFramework::Option::LogLevel_Warning, "[W]" fmt, ## __VA_ARGS__)
#define CubismLogError(fmt, ...) CubismLogPrintln(Live2D::Cubism::Framework::CubismFramework::Option::LogLevel_Error, "[E]" fmt, ## __VA_ARGS__)
#elif CSM_LOG_LEVEL == CSM_LOG_LEVEL_DEBUG
#define CubismLogVerbose(fmt, ...)
#define CubismLogDebug(fmt, ...) CubismLogPrintln(Live2D::Cubism::Framework::CubismFramework::Option::LogLevel_Debug, "[D]" fmt, ## __VA_ARGS__)
#define CubismLogInfo(fmt, ...) CubismLogPrintln(Live2D::Cubism::Framework::CubismFramework::Option::LogLevel_Info, "[I]" fmt, ## __VA_ARGS__)
#define CubismLogWarning(fmt, ...) CubismLogPrintln(Live2D::Cubism::Framework::CubismFramework::Option::LogLevel_Warning, "[W]" fmt, ## __VA_ARGS__)
#define CubismLogError(fmt, ...) CubismLogPrintln(Live2D::Cubism::Framework::CubismFramework::Option::LogLevel_Error, "[E]" fmt, ## __VA_ARGS__)
#elif CSM_LOG_LEVEL == CSM_LOG_LEVEL_INFO
#define CubismLogVerbose(fmt, ...)
#define CubismLogDebug(fmt, ...)
#define CubismLogInfo(fmt, ...) CubismLogPrintln(Live2D::Cubism::Framework::CubismFramework::Option::LogLevel_Info, "[I]" fmt, ## __VA_ARGS__)
#define CubismLogWarning(fmt, ...) CubismLogPrintln(Live2D::Cubism::Framework::CubismFramework::Option::LogLevel_Warning, "[W]" fmt, ## __VA_ARGS__)
#define CubismLogError(fmt, ...) CubismLogPrintln(Live2D::Cubism::Framework::CubismFramework::Option::LogLevel_Error, "[E]" fmt, ## __VA_ARGS__)
#elif CSM_LOG_LEVEL == CSM_LOG_LEVEL_WARNING
#define CubismLogVerbose(fmt, ...)
#define CubismLogDebug(fmt, ...)
#define CubismLogInfo(fmt, ...)
#define CubismLogWarning(fmt, ...) CubismLogPrintln(Live2D::Cubism::Framework::CubismFramework::Option::LogLevel_Warning, "[W]" fmt, ## __VA_ARGS__)
#define CubismLogError(fmt, ...) CubismLogPrintln(Live2D::Cubism::Framework::CubismFramework::Option::LogLevel_Error, "[E]" fmt, ## __VA_ARGS__)
#elif CSM_LOG_LEVEL == CSM_LOG_LEVEL_ERROR
#define CubismLogVerbose(fmt, ...)
#define CubismLogDebug(fmt, ...)
#define CubismLogInfo(fmt, ...)
#define CubismLogWarning(fmt, ...)
#define CubismLogError(fmt, ...) CubismLogPrintln(Live2D::Cubism::Framework::CubismFramework::Option::LogLevel_Error, "[E]" fmt, ## __VA_ARGS__)
#else
#define CubismLogVerbose(fmt, ...)
#define CubismLogDebug(fmt, ...)
#define CubismLogInfo(fmt, ...)
#define CubismLogWarning(fmt, ...)
#define CubismLogError(fmt, ...)
#endif
//------------ LIVE2D NAMESPACE ------------
namespace Live2D { namespace Cubism { namespace Framework {
template<class T>
class csmVector;
}}}
namespace Live2D { namespace Cubism { namespace Framework { namespace Utils {
/**
* @brief デバッグ用ユーティリティクラス。<br>
* ログの出力、バイトのダンプなど
*/
class CubismDebug
{
public:
/**
*@brief ログを出力する。第一引数にログレベルを設定する。<br>
* CubismFramework::Initialize()時にオプションで設定されたログ出力レベルを下回る場合はログに出さない。
*
*@param logLevel -> ログレベルの設定
*@param format -> 書式付き文字列
*@param ... -> 可変長引数
*
*/
static void Print(CubismFramework::Option::LogLevel logLevel, const csmChar* format, ...);
/**
*@brief データから指定した長さだけダンプ出力する。<br>
* CubismFramework::Initialize()時にオプションで設定されたログ出力レベルを下回る場合はログに出さない。
*
*@param logLevel -> ログレベルの設定
*@param data -> ダンプするデータ
*@param length -> ダンプする長さ
*
*/
static void DumpBytes(CubismFramework::Option::LogLevel logLevel, const csmUint8* data, csmInt32 length);
private:
/**
* privateコンストラクタ
*/
CubismDebug();
};
}}}}
//------------ LIVE2D NAMESPACE ------------
+570
View File
@@ -0,0 +1,570 @@
/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
#include "CubismJson.hpp"
#include <stdlib.h>
#include "Type/csmString.hpp"
#include "CubismDebug.hpp"
using namespace std; // for strtof
//------------ LIVE2D NAMESPACE ------------
namespace Live2D { namespace Cubism { namespace Framework { namespace Utils {
//StaticInitializeNotForClientCall()で初期化する
Boolean* Boolean::TrueValue = NULL;
Boolean* Boolean::FalseValue = NULL;
Value* Value::ErrorValue = NULL;
Value* Value::NullValue = NULL;
csmVector<csmString>* Value::s_dummyKeys = NULL;
void Value::StaticReleaseNotForClientCall()
{
CSM_DELETE(Boolean::TrueValue);
CSM_DELETE(Boolean::FalseValue);
CSM_DELETE(Value::ErrorValue);
CSM_DELETE(Value::NullValue);
CSM_DELETE(Value::s_dummyKeys);
Boolean::TrueValue = NULL;
Boolean::FalseValue = NULL;
Value::ErrorValue = NULL;
Value::NullValue = NULL;
Value::s_dummyKeys = NULL;
}
void Value::StaticInitializeNotForClientCall()
{
Boolean::TrueValue = CSM_NEW Boolean(true);
Boolean::FalseValue = CSM_NEW Boolean(false);
Value::ErrorValue = CSM_NEW Error("ERROR", true);
Value::NullValue = CSM_NEW Utils::NullValue();
Value::s_dummyKeys = CSM_NEW csmVector<csmString>();
}
CubismJson::CubismJson()
: _error(NULL)
, _lineCount(0)
, _root(NULL)
{ }
CubismJson::CubismJson(const csmByte* buffer, csmInt32 length)
: _error(NULL)
, _lineCount(0)
, _root(NULL)
{
ParseBytes(buffer, length);
}
CubismJson::~CubismJson()
{
if (_root && !_root->IsStatic())
{
CSM_DELETE(_root);
}
_root = NULL;
}
void CubismJson::Delete(CubismJson* instance)
{
CSM_DELETE_SELF(CubismJson, instance);
}
CubismJson* CubismJson::Create(const csmByte* buffer, csmSizeInt size)
{
CubismJson* json = CSM_NEW CubismJson();
const csmBool succeeded = json->ParseBytes(buffer, size);
if (!succeeded)
{
CubismJson::Delete(json);
return NULL;
}
else
{
return json;
}
}
Value& CubismJson::GetRoot() const
{
return *_root;
}
csmBool CubismJson::ParseBytes(const csmByte* buffer, csmInt32 size)
{
csmInt32 endPos;
_root = ParseValue(reinterpret_cast<const csmChar*>(buffer), size, 0, &endPos);
if (_error)
{
#if defined(CSM_TARGET_WIN_GL) || defined(_MSC_VER)
csmChar strbuf[256] = {'\0'};
_snprintf_s(strbuf, 256, 256, "Json parse error : @line %d\n", (_lineCount + 1));
_root = CSM_NEW String(strbuf);
#else
csmChar strbuf[256] = { '\0' };
snprintf(strbuf, 256, "Json parse error : @line %d\n", (_lineCount + 1));
_root = CSM_NEW String(strbuf);
#endif
CubismLogInfo("%s", _root->GetRawString());
return false;
}
else if (_root == NULL)
{
_root = CSM_NEW Error(_error, false); //rootは開放されるのでエラーオブジェクトを別途作る
return false;
}
return true;
}
csmString CubismJson::ParseString(const csmChar* string, csmInt32 length, csmInt32 begin, csmInt32* outEndPos)
{
if (_error)
{
return NULL;
}
if (!string)
{
_error = "string is null";
return NULL;
}
csmInt32 i = begin;
csmString ret;
csmInt32 buf_start = begin; //sbufに登録されていない文字の開始位置
for (; i < length; i++)
{
switch (string[i])
{
case '\"': {//終端の”, エスケープ文字は別に処理されるのでここにはこない
*outEndPos = i + 1; // ”の次の文字
ret.Append(static_cast<const csmChar*>(string + buf_start), (i - buf_start));
return ret;
}
case '\\': {//エスケープの場合
i++; //2文字をセットで扱う
if (i - 1 > buf_start)
{
ret.Append(static_cast<const csmChar*>(string + buf_start), (i - buf_start - 1)); //前の文字までを登録する
}
buf_start = i + 1; //エスケープ(2文字)の次の文字から
if (i < length)
{
switch (string[i])
{
case '\\': ret.Append(1, '\\');
break;
case '\"': ret.Append(1, '\"');
break;
case '/': ret.Append(1, '/');
break;
case 'b': ret.Append(1, '\b');
break;
case 'f': ret.Append(1, '\f');
break;
case 'n': ret.Append(1, '\n');
break;
case 'r': ret.Append(1, '\r');
break;
case 't': ret.Append(1, '\t');
break;
case 'u':
_error = "parse string/unicode escape not supported";
default:
break;
}
}
else
{
_error = "parse string/escape error";
}
break;
}
default: {
break;
}
}
}
_error = "parse string/illegal end";
return NULL;
}
Value* CubismJson::ParseNumeric(const csmChar* buffer, csmInt32 length, csmInt32 begin, csmInt32* outEndPos)
{
if (_error)
{
return NULL;
}
if (!buffer)
{
_error = "buffer is null";
return NULL;
}
csmFloat32 ret = 0.0f;
csmInt32 i = begin;
csmBool decimalPointSeen = false;
csmBool isNegative = false;
csmFloat32 decimalMultiplier = 0.1f;
// 改行もしくは区切り文字に当たるまで読み込む
for (; i < length; i++)
{
switch (buffer[i])
{
case '-':
{
isNegative = true;
break;
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
csmInt32 digit = buffer[i] - '0';
if (!decimalPointSeen) // 整数部分構築
{
ret = ret * 10 + digit;
}
else // 小数部分構築
{
ret += digit * decimalMultiplier;
decimalMultiplier *= 0.1f;
}
break;
}
case '.': // . 小数点記号チェック
{
if (decimalPointSeen)
{
_error = "multiple decimal points found";
return NULL;
}
decimalPointSeen = true;
break;
}
case '\n': case ',': // 終端には改行文字か、区切り文字の , が来る
{
*outEndPos = i;
if (isNegative) // 負数処理
{
ret *= -1;
}
return CSM_NEW Float(ret);
}
case '\r': break; // CRLF スキップ用
default:
{
_error = "non-numeric charactor found";
return NULL;
}
}
}
_error = "parse numeric/illegal end";
return NULL;
}
Value* CubismJson::ParseObject(const csmChar* buffer, csmInt32 length, csmInt32 begin, csmInt32* outEndPos)
{
if (_error)
{
return NULL;
}
if (!buffer)
{
_error = "buffer is null";
return NULL;
}
Map* ret = CSM_NEW Map();
//key : value ,
csmString key;
csmInt32 i = begin;
csmInt32 local_ret_endpos2[1];
csmBool ok = false;
// , が続く限りループ
for (; i < length; i++)
{
for (; i < length; i++)
{
switch (buffer[i])
{
case '\"':
key = ParseString(buffer, length, i + 1, local_ret_endpos2);
if (_error) return NULL;
i = local_ret_endpos2[0];
ok = true;
goto BREAK_LOOP1; //-- loopから出る
case '}': //閉じカッコ
*outEndPos = i + 1;
return ret; //空
case ':':
_error = "illegal ':' position";
break;
case '\n': _lineCount++;
default: break; //スキップする文字
}
}
BREAK_LOOP1:
if (!ok)
{
_error = "key not found";
return NULL;
}
ok = false;
// : をチェック
for (; i < length; i++)
{
switch (buffer[i])
{
case ':': ok = true;
i++;
goto BREAK_LOOP2; //-- loopから出る
case '}':
_error = "illegal '}' position";
break;
case '\n': _lineCount++;
//case ' ': case '\t': case '\r':
default: break; //スキップする文字
}
}
BREAK_LOOP2:
if (!ok)
{
_error = "':' not found";
return NULL;
}
// 値をチェック
Value* value = ParseValue(buffer, length, i, local_ret_endpos2);
if (_error)
{
return NULL;
}
i = local_ret_endpos2[0];
// ret.put( key , value ) ;
ret->Put(key, value);
for (; i < length; i++)
{
switch (buffer[i])
{
case ',':
goto BREAK_LOOP3;
case '}':
*outEndPos = i + 1;
return ret; // << [] 正常終了 >>
case '\n': _lineCount++;
//case ' ': case '\t': case '\r':
default: break; //スキップ
}
}
BREAK_LOOP3:
; //dummy
}
_error = "illegal end of parseObject";
return NULL;
}
Value* CubismJson::ParseArray(const csmChar* buffer, csmInt32 length, csmInt32 begin, csmInt32* outEndPos)
{
if (_error)
{
return NULL;
}
if (!buffer)
{
_error = "buffer is null";
return NULL;
}
Array* ret = CSM_NEW Array();
//key : value ,
csmInt32 i = begin;
csmInt32 local_ret_endpos2[1];
// , が続く限りループ
for (; i < length; i++)
{
// : をチェック
Value* value = ParseValue(buffer, length, i, local_ret_endpos2);
if (_error)
{
return NULL;
}
i = local_ret_endpos2[0];
if (value)
{
ret->Add(value);
}
//FOR_LOOP3:
//bool breakflag = false;
for (; i < length; i++)
{
switch (buffer[i])
{
case ',':
// breakflag = true;
// break;//次のKEY,VALUEへ
goto BREAK_LOOP3;
case ']':
*outEndPos = i + 1;
return ret; //終了
case '\n': ++_lineCount;
//case ' ': case '\t': case '\r':
default: break; //スキップ
}
}
BREAK_LOOP3:
; //dummy
}
CSM_DELETE(ret);
_error = "illegal end of parseObject";
return NULL;
}
Value* CubismJson::ParseValue(const csmChar* buffer, csmInt32 length, csmInt32 begin, csmInt32* outEndPos)
{
if (_error)
{
return NULL;
}
if (!buffer)
{
_error = "buffer is null";
return NULL;
}
Value* o = NULL;
csmInt32 i = begin;
csmFloat32 f;
csmString s1; //デバッグ用に使っている
for (; i < length; i++)
{
switch (buffer[i])
{
case '-':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
return ParseNumeric(buffer, length, i, outEndPos);
case '\"':
return CSM_NEW String(ParseString(buffer, length, i + 1, outEndPos)); //\"の次の文字から
case '[':
o = ParseArray(buffer, length, i + 1, outEndPos);
return o;
case '{':
o = ParseObject(buffer, length, i + 1, outEndPos);
return o;
case 'n': //null以外にない
if (i + 3 < length)
{
o = CSM_NEW NullValue(); //開放できるようにする
*outEndPos = i + 4;
}
else _error = "parse null";
return o;
case 't': //true以外にない
if (i + 3 < length)
{
o = Boolean::TrueValue;
*outEndPos = i + 4;
}
else _error = "parse true";
return o;
case 'f': //false以外にない
if (i + 4 < length)
{
o = Boolean::FalseValue;
*outEndPos = i + 5;
}
else _error = "parse false";
return o;
case ',': //Array separator
_error = "illegal ',' position";
return NULL;
case ']': //不正な}だがスキップする。配列の最後に不要な , があると思われる
*outEndPos = i; //同じ文字を再処理
return NULL;
case '\n': _lineCount++;
case ' ': case '\t': case '\r':
default: //スキップ
break;
}
}
_error = "illegal end of value";
return NULL;
}
Map::~Map()
{
csmMap<csmString, Value*>::const_iterator ite = _map.Begin();
while (ite != _map.End())
{
Value* v = (*ite).Second;
if (v && !v->IsStatic())
{
CSM_DELETE(v);
}
++ite;
}
if (_keys)
{
CSM_DELETE(_keys);
}
}
Array::~Array()
{
csmVector<Value*>::iterator ite = _array.Begin();
for (; ite != _array.End(); ++ite)
{
Value* v = (*ite);
if (v && !v->IsStatic())
{
CSM_DELETE(v);
}
}
}
}}}}
//------------ LIVE2D NAMESPACE ------------
+907
View File
@@ -0,0 +1,907 @@
/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
#pragma once
#include <stdio.h>
#include "CubismFramework.hpp"
#include "Type/csmVector.hpp"
#include "Type/csmMap.hpp"
#include "Type/csmString.hpp"
//------------ LIVE2D NAMESPACE ------------
namespace Live2D { namespace Cubism { namespace Framework { namespace Utils {
class Value;
class Error;
class NullValue;
#define CSM_JSON_ERROR_TYPE_MISMATCH "Error:type mismatch"
#define CSM_JSON_ERROR_INDEX_OUT_OF_BOUNDS "Error:index out of bounds"
/**
* @brief パースしたJSONエレメントの要素の基底クラス
*
*/
class Value
{
friend class Array;
friend class Live2D::Cubism::Framework::CubismFramework;
public:
static Value* ErrorValue; ///< 一時的な返り値として返すエラー。CubismFramework::Dispose()するまではCSM_DELETEしない。
static Value* NullValue; ///< 一時的な返り値として返すNULL。CubismFramework::Dispose()するまではCSM_DELETEしない。
/**
* @brief コンストラクタ
*
*/
Value() {}
/**
* @brief デストラクタ
*
*/
virtual ~Value() {}
/**
* @brief 要素を文字列で返す(csmString型)
*
*/
virtual const csmString& GetString(const csmString& defaultValue = "", const csmString& indent = "") = 0;
/**
* @brief 要素を文字列で返す(csmChar*)
*
*/
virtual const csmChar* GetRawString(const csmString& defaultValue = "", const csmString& indent = "")
{
return this->GetString(defaultValue, indent).GetRawString();
}
/**
* @brief 要素を数値型で返す(csmInt32)
*
*/
virtual csmInt32 ToInt(csmInt32 defaultValue = 0) { return defaultValue; }
/**
* @brief 要素を数値型で返す(csmFloat32)
*
*/
virtual csmFloat32 ToFloat(csmFloat32 defaultValue = 0.0f) { return defaultValue; }
/**
* @brief 要素を真偽値で返す(csmBool)
*
*/
virtual csmBool ToBoolean(csmBool defaultValue = false) { return defaultValue; }
/**
* @brief 要素を真偽値で返す(csmBool)
*
*/
virtual csmInt32 GetSize() { return 0; }
/**
* @brief 要素をコンテナで返す(csmVector<Value*>)
*
*/
virtual csmVector<Value*>* GetVector(csmVector<Value*>* defaultValue = NULL) {
if (!defaultValue)
{
defaultValue = new csmVector<Value*>;
}
return defaultValue;
}
/**
* @brief 要素をマップで返す(csmMap<csmString, Value*>)
*
*/
virtual csmMap<csmString, Value*>* GetMap(csmMap<csmString, Value*>* defaultValue = NULL) { return defaultValue; }
/**
* @brief 添字演算子[csmInt32]
*
*/
virtual Value& operator[](csmInt32 index)
{
return *(ErrorValue->SetErrorNotForClientCall(CSM_JSON_ERROR_TYPE_MISMATCH));
}
/**
* @brief 添字演算子[csmString]
*
*/
virtual Value& operator[](const csmString& string)
{
return *(NullValue->SetErrorNotForClientCall(CSM_JSON_ERROR_TYPE_MISMATCH));
}
/**
* @brief 添字演算子[csmChar*]
*
*/
virtual Value& operator[](const csmChar* s)
{
return *(NullValue->SetErrorNotForClientCall(CSM_JSON_ERROR_TYPE_MISMATCH));
}
/**
* @brief マップのキー一覧をコンテナで返す
*
* @return マップのキー一覧
*/
virtual csmVector<csmString>& GetKeys()
{
return *s_dummyKeys;
}
/**
*@brief Valueの種類がエラー値ならtrue。
*/
virtual csmBool IsError() { return false; }
/**
*@brief Valueの種類がNULL値ならtrue。
*/
virtual csmBool IsNull() { return false; }
/**
*@brief Valueの種類が真偽値ならtrue。
*/
virtual csmBool IsBool() { return false; }
/**
*@brief Valueの種類が数値型ならtrue。
*/
virtual csmBool IsFloat() { return false; }
/**
*@brief Valueの種類が文字列ならtrue。
*/
virtual csmBool IsString() { return false; }
/**
*@brief Valueの種類が配列ならtrue。
*/
virtual csmBool IsArray() { return false; }
/**
*@brief Valueの種類がマップ型ならtrue。
*/
virtual csmBool IsMap() { return false; }
/**
*@brief 引数の値と等しければtrue。
*/
virtual csmBool Equals(const csmString& value) { return false; }
/**
*@brief 引数の値と等しければtrue。
*/
virtual csmBool Equals(const csmChar* value) { return false; }
/**
*@brief 引数の値と等しければtrue。
*/
virtual csmBool Equals(csmInt32 value) { return false; }
/**
*@brief 引数の値と等しければtrue。
*/
virtual csmBool Equals(csmFloat32 value) { return false; }
/**
*@brief 引数の値と等しければtrue。
*/
virtual csmBool Equals(csmBool value) { return false; }
/**
*@brief Valueの値が静的ならtrue. 静的なら解放しない
*/
virtual csmBool IsStatic() { return false; }
/**
*@brief Valueにエラー値をセットする
*/
virtual Value* SetErrorNotForClientCall(const csmChar* errorStr) {
this->_stringBuffer = errorStr;
return NullValue;
}
protected:
csmString _stringBuffer; ///< 文字列バッファ
private:
static csmVector<csmString>* s_dummyKeys; ///< ダミーキー
/**
* @brief 初期化用メソッド
*/
static void StaticInitializeNotForClientCall();
/**
* @brief リリース用メソッド
*/
static void StaticReleaseNotForClientCall();
};
/**
* @brief Ascii文字のみ対応した最小限の軽量JSONパーサ。<br>
* 仕様はJSONのサブセットとなる。<br>
* 設定ファイル(model3.json)などのロード用<br>
* <br>
* [未対応項目]<br>
* ・日本語などの非ASCII文字<br>
* ・e による指数表現
*/
class CubismJson
{
public:
/**
* @brief バイトデータから直接ロードしてパースする<br>
* 引数 buffer は外部で管理(破棄)する必要がある
*
* @param buffer -> バイトデータのバッファ
* @param size -> バッファサイズ
* @return CubismJsonクラスのインスタンス。失敗したらNULL。
*/
static CubismJson* Create(const csmByte* buffer, csmSizeInt size);
/**
* @brief パースしたJSONオブジェクトの解放処理
*
* @param[in] instance CubismJsonクラスのインスタンス
*
*/
static void Delete(CubismJson* instance);
/**
* @brief パースしたJSONのルート要素のポインタを返す
*
*/
Value& GetRoot() const;
/**
* @brief パース時のエラー値を返す
*
*/
const csmChar* GetParseError() const { return _error; }
/**
* @brief ルート要素の次の要素がファイルの終端だったらtrueを返す
*
*/
csmBool CheckEndOfFile() const { return (*_root)[1].Equals("EOF"); }
protected:
/**
* @brief JSONのパースを実行する
*
* @param[in] buffer -> パース対象のデータバイト
* @param[in] size -> データバイトのサイズ
* @retval true -> 成功
* @retval false -> 失敗
*/
csmBool ParseBytes(const csmByte* buffer, csmInt32 size);
/**
* @brief 次の「"」までの文字列をパースする。文字列は外部で解放する必要がある。
*
* @param[in] string -> パース対象の文字列
* @param[in] length -> パースする長さ
* @param[in] begin -> パースを開始する位置
* @param[out] outEndPos -> パース終了時の位置
* @return パースした文字列要素
*/
csmString ParseString(const csmChar* string, csmInt32 length, csmInt32 begin, csmInt32* outEndPos);
/**
* @brief 数値をパースする。ロケール設定にかかわらず、小数点の区切り文字を . としてパースする。
*
* @param[in] buffer -> JSONエレメントのバッファ
* @param[in] length -> パースする長さ
* @param[in] begin -> パースを開始する位置
* @param[out] outEndPos -> パース終了時の位置
* @return パースから取得したValueオブジェクト
*/
Value* ParseNumeric(const csmChar* buffer, csmInt32 length, csmInt32 begin, csmInt32* outEndPos);
/**
* @brief JSONのオブジェクトエレメントをパースしてValueオブジェクトを返す
*
* @param[in] buffer -> JSONエレメントのバッファ
* @param[in] length -> パースする長さ
* @param[in] begin -> パースを開始する位置
* @param[out] outEndPos -> パース終了時の位置
* @return パースから取得したValueオブジェクト
*/
Value* ParseObject(const csmChar* buffer, csmInt32 length, csmInt32 begin, csmInt32* outEndPos);
/**
* @brief JSONの配列エレメントをパースしてValueオブジェクトを返す
*
* @param[in] buffer -> JSONエレメントのバッファ
* @param[in] length -> パースする長さ
* @param[in] begin -> パースを開始する位置
* @param[out] outEndPos -> パース終了時の位置
* @return パースから取得したValueオブジェクト
*/
Value* ParseArray(const csmChar* buffer, csmInt32 length, csmInt32 begin, csmInt32* outEndPos);
/**
* @brief JSONエレメントからValue(float,String,Value*,Array,null,true,false)をパースする<br>
* エレメントの書式に応じて内部でParseString(), ParseObject(), ParseArray()を呼ぶ<br>
*
* @param[in] buffer -> JSONエレメントのバッファ
* @param[in] length -> パースする長さ
* @param[in] begin -> パースを開始する位置
* @param[out] outEndPos -> パース終了時の位置
* @return パースから取得したValueオブジェクト
*/
Value* ParseValue(const csmChar* buffer, csmInt32 length, csmInt32 begin, csmInt32* outEndPos);
private:
/**
* @brief コンストラクタ
*
*/
CubismJson();
/**
* @brief 引数付きコンストラクタ
* @param[in] buffer -> JSONエレメントのバッファ
* @param[in] length -> パースする長さ
*/
CubismJson(const csmByte* buffer, csmInt32 length);
/**
* @brief デストラクタ
*
*/
virtual ~CubismJson();
const csmChar* _error; ///< パース時のエラー
csmInt32 _lineCount; ///< エラー報告に用いる行数カウント
Value* _root; ///< パースされたルート要素
};
/**
*@brief パースしたJSONの要素をDouble値として扱う
*/
class Float : public Value
{
public:
/**
* @brief コンストラクタ
*/
Float(csmFloat32 v) : Value()
{
this->_value = v;
}
/**
* @brief デストラクタ
*/
virtual ~Float() {}
/**
*@brief Valueの種類が数値型ならtrue。
*/
virtual csmBool IsFloat() { return true; }
/**
* @brief 要素を文字列で返す(csmString型)
*
*/
virtual const csmString& GetString(const csmString& defaultValue = "", const csmString& indent = "")
{
#if defined(CSM_TARGET_WIN_GL) || defined(_MSC_VER)
csmChar strbuf[32] = {'\0'};
_snprintf_s(strbuf, 32, 32, "%f", this->_value);
_stringBuffer = csmString(strbuf);
return _stringBuffer;
#else
// string stream 未対応
csmChar strbuf[32] = { '\0' };
snprintf(strbuf, 32, "%f", this->_value);
_stringBuffer = csmString(strbuf);
return _stringBuffer;
#endif
}
/**
* @brief 要素を数値型で返す(csmInt32)
*/
virtual csmInt32 ToInt(csmInt32 defaultValue = 0) { return static_cast<csmInt32>(this->_value); }
/**
* @brief 要素を数値型で返す(csmFloat32)
*/
virtual csmFloat32 ToFloat(csmFloat32 defaultValue = 0) { return this->_value; }
/**
*@brief 引数の値と等しければtrue。
*/
virtual csmBool Equals(csmFloat32 v) { return v == this->_value; }
/**
*@brief 引数の値と等しければtrue。
*/
virtual csmBool Equals(const csmString& v) { return false; }
/**
*@brief 引数の値と等しければtrue。
*/
virtual csmBool Equals(const csmChar* v) { return false; }
/**
*@brief 引数の値と等しければtrue。
*/
virtual csmBool Equals(csmInt32 v) { return false; }
/**
*@brief 引数の値と等しければtrue。
*/
virtual csmBool Equals(csmBool v) { return false; }
private:
csmFloat32 _value; ///< JSON要素の値
};
/**
* @brief パースしたJSONの要素を真偽値として扱う
*
*/
class Boolean : public Value
{
friend class Value;
public:
static Boolean* TrueValue; ///< true
static Boolean* FalseValue; ///< false
/**
* @brief デストラクタ
*
*/
virtual ~Boolean() {}
/**
*@brief Valueの種類が真偽値ならtrue。
*/
virtual csmBool IsBool() { return true; }
/**
* @brief 要素を真偽値で返す(csmBool)
*/
virtual csmBool ToBoolean(csmBool defaultValue = false) { return _boolValue; }
/**
* @brief 要素を文字列で返す(csmString型)
*/
virtual const csmString& GetString(const csmString& defaultValue = "", const csmString& indent = "")
{
_stringBuffer = csmString(_boolValue ? "true" : "false");
return _stringBuffer;
}
/**
*@brief 引数の値と等しければtrue。
*/
virtual csmBool Equals(csmBool v) { return v == _boolValue; }
/**
*@brief 引数の値と等しければtrue。
*/
virtual csmBool Equals(const csmString& v) { return false; }
/**
*@brief 引数の値と等しければtrue。
*/
virtual csmBool Equals(const csmChar* v) { return false; }
/**
*@brief 引数の値と等しければtrue。
*/
virtual csmBool Equals(csmInt32 v) { return false; }
/**
*@brief 引数の値と等しければtrue。
*/
virtual csmBool Equals(csmFloat32 v) { return false; }
/**
*@brief Valueの値が静的ならtrue. 静的なら解放しない
*/
virtual csmBool IsStatic() { return true; }
private:
/**
* @brief 引数付きコンストラクタ
*/
Boolean(csmBool v) : Value() { this->_boolValue = v; }
csmBool _boolValue; ///< JSON要素の値
};
/**
* @brief パースしたJSONの要素を文字列として扱う
*
*/
class String : public Value
{
public:
/**
* @brief 引数付きコンストラクタ
*/
String(const csmString& s) : Value() { this->_stringBuffer = s; }
/**
* @brief 引数付きコンストラクタ
*/
String(const csmChar* s) : Value() { this->_stringBuffer = s; }
/**
* @brief デストラクタ
*/
virtual ~String() {}
/**
*@brief Valueの種類が文字列ならtrue。
*/
virtual csmBool IsString() { return true; }
/**
* @brief 要素を文字列で返す(csmString型)
*/
virtual const csmString& GetString(const csmString& defaultValue = "", const csmString& indent = "")
{
return _stringBuffer;
}
/**
*@brief 引数の値と等しければtrue。
*/
virtual csmBool Equals(const csmString& v) { return (_stringBuffer == v); }
/**
*@brief 引数の値と等しければtrue。
*/
virtual csmBool Equals(const csmChar* v) { return (_stringBuffer == v); }
/**
*@brief 引数の値と等しければtrue。
*/
virtual csmBool Equals(csmInt32 v) { return false; }
/**
*@brief 引数の値と等しければtrue。
*/
virtual csmBool Equals(csmFloat32 v) { return false; }
/**
*@brief 引数の値と等しければtrue。
*/
virtual csmBool Equals(csmBool v) { return false; }
};
/**
* @brief JSONパース時のエラー結果。文字列型のように振る舞う
*
*/
class Error : public String
{
friend class Value; //
friend class Array; //
friend class CubismJson; //
public:
/**
*@brief Valueの値が静的ならtrue. 静的なら解放しない
*/
virtual csmBool IsStatic() { return _isStatic; }
/**
* @brief エラー情報をセットする
*/
virtual Value* SetErrorNotForClientCall(const csmChar* s)
{
this->_stringBuffer = s;
return this;
}
protected:
/**
* @brief 引数付きコンストラクタ
*/
Error(const csmString& s, csmBool isStatic) : String(s)
, _isStatic(isStatic) {}
/**
* @brief デストラクタ
*/
virtual ~Error() {}
/**
*@brief Valueの種類がエラー値ならtrue。
*/
virtual csmBool IsError() { return true; }
csmBool _isStatic; ///< 静的なValueかどうか
};
/**
* @brief パースしたJSONの要素をNull値として持つ
*/
class NullValue : public Value
{
friend class Value; //
friend class CubismJson; //
public:
/**
* @brief デストラクタ
*/
virtual ~NullValue() {}
/**
*@brief Valueの種類がNULL値ならtrue。
*/
virtual csmBool IsNull() { return true; }
/**
* @brief 要素を文字列で返す(csmString型)
*/
virtual const csmString& GetString(const csmString& defaultValue = "", const csmString& indent = "")
{
return _stringBuffer;
}
/**
*@brief Valueの値が静的ならtrue. 静的なら解放しない
*/
virtual csmBool IsStatic() { return true; }
private:
/**
* @brief コンストラクタ
*/
NullValue() : Value() { _stringBuffer = "NullValue"; }
};
/**
* @brief パースしたJSONの要素を配列として持つ
*
*/
class Array : public Value
{
public:
/**
* @brief コンストラクタ
*/
Array() : Value()
, _array() {}
/**
* @brief デストラクタ
*/
virtual ~Array();
/**
*@brief Valueの種類が配列ならtrue。
*/
virtual csmBool IsArray() { return true; }
/**
* @brief 添字演算子[csmInt32]
*
*/
virtual Value& operator[](csmInt32 index)
{
if (index < 0 || (static_cast<csmInt32>(_array.GetSize()) <= index))
return *(ErrorValue->SetErrorNotForClientCall(CSM_JSON_ERROR_INDEX_OUT_OF_BOUNDS));
Value* v = _array[index];
if (v == NULL) return *Value::NullValue;
return *v;
}
/**
* @brief 添字演算子[csmString]
*
*/
virtual Value& operator[](const csmString& string)
{
return *(ErrorValue->SetErrorNotForClientCall(CSM_JSON_ERROR_TYPE_MISMATCH));
}
/**
* @brief 添字演算子[csmChar*]
*
*/
virtual Value& operator[](const csmChar* s)
{
return *(ErrorValue->SetErrorNotForClientCall(CSM_JSON_ERROR_TYPE_MISMATCH));
}
/**
* @brief 要素を文字列で返す(csmString型)
*
*/
virtual const csmString& GetString(const csmString& defaultValue = "", const csmString& indent = "")
{
_stringBuffer = indent + "[\n";
csmVector<Value*>::iterator ite = _array.Begin();
for (; ite != _array.End(); ite++)
{
Value* v = (*ite);
_stringBuffer += indent + " " + v->GetString(indent + " ") + "\n";
}
_stringBuffer += indent + "]\n";
return _stringBuffer;
}
/**
* @brief 配列要素を追加する
*/
void Add(Value* v) { _array.PushBack(v, false); }
/**
* @brief 要素をコンテナで返す(csmVector<Value*>)
*
*/
virtual csmVector<Value*>* GetVector(csmVector<Value*>* defaultValue = NULL) { return &_array; }
/**
* @brief 要素の数を返す
*
*/
virtual csmInt32 GetSize() { return static_cast<csmInt32>(_array.GetSize()); }
private:
csmVector<Value*> _array; ///< JSON要素の値
};
/**
* @brief パースしたJSONの要素をマップとして持つ
*
*/
class Map : public Value
{
public:
/**
* @brief コンストラクタ
*/
Map() : Value()
, _keys(NULL) {}
/**
* @brief デストラクタ
*/
virtual ~Map();
/**
* @brief Valueの値がMap型ならtrue
*/
virtual csmBool IsMap() { return true; }
/**
* @brief 添字演算子[csmString]
*/
virtual Value& operator[](const csmString& s)
{
Value* ret = _map[s];
if (ret == NULL)
{
return *Value::NullValue;
}
return *ret;
}
/**
* @brief 添字演算子[csmChar*]
*
*/
virtual Value& operator[](const csmChar* s)
{
for (csmMap<csmString, Value*>::const_iterator iter = _map.Begin(); iter != _map.End(); ++iter)
{
if( strcmp(iter->First.GetRawString(), s) == 0 )
{
if(iter->Second==NULL)
{
return *Value::NullValue;
}
return *iter->Second;
}
}
return *Value::NullValue;
}
/**
* @brief 添字演算子[csmInt32]
*/
virtual Value& operator[](csmInt32 index)
{
return *(ErrorValue->SetErrorNotForClientCall(CSM_JSON_ERROR_TYPE_MISMATCH));
}
virtual const csmString& GetString(const csmString& defaultValue = "", const csmString& indent = "")
{
_stringBuffer = indent + "{\n";
csmMap<csmString, Value*>::const_iterator ite = _map.Begin();
while (ite != _map.End())
{
const csmString& key = (*ite).First;
Value* v = (*ite).Second;
_stringBuffer += indent + " " + key + " : " + v->GetString(indent + " ") + "\n";
++ite;
}
_stringBuffer += indent + "}\n";
return _stringBuffer;
}
/**
* @brief 要素をMap型で返す
*/
virtual csmMap<csmString, Value*>* GetMap(csmMap<csmString, Value*>* defaultValue = NULL)
{
return &_map;
}
/**
* @brief Mapに要素を追加する
*/
void Put(csmString& key, Value* v)
{
_map[key] = v;
}
/**
* @brief Mapからキーのリストを取得する
*/
virtual csmVector<csmString>& GetKeys()
{
if (!_keys)
{
_keys = CSM_NEW csmVector<csmString>();
csmMap<csmString, Value*>::const_iterator ite = _map.Begin();
while (ite != _map.End())
{
const csmString& key = (*ite).First;
_keys->PushBack(key, true);
++ite;
}
}
return *_keys;
}
/**
* @brief Mapの要素数を取得する
*/
virtual csmInt32 GetSize() { return static_cast<csmInt32>(_keys->GetSize()); }
private:
csmMap<csmString, Value*> _map; ///< JSON要素の値
csmVector<csmString>* _keys; ///< JSON要素の値
};
}}}}
//------------ LIVE2D NAMESPACE ------------
+129
View File
@@ -0,0 +1,129 @@
/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
#include "CubismString.hpp"
#include "Type/csmVector.hpp"
#include <stdio.h>
#include <stdarg.h>
//--------- LIVE2D NAMESPACE ------------
namespace Live2D { namespace Cubism { namespace Framework { namespace Utils {
//標準出力の戻り値が複製されるのでオーバーヘッドは大きい。
csmString CubismString::GetFormatedString(const csmChar* format, ...)
{
csmInt32 bufferSize = 256;
csmChar* buffer = static_cast<csmChar*>(CSM_MALLOC(sizeof(csmChar)* bufferSize));
va_list args;
va_start(args, format);
for (;;) {
#ifdef _WINDOWS
if (vsnprintf_s(buffer, bufferSize, _TRUNCATE, format, args) < bufferSize) {
#else
if (vsnprintf(buffer, bufferSize, format, args) < bufferSize) {
#endif
break;
} else {
// メモリが足りない為、拡張して確保しなおす。
CSM_FREE(buffer);
bufferSize *= 2;
buffer = static_cast<csmChar*>(CSM_MALLOC(sizeof(csmChar)* bufferSize));
}
}
va_end(args);
csmString ret = buffer;
CSM_FREE(buffer);
return ret; // CubismString型にされて返されるためアドレスを返すので良い。
}
csmBool CubismString::IsStartsWith(const csmChar* text, const csmChar* startWord)
{
while (*startWord != '\0')
{
if (*text == '\0' || *(text++) != *(startWord++))
{
return false;
}
}
return true;
}
csmFloat32 CubismString::StringToFloat(const csmChar* string, csmInt32 length, csmInt32 position, csmInt32* outEndPos)
{
csmInt32 i = position;
csmBool minus = false; //マイナスフラグ
csmBool period = false;
csmFloat32 v1 = 0;
//負号の確認
csmInt32 c = string[i];
if (c == '-')
{
minus = true;
i++;
}
//整数部の確認
for (; i < length; i++)
{
c = string[i];
if ('0' <= c && c <= '9')
{
v1 = v1 * 10 + (c - '0');
}
else if (c == '.')
{
period = true;
i++;
break;
}
else
{
break;
}
}
//小数部の確認
if (period)
{
csmFloat32 mul = 0.1f;
for (; i < length; i++)
{
c = string[i] & 0xFF;
if ('0' <= c && c <= '9')
{
v1 += mul * (c - '0');
}
else
{
break;
}
mul *= 0.1f; //一桁下げる
if (!c) break;
}
}
if (i == position)
{
//一文字も読み込まなかった場合
*outEndPos = -1; //エラー値が入るので呼び出し元で適切な処理を行う
return 0;
}
if (minus) v1 = -v1;
*outEndPos = i;
return v1;
}
}}}}
//------------------------- LIVE2D NAMESPACE ------------
@@ -0,0 +1,53 @@
/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
#pragma once
#include "Type/csmString.hpp"
//--------- LIVE2D NAMESPACE ------------
namespace Live2D { namespace Cubism { namespace Framework { namespace Utils{
class CubismString
{
public:
/**
* @brief 標準出力の書式を適用した文字列を取得する。
*
* @param[in] format -> 標準出力の書式指定文字列
* @param[in] ... -> 書式指定文字列に渡す文字列
* @return 書式を適用した文字列
*/
static csmString GetFormatedString(const csmChar* format, ...);
/**
* @brief textがstartWordで始まっているかどうかを返す
* @param[in] text -> 検査対象の文字列
* @param[in] startWord -> 比較対象の文字列
* @retval false -> textがstartWordで始まっている
* @retval true -> textがstartWordで始まっていない
*/
static csmBool IsStartsWith(const csmChar* text, const csmChar* startWord);
/***
* @brief position位置の文字から数字を解析する。
*
* @param[in] string -> 文字列
* @param[in] length -> 文字列の長さ
* @param[in] position -> 解析したい文字の位置
* @param[out] outEndPos -> 一文字も読み込まなかった場合はエラー値(-1)が入る
* @return 解析結果の数値
*/
static csmFloat32 StringToFloat(const csmChar* string, csmInt32 length, csmInt32 position, csmInt32* outEndPos);
private:
// コンストラクタ・デストラクタ呼び出し不可な静的クラスにする
CubismString();
};
}}}}
//--------- LIVE2D NAMESPACE ------------