Add json encoding/decoding functions to lua
This adds two global functions: - `JsonEncode()`: Encode data as JSON. Optionally "minify" the result. - `JsonDecode()`: Decode JSON data.
This commit is contained in:
@@ -108,6 +108,8 @@
|
|||||||
<Function name='IsRoutine'/>
|
<Function name='IsRoutine'/>
|
||||||
<Function name='IsSMOnlineLoggedIn'/>
|
<Function name='IsSMOnlineLoggedIn'/>
|
||||||
<Function name='IsUsingWideScreen'/>
|
<Function name='IsUsingWideScreen'/>
|
||||||
|
<Function name='JsonDecode'/>
|
||||||
|
<Function name='JsonEncode'/>
|
||||||
<Function name='JudgmentLineToColor'/>
|
<Function name='JudgmentLineToColor'/>
|
||||||
<Function name='JudgmentLineToLocalizedString'/>
|
<Function name='JudgmentLineToLocalizedString'/>
|
||||||
<Function name='JudgmentLineToStrokeColor'/>
|
<Function name='JudgmentLineToStrokeColor'/>
|
||||||
|
|||||||
@@ -411,6 +411,13 @@ save yourself some time, copy this for undocumented things:
|
|||||||
<Function name='join' theme='_fallback' return='string' arguments='string delimiter, table list'>
|
<Function name='join' theme='_fallback' return='string' arguments='string delimiter, table list'>
|
||||||
[02 Utilities.lua] Joins a table, splitting each item with <code>delimiter</code>, returning a string of the results.
|
[02 Utilities.lua] Joins a table, splitting each item with <code>delimiter</code>, returning a string of the results.
|
||||||
</Function>
|
</Function>
|
||||||
|
<Function name='JsonDecode' return='various' arguments='string data'>
|
||||||
|
Decodes JSON encoded <code>data</code> and returns the result.
|
||||||
|
</Function>
|
||||||
|
<Function name='JsonEncode' return='string' arguments='various data, bool minify'>
|
||||||
|
Returns <code>data</code> as JSON. Empty tables are represented as arrays in the output.<br />
|
||||||
|
<code>minify</code> is optional and defaults to <code>false</code>. If <code>true</code>, all unnecessary whitespace is omitted from the output.
|
||||||
|
</Function>
|
||||||
<Function name='JudgmentLineToColor' theme='_fallback' return='color' arguments='JudgmentLine jl'>
|
<Function name='JudgmentLineToColor' theme='_fallback' return='color' arguments='JudgmentLine jl'>
|
||||||
[02 Colors.lua]
|
[02 Colors.lua]
|
||||||
</Function>
|
</Function>
|
||||||
|
|||||||
+201
-1
@@ -9,6 +9,8 @@
|
|||||||
#include "LuaManager.h"
|
#include "LuaManager.h"
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
|
#include <json/json.h>
|
||||||
|
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -2515,7 +2517,205 @@ int LuaFunc_commify(lua_State* L)
|
|||||||
}
|
}
|
||||||
LUAFUNC_REGISTER_COMMON(commify);
|
LUAFUNC_REGISTER_COMMON(commify);
|
||||||
|
|
||||||
void luafunc_approach_internal(lua_State* L, int valind, int goalind, int speedind, const float mult);
|
int LuaFunc_JsonEncode(lua_State* L);
|
||||||
|
int LuaFunc_JsonEncode(lua_State* L)
|
||||||
|
{
|
||||||
|
int argc = lua_gettop(L);
|
||||||
|
bool minified = false;
|
||||||
|
|
||||||
|
if (argc < 1 || argc > 2)
|
||||||
|
{
|
||||||
|
luaL_error(L, "JsonEncode must be called with one or two arguments");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc == 2)
|
||||||
|
{
|
||||||
|
minified = lua_toboolean(L, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::function<Json::Value(int)> convert = [&L, &convert](int index) -> Json::Value
|
||||||
|
{
|
||||||
|
if (lua_isboolean(L, index))
|
||||||
|
{
|
||||||
|
return Json::Value(static_cast<bool>(lua_toboolean(L, index)));
|
||||||
|
}
|
||||||
|
else if (lua_isnil(L, index))
|
||||||
|
{
|
||||||
|
return Json::Value(Json::nullValue);
|
||||||
|
}
|
||||||
|
else if (lua_isnumber(L, index))
|
||||||
|
{
|
||||||
|
double val = lua_tonumber(L, index);
|
||||||
|
|
||||||
|
if (val == static_cast<Json::UInt>(val))
|
||||||
|
{
|
||||||
|
return Json::Value(static_cast<Json::UInt>(val));
|
||||||
|
}
|
||||||
|
else if (val == static_cast<Json::Int>(val))
|
||||||
|
{
|
||||||
|
return Json::Value(static_cast<Json::Int>(val));
|
||||||
|
}
|
||||||
|
return Json::Value(val);
|
||||||
|
}
|
||||||
|
else if (lua_isstring(L, index))
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
const char *s = lua_tolstring(L, index, &len);
|
||||||
|
|
||||||
|
return Json::Value(std::string(s, len));
|
||||||
|
}
|
||||||
|
else if (lua_istable(L, index))
|
||||||
|
{
|
||||||
|
// if the index is relative to the top of the stack,
|
||||||
|
// then calculate the absolute index, so we have a
|
||||||
|
// stable reference
|
||||||
|
if (index < 0)
|
||||||
|
{
|
||||||
|
index = lua_gettop(L) + index + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len = lua_objlen(L, index);
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
// array
|
||||||
|
Json::Value array(Json::arrayValue);
|
||||||
|
array.resize(len);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
lua_rawgeti(L, index, i + 1);
|
||||||
|
array[i] = convert(-1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// object
|
||||||
|
Json::Value obj(Json::objectValue);
|
||||||
|
|
||||||
|
lua_pushnil(L);
|
||||||
|
while (lua_next(L, index) != 0)
|
||||||
|
{
|
||||||
|
if (!lua_isstring(L, -2))
|
||||||
|
{
|
||||||
|
luaL_error(L, "object keys must be strings");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t keylen;
|
||||||
|
const char *key = lua_tolstring(L, -2, &keylen);
|
||||||
|
obj[std::string(key, keylen)] = convert(-1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.size() < 1)
|
||||||
|
{
|
||||||
|
return Json::Value(Json::arrayValue);
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int tp = lua_type(L, index);
|
||||||
|
luaL_error(L, "%s is not JSON serializable", lua_typename(L, tp));
|
||||||
|
return Json::Value(Json::nullValue); /* not reached */
|
||||||
|
};
|
||||||
|
|
||||||
|
Json::Value root = convert(1);
|
||||||
|
|
||||||
|
std::string data;
|
||||||
|
if(!minified)
|
||||||
|
{
|
||||||
|
Json::StyledWriter writer;
|
||||||
|
data = writer.write(root);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Json::FastWriter writer;
|
||||||
|
data = writer.write(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pushlstring(L, data.c_str(), data.length());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
LUAFUNC_REGISTER_COMMON(JsonEncode);
|
||||||
|
|
||||||
|
int LuaFunc_JsonDecode(lua_State* L);
|
||||||
|
int LuaFunc_JsonDecode(lua_State* L)
|
||||||
|
{
|
||||||
|
int argc = lua_gettop(L);
|
||||||
|
|
||||||
|
if (argc < 1)
|
||||||
|
{
|
||||||
|
luaL_error(L, "JsonDecode requires an argument");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t datalen;
|
||||||
|
const char *data = lua_tolstring(L, 1, &datalen);
|
||||||
|
|
||||||
|
Json::Reader reader;
|
||||||
|
Json::Value root;
|
||||||
|
|
||||||
|
bool ok = reader.parse(std::string(data, datalen), root, true);
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
std::string error = reader.getFormatedErrorMessages();
|
||||||
|
luaL_error(L, "failed to parse JSON: %s", error.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::function<void(const Json::Value&)> convert = [&L, &convert](const Json::Value& val)
|
||||||
|
{
|
||||||
|
if (val.isNull())
|
||||||
|
{
|
||||||
|
lua_pushnil(L);
|
||||||
|
}
|
||||||
|
else if (val.isInt() || val.isUInt() || val.isDouble())
|
||||||
|
{
|
||||||
|
lua_pushnumber(L, val.asDouble());
|
||||||
|
}
|
||||||
|
else if (val.isString())
|
||||||
|
{
|
||||||
|
std::string s = val.asString();
|
||||||
|
lua_pushlstring(L, s.c_str(), s.length());
|
||||||
|
}
|
||||||
|
else if (val.isBool())
|
||||||
|
{
|
||||||
|
lua_pushboolean(L, val.asBool());
|
||||||
|
}
|
||||||
|
else if (val.isArray())
|
||||||
|
{
|
||||||
|
lua_createtable(L, val.size(), 0);
|
||||||
|
for (int i = 0; i < val.size(); i++)
|
||||||
|
{
|
||||||
|
convert(val[i]);
|
||||||
|
lua_rawseti(L, -2, i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (val.isObject())
|
||||||
|
{
|
||||||
|
lua_createtable(L, 0, val.size());
|
||||||
|
for (const std::string& member : val.getMemberNames())
|
||||||
|
{
|
||||||
|
lua_pushlstring(L, member.c_str(), member.length());
|
||||||
|
convert(val[member]);
|
||||||
|
lua_rawset(L, -3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
luaL_error(L, "failed to parse JSON: invalid type");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
convert(root);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
LUAFUNC_REGISTER_COMMON(JsonDecode);
|
||||||
|
|
||||||
|
void luafunc_approach_internal(lua_State* L, int valind, int goalind, int speedind, const float mult, int process_index);
|
||||||
void luafunc_approach_internal(lua_State* L, int valind, int goalind, int speedind, const float mult, int process_index)
|
void luafunc_approach_internal(lua_State* L, int valind, int goalind, int speedind, const float mult, int process_index)
|
||||||
{
|
{
|
||||||
#define TONUMBER_NICE(dest, num_name, index) \
|
#define TONUMBER_NICE(dest, num_name, index) \
|
||||||
|
|||||||
Reference in New Issue
Block a user