#include <istream>
#include <ostream>
#include <iostream>
#include <strstream>
#include <list>
#include <map>
#include "cocos2d.h"
#include <math.h>
#define ENCODE_LUA_API 1
#ifndef LUA
# define LUA
#endif
#if defined(LUA) && (ENCODE_LUA_API > 0)
# define NEED_DEFINE_ENCODE_LUA_API 1
#endif
extern "C" {
# include "lua.h"
# include "lauxlib.h"
}
int CIO2_Lua_Open(lua_State *state);
using namespace std;
using namespace cocos2d;
//========================================= optimize =========================================
char* nil = new char(0x00); //memory leaks.
#define CIO_TYPE_NIL 0x7f //127
#define CIO_TYPE_FALSE 0x00
#define CIO_TYPE_TRUE 0x01
#define CIO_TYPE_INT 0x04
#define CIO_TYPE_STRING 0x05
#define CIO_TYPE_CSTR 0x06
#define CIO_TYPE_WSTR 0x07
#define CIO_TYPE_TABLE 0x08
#define CIO_TYPE_BYTES 0x09
#define CIO_TYPE_LONG 0x0a
#define CIO_TYPE_TIME 0x0b //long (2000-01-01 00:00:00)
#define CIO_TYPE_LIST 0x0c
#define CIO_TYPE_INTEGER_ARRAY 0x0d
#define CIO_TYPE_STRING_ARRAY 0x0e
#define CIO_TYPE_DOUBLE 0x0f
typedef std::map<char,char> STRING_MAP;
#define STRING_MAP_PAIR(k,v) pair<char, char>(k,v)
STRING_MAP TYPE_SHORT_STRING_MAP = {
STRING_MAP_PAIR(50, 0),
STRING_MAP_PAIR(51, 1),
STRING_MAP_PAIR(52, 2),
STRING_MAP_PAIR(53, 3),
STRING_MAP_PAIR(54, 4),
STRING_MAP_PAIR(55, 5),
STRING_MAP_PAIR(56, 6),
STRING_MAP_PAIR(57, 7),
STRING_MAP_PAIR(58, 8),
STRING_MAP_PAIR(59, 9),
STRING_MAP_PAIR(60, 10),
STRING_MAP_PAIR(61, 11),
STRING_MAP_PAIR(62, 12),
STRING_MAP_PAIR(63, 13),
STRING_MAP_PAIR(64, 14),
STRING_MAP_PAIR(65, 15),
STRING_MAP_PAIR(66, 16),
STRING_MAP_PAIR(67, 17),
STRING_MAP_PAIR(68, 18),
STRING_MAP_PAIR(69, 19),
STRING_MAP_PAIR(70, 20),
STRING_MAP_PAIR(71, 21),
STRING_MAP_PAIR(72, 22),
STRING_MAP_PAIR(73, 23),
STRING_MAP_PAIR(74, 24),
STRING_MAP_PAIR(75, 25),
STRING_MAP_PAIR(76, 32),
};
STRING_MAP TYPE_SHORT_STRING_MAP2 = {
STRING_MAP_PAIR(0, 50),
STRING_MAP_PAIR(1, 51),
STRING_MAP_PAIR(2, 52),
STRING_MAP_PAIR(3, 53),
STRING_MAP_PAIR(4, 54),
STRING_MAP_PAIR(5, 55),
STRING_MAP_PAIR(6, 56),
STRING_MAP_PAIR(7, 57),
STRING_MAP_PAIR(8, 58),
STRING_MAP_PAIR(9, 59),
STRING_MAP_PAIR(10, 60),
STRING_MAP_PAIR(11, 61),
STRING_MAP_PAIR(12, 62),
STRING_MAP_PAIR(13, 63),
STRING_MAP_PAIR(14, 64),
STRING_MAP_PAIR(15, 65),
STRING_MAP_PAIR(16, 66),
STRING_MAP_PAIR(17, 67),
STRING_MAP_PAIR(18, 68),
STRING_MAP_PAIR(19, 69),
STRING_MAP_PAIR(20, 70),
STRING_MAP_PAIR(21, 71),
STRING_MAP_PAIR(22, 72),
STRING_MAP_PAIR(23, 73),
STRING_MAP_PAIR(24, 74),
STRING_MAP_PAIR(25, 75),
STRING_MAP_PAIR(32, 76),
};
//=======================================end optimize =========================================
class StreamBuf4Encodeing;
namespace LuaArray {
enum Type {
STRING,
// NUMBER,
INT,
BOOLEAN,
};
class LuaArrayItem {
friend class StreamBuf4Encodeing;
public:
virtual ~LuaArrayItem(){
};
virtual Type getType() const = 0;
};
// class LuaArrayItemNumber : virtual public LuaArrayItem{
// private:
// lua_Number val;
// public:
// LuaArrayItemNumber(lua_Number val):val(val) { };
// virtual Type getType() const override { return Type::NUMBER; };
// inline lua_Number getValue() const{ return this->val; };
// };
class LuaArrayItemINT : virtual public LuaArrayItem{
private:
int val;
public:
LuaArrayItemINT(int val):val(val) { };
virtual Type getType() const override { return Type::INT; };
inline int getValue() const{ return this->val; };
};
class LuaArrayItemString : virtual public LuaArrayItem{
private:
std::string val;
public:
LuaArrayItemString(std::string _val):val(_val) { };
virtual Type getType() const override { return Type::STRING; };
inline std::string getValue() const{ return this->val; };
};
class LuaArrayItemBoolean : virtual public LuaArrayItem{
private:
bool val;
public:
LuaArrayItemBoolean(bool val):val(val) { };
virtual Type getType() const override { return Type::BOOLEAN; };
inline bool getValue(){ return this->val; };
};
class LuaArray{
private:
std::list<LuaArrayItem*> _list;
public:
~LuaArray(){
for(auto &itr:_list){
delete itr;
}
_list.clear();
};
inline std::list<LuaArrayItem*>& getList(){
return this->_list;
};
};
}
class StreamBuf4Encodeing {
# define DEFAULT_BUFFER_CAPACITY 2048
private:
char *buffer;
size_t capacity;
size_t pos ;
size_t size;
public:
StreamBuf4Encodeing():buffer(nullptr),
capacity(0),
pos(0),
size(0)
{
capacity = DEFAULT_BUFFER_CAPACITY;
buffer = (char*)malloc(capacity);
};
StreamBuf4Encodeing(char * c,int n){
new (this)StreamBuf4Encodeing();
if(DEFAULT_BUFFER_CAPACITY < n ){
if (buffer) free(buffer);
capacity = DEFAULT_BUFFER_CAPACITY;
buffer = (char*)malloc(capacity);
}
memcpy(buffer, c, n);
size = n;
};
virtual ~StreamBuf4Encodeing(void) {
free(buffer);
size = 0;
capacity = 0;
}
virtual std::string toString(){
return std::string(buffer,size);
}
private:
StreamBuf4Encodeing& operator << (LuaArray::LuaArrayItem * luaArrayItem){
auto type = luaArrayItem->getType();
switch (type) {
case LuaArray::Type::INT : {
LuaArray::LuaArrayItemINT *numItr =
dynamic_cast<LuaArray::LuaArrayItemINT*>(luaArrayItem);
int num = numItr->getValue();
this->_write_int((int)(num));
break;
}
case LuaArray::Type::STRING : {
LuaArray::LuaArrayItemString *strItr =
dynamic_cast<LuaArray::LuaArrayItemString*>(luaArrayItem);
std::string str = strItr->getValue();
this->Write_str(str);
break;
}
case LuaArray::Type::BOOLEAN :{
LuaArray::LuaArrayItemBoolean *boolItr =
dynamic_cast<LuaArray::LuaArrayItemBoolean*>(luaArrayItem);
bool b = boolItr->getValue();
if(b) this->Write_true();
else this->Write_false();
break;
}
default:
break;
}
return *this;
};
inline StreamBuf4Encodeing& _write_type_head(unsigned char val) {
return this->_write_char(val);
};
inline void remalloc(size_t cap){
if(cap > this->size){
char * rawBuf = this->buffer;
char * newbuf = (char*)malloc(cap);
this->buffer = newbuf;
memcpy(this->buffer,rawBuf,this->size);
free(rawBuf);
}else if(cap < this->size / 2){
char * rawBuf = this->buffer;
char * newbuf = (char*)malloc(cap);
this->buffer = newbuf;
memcpy(this->buffer,rawBuf,cap); //会导致数据丢失
this->size = cap;
this->pos = cap - 1;
free(rawBuf);
}
}
inline StreamBuf4Encodeing& _write_chars(char* c,size_t len) {
while(this->capacity < this->pos + len ){
this->remalloc(this->capacity * 2);
}
memcpy((this->buffer + pos),c, len);
pos+= len;
size += len;
return *this;
}
inline StreamBuf4Encodeing& _write_char(unsigned char val){
char c;
c = val;
this->_write_chars(&c,1);
return *this;
};
inline StreamBuf4Encodeing& _write_str(char *c,size_t len){
this->_write_chars(c,len);
return *this;
};
inline StreamBuf4Encodeing& _write_int(int i){
char *c = (char*)(&i);
this->_write_chars(c, sizeof(int));
return *this;
};
inline StreamBuf4Encodeing& _write_str(const char *c,size_t len){
char * vc = (char*)c;
return this->_write_str(vc,len);
};
public:
inline StreamBuf4Encodeing& Write_str(std::string val){
int len =(int) val.length();
if( TYPE_SHORT_STRING_MAP2.find(len) != TYPE_SHORT_STRING_MAP2.end()) {
char tlen = TYPE_SHORT_STRING_MAP2[len];
this->_write_char(tlen);
}else {
this->_write_type_head(CIO_TYPE_STRING);
this->_write_int(len);
}
return this->_write_str(val.c_str(),val.length());
};
inline StreamBuf4Encodeing& Write_number(lua_Number val){
if(floor(val) == val) {
int v = (int)val;
char * c = (char*) (&v);
this->_write_type_head(CIO_TYPE_INT);
this->_write_chars(c,sizeof(int));
}else {
this->_write_type_head(CIO_TYPE_DOUBLE);
char * c = (char*) (&val);
this->_write_chars(c, sizeof(lua_Number));
}
return *this;
};
inline StreamBuf4Encodeing& Write_false(){ return this ->_write_char(CIO_TYPE_FALSE); };
inline StreamBuf4Encodeing& Write_true(){ return this ->_write_char(CIO_TYPE_TRUE); };
inline StreamBuf4Encodeing& Write_nil(){ return this ->_write_char(CIO_TYPE_NIL); };
inline StreamBuf4Encodeing& Write_int(int val){
this->_write_type_head(CIO_TYPE_INT);
return this->_write_int(val);
};
inline StreamBuf4Encodeing& Write_table(StreamBuf4Encodeing & encode,size_t len){
this->_write_type_head(CIO_TYPE_TABLE);
this->_write_int((int)len);
std::string str = encode.toString();
this ->_write_str(str.c_str(),str.length());
return (*this) ;
};
inline StreamBuf4Encodeing& Write_int_array(StreamBuf4Encodeing & encode,size_t len){
this->_write_type_head(CIO_TYPE_INTEGER_ARRAY);
this->_write_int((int)len);
std::string str = encode.toString();
this ->_write_str(str.c_str(),str.length());
return (*this);
};
inline StreamBuf4Encodeing& Write_string_array(StreamBuf4Encodeing & encode,size_t len){
this->_write_type_head(CIO_TYPE_STRING_ARRAY);
this->_write_int((int)len);
std::string str = encode.toString();
this ->_write_str(str.c_str(),str.length());
return (*this);
};
};
class StreamBuf4Dencodeing{
private:
char * buffer;
int pos;
int size;
public:
StreamBuf4Dencodeing(char* c,int n):size(n),pos(0){
buffer = (char*)malloc(n);
memcpy(buffer, c, n);
};
~StreamBuf4Dencodeing(void){
free(buffer);
};
unsigned char readChar() {
char* ptr = buffer + pos;
// if(pos >40){
// char *temptr = buffer + pos - 40;
// int i = 0;
// }
pos++;
return ptr[0];
};
void readStr(char* _buf,int len) {
memcpy(_buf,buffer+pos,len);
pos+= len;
}
public:
int getPos() const {
return this->pos;
};
bool eof(){
return pos >= size;
}
unsigned char readType(){
return this->readChar();
}
lua_Number readNum() {
lua_Number num;
char * c = (char*)(&num);
this->readStr(c,sizeof(lua_Number));
return num;
};
int readInt() {
int num;
char * c = (char*)(&num);
this->readStr(c,sizeof(int));
return num;
};
void moveCursor(int n){
this->pos += n;
}
bool readBoolean() {
return this->readChar();
};
//有bug.还会导致逻辑混乱。
// std::string readString() {
//
// char tlen = this->readChar();
// this->moveCursor(-1);//不能影响游标,只是用来做检测,确定是进入什么逻辑
//
// int len = 0;
// if(TYPE_SHORT_STRING_MAP.find(tlen) != TYPE_SHORT_STRING_MAP.end()) {
// char tlen = this->readChar();
// len = TYPE_SHORT_STRING_MAP[tlen];
// }else {
// len = this->readInt();
// }
// return this->readString(len);
// };
std::string readString(int len) {
char *c = (char*)malloc(len);
this->readStr(c,len);
std::string str(c,len);
free(c);
return str;
};
};
extern "C" {
static int cio2_encode_table(lua_State *L, StreamBuf4Encodeing &encode) ;
static void cio2_encode_val(lua_State *L,int stackIdx, StreamBuf4Encodeing &encode);
static int cio_decode_array(lua_State *L,StreamBuf4Dencodeing& decoder,unsigned char type);
static int cio_decode_list(lua_State *L,StreamBuf4Dencodeing& decoder);
static int cio_decode_table(lua_State *L ,StreamBuf4Dencodeing& decoder,size_t len);
static int __gcReleaseLuaArray(lua_State *L);
static int __gcReleaseLuaArray(lua_State* L) {
int top = lua_gettop(L);
int t = lua_type(L,top);
if(t == LUA_TUSERDATA ) {
void * ud = lua_touserdata(L, top);
LuaArray::LuaArray **array = (LuaArray::LuaArray**)(ud);
if(*array == nullptr) return 0;
delete *array;
*array = nullptr;
}
return 0;
};
static void cio2_encode_val(lua_State *L,int stackIdx, StreamBuf4Encodeing &encode){
int nodeType = lua_type(L, stackIdx);
switch (nodeType) {
case LUA_TNUMBER:
{
encode.Write_number(lua_tonumber(L, stackIdx));
break;
}
case LUA_TSTRING:
{
encode.Write_str(lua_tostring(L, stackIdx));
break;
}
case LUA_TTABLE:
{
cio2_encode_table(L,encode);
break;
}
case LUA_TBOOLEAN:{
int _bool = lua_toboolean(L, stackIdx);
if(_bool) encode.Write_true();
else encode.Write_false();
break;
}
case LUA_TUSERDATA:
{
StreamBuf4Encodeing tencode;
LuaArray::LuaArray **array = (LuaArray::LuaArray**)lua_touserdata(L, stackIdx);
char type = 0x00;
for(auto &itr: (*array)->getList()) {
switch(itr->getType()){
case LuaArray::Type::BOOLEAN: {
//
// LuaArray::LuaArrayItem *arrayItr = &(*itr);
// LuaArray::LuaArrayItemBoolean *_bool = dynamic_cast<LuaArray::LuaArrayItemBoolean*>(arrayItr) ;
// if(_bool->getValue()==true) tencode.Write_true();
// else tencode.Write_false();
printf("%s","不支持boolean 数组的解码!");
break;
}
case LuaArray::Type::INT : {
LuaArray::LuaArrayItem *arrayItr = &(*itr);
LuaArray::LuaArrayItemINT *num = dynamic_cast<LuaArray::LuaArrayItemINT*>(arrayItr) ;
tencode.Write_int(num->getValue());
type = CIO_TYPE_INTEGER_ARRAY;
break;
}
case LuaArray::Type::STRING :{
LuaArray::LuaArrayItem *arrayItr = &(*itr);
LuaArray::LuaArrayItemString *str = dynamic_cast<LuaArray::LuaArrayItemString*>(arrayItr) ;
tencode.Write_str(str->getValue());
type = CIO_TYPE_STRING_ARRAY;
break;
}
}
}
//write to buffer;
switch(type){
case CIO_TYPE_INTEGER_ARRAY:{
encode.Write_int_array(tencode, (*array)->getList().size());
break;
}
case CIO_TYPE_STRING_ARRAY:{
encode.Write_string_array(tencode, (*array)->getList().size());
break;
}
}
}
default:
break;
}
}
static int cio2_encode_table(lua_State *L, StreamBuf4Encodeing &encode) {
int top = lua_gettop(L);
int type = lua_type(L, top);
if(type != LUA_TTABLE) {
luaL_error(L,"%s","arg must a table.");
return -1;
}
lua_pushnil(L);
StreamBuf4Encodeing tencode;
int len = 0 ;
while (lua_next(L, top) != 0) {
cio2_encode_val(L, -2, tencode); //key
cio2_encode_val(L, -1, tencode); //value
len++;
lua_pop(L, 1); //clean processed.
}
encode.Write_table(tencode, len);
return 0;
};
static int cio_encode(lua_State *L) {
int RET_ARG_LEN = 1;
int top = lua_gettop(L);
int t = lua_type(L, top);
if(t != LUA_TTABLE){
luaL_error(L, "%s","argment must a table when call \"by cio_encode\"");
return RET_ARG_LEN;
}
StreamBuf4Encodeing ecode;
int ret = cio2_encode_table(L, ecode);
if(ret !=0){
luaL_error(L, "%s","decode table fail by cio_encode.");
return -1;
}else {
std::string str = ecode.toString();
lua_pushlstring(L, str.c_str(), str.length());
return RET_ARG_LEN;
}
return 0;
}
static int cio_table_toarray(lua_State *L) {
int top = lua_gettop(L);
int type =lua_type(L, top);
if(type != LUA_TTABLE ) {
luaL_error(L, "%s","arguments must a table");
return 0;
}
lua_pushnil(L);
LuaArray::LuaArray *array = new LuaArray::LuaArray();
while (lua_next(L, top) != 0) {
int valtype = lua_type(L,-1);
switch(valtype){
case LUA_TNUMBER:
{
lua_Number num = lua_tonumber(L, -1);
LuaArray::LuaArrayItemINT *udNum = new LuaArray::LuaArrayItemINT(num);
array->getList(). push_back(udNum);
break;
}
case LUA_TSTRING:
{
const char* str = lua_tostring(L, -1);
LuaArray::LuaArrayItemString *udStr = new LuaArray::LuaArrayItemString(str);
array->getList().push_back(udStr);
break;
}
case LUA_TBOOLEAN:
{
int num = lua_toboolean(L, -1);
LuaArray::LuaArrayItemBoolean *udBool = new LuaArray::LuaArrayItemBoolean(num);
array->getList().push_back(udBool);
break;
}
}
lua_pop(L, 1); //clean processed.
}
lua_pushnumber(L, 0);
//new userdata.
LuaArray::LuaArray ** array_userdata = (LuaArray::LuaArray **)lua_newuserdata(L, sizeof(LuaArray::LuaArray*));
*array_userdata = array;
//bing metatable
luaL_getmetatable(L, "LuaArray");
lua_setmetatable(L, -2);
return 1;
}
static int cio_decode_val(lua_State* L,StreamBuf4Dencodeing& decoder){
unsigned char type = decoder.readType();
//优化操作
if(TYPE_SHORT_STRING_MAP.find(type)!= TYPE_SHORT_STRING_MAP.end()){
int len = TYPE_SHORT_STRING_MAP[type];
std::string str = decoder.readString(len);
lua_pushlstring(L, str.c_str(), len);
}else{
// printf("--------%c",type);
switch (type) {
case CIO_TYPE_NIL : lua_pushnil(L); break;
case CIO_TYPE_FALSE : lua_pushboolean(L, 0);break;
case CIO_TYPE_TRUE : lua_pushboolean(L, 1);break;
case CIO_TYPE_INT : lua_pushinteger(L, decoder.readInt()); break;
case CIO_TYPE_STRING :
{
//std::string str = decoder.readString();
int len = decoder.readInt();
std::string str = decoder.readString(len);
lua_pushlstring(L, str.c_str(), str.length());
break;
}
case CIO_TYPE_CSTR :break;
case CIO_TYPE_WSTR :break;
case CIO_TYPE_TABLE :{
//cio_decode_val(L,decoder);
int len = decoder.readInt();
// decoder.moveCursor(-sizeof(int));
cio_decode_table(L,decoder,len);
break;
}
case CIO_TYPE_BYTES :break;
case CIO_TYPE_LONG :break;
case CIO_TYPE_TIME :break;
case CIO_TYPE_LIST :
{
cio_decode_list(L,decoder);
break;
}
case CIO_TYPE_INTEGER_ARRAY :
case CIO_TYPE_STRING_ARRAY :
{
cio_decode_array(L,decoder,type);
break;
}
case CIO_TYPE_DOUBLE : lua_pushnumber(L, decoder.readNum());break;
default:
break;
}
}
return 0;
};
static int cio_decode_array(lua_State *L,StreamBuf4Dencodeing& decoder,unsigned char type){
int len = decoder.readInt();
lua_newtable(L);
for( int i = 1 ;i <= len; i++) {
lua_pushnumber(L, i); //key
cio_decode_val(L,decoder); //value
lua_settable(L, -3);
}
return 0;
};
static int cio_decode_list(lua_State *L,StreamBuf4Dencodeing& decoder){
int len = decoder.readInt();
lua_newtable(L);
for( int i = 1 ;i <= len; i++) {
lua_pushnumber(L, i); //key
cio_decode_val(L,decoder); //value
lua_settable(L, -3);
}
return 0;
};
static int i = 0;
static int cio_decode_table(lua_State *L ,StreamBuf4Dencodeing& decoder,size_t len) {
lua_newtable(L);
while (!decoder.eof() && len) {
cio_decode_val(L,decoder); //key
cio_decode_val(L,decoder); //value
lua_settable(L, -3);
len --;
}
return 0;
};
static int cio_decode(lua_State *L) {
int top = lua_gettop(L);
int t = lua_type(L,top);
if(t != LUA_TSTRING) {
luaL_error(L,"%s","arg must string.");
return -1;
}
size_t size;
const char * c = lua_tolstring(L,top,&size);
StreamBuf4Dencodeing decoder((char*)c,(int)size); //bug.长度丢失
if(decoder.readType() != CIO_TYPE_TABLE ) {
luaL_error(L, "%s","the encode is not encode from a lua table.");
return -1;
}
int len = decoder.readInt();
int ret = cio_decode_table(L, decoder,len);
if(ret == 0){
int processBuferLen = decoder.getPos();
lua_pushnumber(L, processBuferLen); //已处理的长度
return 2;
}
else luaL_error(L,"%s", "decode error!");
return 1;
}
}
#ifdef NEED_DEFINE_ENCODE_LUA_API
int CIO2_Lua_Open(lua_State *L) {
//register coi2 api
const struct luaL_Reg cio2_libs [] = {
{"Encode",cio_encode},
{"Decode",cio_decode},
{"ToArray",cio_table_toarray },
{NULL,NULL}
};
luaL_register(L, "CIO2", cio2_libs);
//register lua array metatable.
const struct luaL_Reg cio2_lua_array [] = {
{NULL,NULL}
};
//luaarray 元表
luaL_newmetatable(L, "LuaArray");
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, __gcReleaseLuaArray);
lua_setfield(L,-2,"__gc");
luaL_register(L, "LuaArray", cio2_lua_array);
return 0;
};
#endif