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='IsSMOnlineLoggedIn'/>
|
||||
<Function name='IsUsingWideScreen'/>
|
||||
<Function name='JsonDecode'/>
|
||||
<Function name='JsonEncode'/>
|
||||
<Function name='JudgmentLineToColor'/>
|
||||
<Function name='JudgmentLineToLocalizedString'/>
|
||||
<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'>
|
||||
[02 Utilities.lua] Joins a table, splitting each item with <code>delimiter</code>, returning a string of the results.
|
||||
</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'>
|
||||
[02 Colors.lua]
|
||||
</Function>
|
||||
|
||||
+201
-1
@@ -9,6 +9,8 @@
|
||||
#include "LuaManager.h"
|
||||
#include <float.h>
|
||||
|
||||
#include <json/json.h>
|
||||
|
||||
#include <numeric>
|
||||
#include <ctime>
|
||||
#include <sstream>
|
||||
@@ -2515,7 +2517,205 @@ int LuaFunc_commify(lua_State* L)
|
||||
}
|
||||
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)
|
||||
{
|
||||
#define TONUMBER_NICE(dest, num_name, index) \
|
||||
|
||||
Reference in New Issue
Block a user