414 lines
12 KiB
C++
414 lines
12 KiB
C++
/****************************************************************************
|
|
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
|
|
|
http://www.cocos.com
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated engine source code (the "Software"), a limited,
|
|
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
|
to use Cocos Creator solely to develop games on your target platforms. You shall
|
|
not use Cocos Creator software for developing other software or tools that's
|
|
used for developing games. You are not granted to publish, distribute,
|
|
sublicense, and/or sell copies of Cocos Creator.
|
|
|
|
The software or tools in this License Agreement are licensed, not sold.
|
|
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
****************************************************************************/
|
|
|
|
#include "jsb_cocos2dx_manual.hpp"
|
|
|
|
#include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
|
|
#include "cocos/scripting/js-bindings/manual/jsb_conversions.hpp"
|
|
//#include "cocos/scripting/js-bindings/manual/jsb_global.h"
|
|
|
|
#include "storage/local-storage/LocalStorage.h"
|
|
#include <sstream>
|
|
|
|
using namespace cocos2d;
|
|
|
|
extern se::Object* __jsb_cocos2d_FileUtils_proto;
|
|
|
|
static bool jsb_cocos2dx_empty_func(se::State& s)
|
|
{
|
|
return true;
|
|
}
|
|
SE_BIND_FUNC(jsb_cocos2dx_empty_func)
|
|
|
|
class __JSPlistDelegator: public cocos2d::SAXDelegator
|
|
{
|
|
public:
|
|
static __JSPlistDelegator* getInstance() {
|
|
static __JSPlistDelegator* pInstance = NULL;
|
|
if (pInstance == NULL) {
|
|
pInstance = new (std::nothrow) __JSPlistDelegator();
|
|
}
|
|
return pInstance;
|
|
};
|
|
|
|
virtual ~__JSPlistDelegator();
|
|
|
|
cocos2d::SAXParser* getParser();
|
|
|
|
std::string parse(const std::string& path);
|
|
std::string parseText(const std::string& text);
|
|
|
|
// implement pure virtual methods of SAXDelegator
|
|
void startElement(void *ctx, const char *name, const char **atts) override;
|
|
void endElement(void *ctx, const char *name) override;
|
|
void textHandler(void *ctx, const char *ch, int len) override;
|
|
|
|
private:
|
|
cocos2d::SAXParser _parser;
|
|
std::string _result;
|
|
bool _isStoringCharacters;
|
|
std::string _currentValue;
|
|
};
|
|
|
|
cocos2d::SAXParser* __JSPlistDelegator::getParser() {
|
|
return &_parser;
|
|
}
|
|
|
|
std::string __JSPlistDelegator::parse(const std::string& path) {
|
|
_result.clear();
|
|
|
|
SAXParser parser;
|
|
if (false != parser.init("UTF-8") )
|
|
{
|
|
parser.setDelegator(this);
|
|
parser.parse(FileUtils::getInstance()->fullPathForFilename(path));
|
|
}
|
|
|
|
return _result;
|
|
}
|
|
|
|
__JSPlistDelegator::~__JSPlistDelegator(){
|
|
CCLOGINFO("deallocing __JSSAXDelegator: %p", this);
|
|
}
|
|
|
|
std::string __JSPlistDelegator::parseText(const std::string& text){
|
|
_result.clear();
|
|
|
|
SAXParser parser;
|
|
if (false != parser.init("UTF-8") )
|
|
{
|
|
parser.setDelegator(this);
|
|
parser.parse(text.c_str(), text.size());
|
|
}
|
|
|
|
return _result;
|
|
}
|
|
|
|
void __JSPlistDelegator::startElement(void *ctx, const char *name, const char **atts) {
|
|
_isStoringCharacters = true;
|
|
_currentValue.clear();
|
|
|
|
std::string elementName = (char*)name;
|
|
|
|
int end = (int)_result.size() - 1;
|
|
if(end >= 0 && _result[end] != '{' && _result[end] != '[' && _result[end] != ':') {
|
|
_result += ",";
|
|
}
|
|
|
|
if (elementName == "dict") {
|
|
_result += "{";
|
|
}
|
|
else if (elementName == "array") {
|
|
_result += "[";
|
|
}
|
|
}
|
|
|
|
void __JSPlistDelegator::endElement(void *ctx, const char *name) {
|
|
_isStoringCharacters = false;
|
|
std::string elementName = (char*)name;
|
|
|
|
if (elementName == "dict") {
|
|
_result += "}";
|
|
}
|
|
else if (elementName == "array") {
|
|
_result += "]";
|
|
}
|
|
else if (elementName == "key") {
|
|
_result += "\"" + _currentValue + "\":";
|
|
}
|
|
else if (elementName == "string") {
|
|
_result += "\"" + _currentValue + "\"";
|
|
}
|
|
else if (elementName == "false" || elementName == "true") {
|
|
_result += elementName;
|
|
}
|
|
else if (elementName == "real" || elementName == "integer") {
|
|
_result += _currentValue;
|
|
}
|
|
}
|
|
|
|
void __JSPlistDelegator::textHandler(void*, const char *ch, int len) {
|
|
std::string text((char*)ch, 0, len);
|
|
|
|
if (_isStoringCharacters)
|
|
{
|
|
_currentValue += text;
|
|
}
|
|
}
|
|
|
|
|
|
// cc.sys.localStorage
|
|
|
|
static bool JSB_localStorageGetItem(se::State& s)
|
|
{
|
|
const auto& args = s.args();
|
|
size_t argc = args.size();
|
|
if (argc == 1)
|
|
{
|
|
std::string ret_val;
|
|
bool ok = true;
|
|
std::string key;
|
|
ok = seval_to_std_string(args[0], &key);
|
|
SE_PRECONDITION2(ok, false, "Error processing arguments");
|
|
std::string value;
|
|
ok = localStorageGetItem(key, &value);
|
|
if (ok)
|
|
s.rval().setString(value);
|
|
else
|
|
s.rval().setNull(); // Should return null to make JSB behavior same as Browser since returning undefined will make JSON.parse(undefined) trigger exception.
|
|
|
|
return true;
|
|
}
|
|
|
|
SE_REPORT_ERROR("Invalid number of arguments");
|
|
return false;
|
|
}
|
|
SE_BIND_FUNC(JSB_localStorageGetItem)
|
|
|
|
static bool JSB_localStorageRemoveItem(se::State& s)
|
|
{
|
|
const auto& args = s.args();
|
|
size_t argc = args.size();
|
|
if (argc == 1)
|
|
{
|
|
bool ok = true;
|
|
std::string key;
|
|
ok = seval_to_std_string(args[0], &key);
|
|
SE_PRECONDITION2(ok, false, "Error processing arguments");
|
|
localStorageRemoveItem(key);
|
|
return true;
|
|
}
|
|
|
|
SE_REPORT_ERROR("Invalid number of arguments");
|
|
return false;
|
|
}
|
|
SE_BIND_FUNC(JSB_localStorageRemoveItem)
|
|
|
|
static bool JSB_localStorageSetItem(se::State& s)
|
|
{
|
|
const auto& args = s.args();
|
|
size_t argc = args.size();
|
|
if (argc == 2)
|
|
{
|
|
bool ok = true;
|
|
std::string key;
|
|
ok = seval_to_std_string(args[0], &key);
|
|
SE_PRECONDITION2(ok, false, "Error processing arguments");
|
|
|
|
std::string value;
|
|
ok = seval_to_std_string(args[1], &value);
|
|
SE_PRECONDITION2(ok, false, "Error processing arguments");
|
|
localStorageSetItem(key, value);
|
|
return true;
|
|
}
|
|
|
|
SE_REPORT_ERROR("Invalid number of arguments");
|
|
return false;
|
|
}
|
|
SE_BIND_FUNC(JSB_localStorageSetItem)
|
|
|
|
static bool JSB_localStorageClear(se::State& s)
|
|
{
|
|
const auto& args = s.args();
|
|
size_t argc = args.size();
|
|
if (argc == 0)
|
|
{
|
|
localStorageClear();
|
|
return true;
|
|
}
|
|
|
|
SE_REPORT_ERROR("Invalid number of arguments");
|
|
return false;
|
|
}
|
|
SE_BIND_FUNC(JSB_localStorageClear)
|
|
|
|
static bool JSB_localStorageKey(se::State& s) {
|
|
const auto &args = s.args();
|
|
size_t argc = args.size();
|
|
if (argc == 1) {
|
|
bool ok = true;
|
|
int nIndex = 0;
|
|
ok = seval_to_int32(args[0], &nIndex);
|
|
SE_PRECONDITION2(ok, false, "Error processing arguments");
|
|
std::string value;
|
|
localStorageGetKey(nIndex, &value);
|
|
s.rval().setString(value);
|
|
return true;
|
|
}
|
|
|
|
SE_REPORT_ERROR("Invalid number of arguments");
|
|
return false;
|
|
}
|
|
SE_BIND_FUNC(JSB_localStorageKey)
|
|
|
|
static bool JSB_localStorage_getLength(se::State& s)
|
|
{
|
|
const auto& args = s.args();
|
|
size_t argc = args.size();
|
|
if (argc == 0) {
|
|
int nLength = 0;
|
|
|
|
localStorageGetLength(nLength);
|
|
s.rval().setInt32(nLength);
|
|
return true;
|
|
}
|
|
|
|
SE_REPORT_ERROR("Invalid number of arguments");
|
|
return false;
|
|
}
|
|
SE_BIND_PROP_GET(JSB_localStorage_getLength);
|
|
|
|
static bool register_sys_localStorage(se::Object* obj)
|
|
{
|
|
se::Value sys;
|
|
if (!obj->getProperty("sys", &sys))
|
|
{
|
|
se::HandleObject sysObj(se::Object::createPlainObject());
|
|
obj->setProperty("sys", se::Value(sysObj));
|
|
sys.setObject(sysObj);
|
|
}
|
|
|
|
se::HandleObject localStorageObj(se::Object::createPlainObject());
|
|
sys.toObject()->setProperty("localStorage", se::Value(localStorageObj));
|
|
|
|
localStorageObj->defineFunction("getItem", _SE(JSB_localStorageGetItem));
|
|
localStorageObj->defineFunction("removeItem", _SE(JSB_localStorageRemoveItem));
|
|
localStorageObj->defineFunction("setItem", _SE(JSB_localStorageSetItem));
|
|
localStorageObj->defineFunction("clear", _SE(JSB_localStorageClear));
|
|
localStorageObj->defineFunction("key", _SE(JSB_localStorageKey));
|
|
localStorageObj->defineProperty("length", _SE(JSB_localStorage_getLength), nullptr);
|
|
|
|
std::string strFilePath = cocos2d::FileUtils::getInstance()->getWritablePath();
|
|
strFilePath += "/jsb.sqlite";
|
|
localStorageInit(strFilePath);
|
|
|
|
se::ScriptEngine::getInstance()->addBeforeCleanupHook([](){
|
|
localStorageFree();
|
|
});
|
|
|
|
se::ScriptEngine::getInstance()->clearException();
|
|
|
|
return true;
|
|
}
|
|
|
|
#define BIND_PROP_WITH_TYPE__CONV_FUNC__RETURN(cls, property, type, convertFunc, returnFunc) \
|
|
static bool js_##cls_set_##property(se::State& s) \
|
|
{ \
|
|
cocos2d::cls* cobj = (cocos2d::cls*)s.nativeThisObject(); \
|
|
SE_PRECONDITION2(cobj, false, "js_#cls_set_#property : Invalid Native Object"); \
|
|
const auto& args = s.args(); \
|
|
size_t argc = args.size(); \
|
|
bool ok = true; \
|
|
if (argc == 1) { \
|
|
type arg0; \
|
|
ok &= convertFunc(args[0], &arg0); \
|
|
SE_PRECONDITION2(ok, false, "js_#cls_set_#property : Error processing arguments"); \
|
|
cobj->set_##property(arg0); \
|
|
return true; \
|
|
} \
|
|
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1); \
|
|
return false; \
|
|
} \
|
|
SE_BIND_PROP_SET(js_##cls_set_##property) \
|
|
\
|
|
static bool js_##cls_get_##property(se::State& s) \
|
|
{ \
|
|
cocos2d::cls* cobj = (cocos2d::cls*)s.nativeThisObject(); \
|
|
SE_PRECONDITION2(cobj, false, "js_#cls_get_#property : Invalid Native Object"); \
|
|
s.rval().returnFunc(cobj->_##property); \
|
|
return true; \
|
|
} \
|
|
SE_BIND_PROP_GET(js_##cls_get_##property)
|
|
|
|
|
|
|
|
|
|
#define _SE_DEFINE_PROP(cls, property) \
|
|
__jsb_cocos2d_##cls##_proto->defineProperty(#property, _SE(js_##cls_get_##property), _SE(js_##cls_set_##property));
|
|
|
|
//IDEA: move to auto bindings.
|
|
|
|
|
|
|
|
static bool js_se_setExceptionCallback(se::State &s) {
|
|
|
|
auto &args = s.args();
|
|
if (args.size() != 1 || !args[0].isObject() || !args[0].toObject()->isFunction()) {
|
|
SE_REPORT_ERROR("expect 1 arguments of Function type, %d provided", (int)args.size());
|
|
return false;
|
|
}
|
|
|
|
se::Object *objFunc = args[0].toObject();
|
|
// se::Value::reset will invoke decRef() while destroying s.args()
|
|
// increase ref here
|
|
objFunc->incRef();
|
|
if (s.thisObject()) {
|
|
s.thisObject()->attachObject(objFunc); // prevent GC
|
|
} else {
|
|
//prevent GC in C++ & JS
|
|
objFunc->root();
|
|
}
|
|
|
|
se::ScriptEngine::getInstance()->setJSExceptionCallback([objFunc](const char *location, const char *message, const char *stack) {
|
|
se::ValueArray jsArgs;
|
|
jsArgs.resize(3);
|
|
jsArgs[0] = se::Value(location);
|
|
jsArgs[1] = se::Value(message);
|
|
jsArgs[2] = se::Value(stack);
|
|
objFunc->call(jsArgs, nullptr);
|
|
});
|
|
return true;
|
|
}
|
|
SE_BIND_FUNC(js_se_setExceptionCallback)
|
|
|
|
|
|
#define DESCRIPT_FIELD(kls, field, field_type) do {\
|
|
ss << "\"" << #field << "\": " << "{" ; \
|
|
ss << "\"type\": \"" << field_type << "\"," ; \
|
|
ss << "\"offset\": " << offsetof(kls, field) << ","; \
|
|
ss << "\"size\": " << sizeof(((kls*)nullptr)->field); \
|
|
ss << "}";} while(false)
|
|
|
|
|
|
static bool register_se_setExceptionCallback(se::Object *obj)
|
|
{
|
|
se::Value jsb;
|
|
if (!obj->getProperty("jsb", &jsb)) {
|
|
jsb.setObject(se::Object::createPlainObject());
|
|
obj->setProperty("jsb", jsb);
|
|
}
|
|
auto *jsbObj = jsb.toObject();
|
|
jsbObj->defineFunction("onError", _SE(js_se_setExceptionCallback));
|
|
return true;
|
|
}
|
|
|
|
bool register_all_cocos2dx_manual(se::Object* obj)
|
|
{
|
|
register_sys_localStorage(obj);
|
|
register_se_setExceptionCallback(obj);
|
|
return true;
|
|
}
|
|
|