github.com/aergoio/aergo@v1.3.1/contract/util.c (about)

     1  #include <stdlib.h>
     2  #include <stdio.h>
     3  #include <string.h>
     4  #include <ctype.h>
     5  #include "util.h"
     6  #include "vm.h"
     7  #include "math.h"
     8  #include "lgmp.h"
     9  
    10  typedef struct sbuff {
    11  	char *buf;
    12  	int idx;
    13  	int buf_len;
    14  } sbuff_t;
    15  
    16  typedef struct tcall {
    17  	void **ptrs;
    18  	int curidx;
    19  	int size;
    20  } callinfo_t;
    21  
    22  typedef struct sort_key {
    23      char *elem;
    24      int start_idx;
    25      int key_len;
    26  } sort_key_t;
    27  
    28  static void lua_util_sbuf_init(sbuff_t *sbuf, int len)
    29  {
    30  	sbuf->idx = 0;
    31  	sbuf->buf_len = len;
    32  	sbuf->buf = malloc (len);
    33  }
    34  
    35  static void copy_to_buffer(char *src, int len, sbuff_t *sbuf)
    36  {
    37  	int orig_buf_len = sbuf->buf_len;
    38  	while (len + sbuf->idx >= sbuf->buf_len) {
    39  		sbuf->buf_len *= 2;
    40  	}
    41  	if (sbuf->buf_len != orig_buf_len) {
    42  		sbuf->buf = realloc (sbuf->buf, sbuf->buf_len);
    43  	}
    44  	memcpy (sbuf->buf + sbuf->idx, src, len);
    45  	sbuf->idx += len;
    46  }
    47  
    48  static void add_escape (sbuff_t *sbuf, char ch)
    49  {
    50  	if (sbuf->idx + 2 >= sbuf->buf_len) {
    51  		sbuf->buf_len *= 2;
    52  		sbuf->buf = realloc (sbuf->buf, sbuf->buf_len);
    53  	}
    54  	sbuf->buf[sbuf->idx++] = '\\';
    55  	sbuf->buf[sbuf->idx++] = ch;
    56  }
    57  
    58  static void copy_str_to_buffer(char *src, int len, sbuff_t *sbuf)
    59  {
    60  	int i;
    61  
    62  	char *end = src + len;
    63  
    64  	for (; src < end; ++src) {
    65  		if (*src >= 0x00 && *src <= 0x1f) {
    66  			if (sbuf->idx + 6 >= sbuf->buf_len) {
    67  				sbuf->buf_len = sbuf->buf_len * 2 + 6;
    68  				sbuf->buf = realloc (sbuf->buf, sbuf->buf_len);
    69  			}
    70  			sprintf(sbuf->buf + sbuf->idx, "\\u00%02x", *src);
    71  			sbuf->idx = sbuf->idx + 6;
    72  			continue;
    73  		}
    74  		switch(*src) {
    75  		case '"':
    76  		case '\\':
    77  			add_escape(sbuf, *src);
    78  			break;
    79  		case '\t':
    80  			add_escape(sbuf, 't');
    81  			break;
    82  		case '\n':
    83  			add_escape(sbuf, 'n');
    84  			break;
    85  		case '\b':
    86  			add_escape(sbuf, 'b');
    87  			break;
    88  		case '\f':
    89  			add_escape(sbuf, 'f');
    90  			break;
    91  		case '\r':
    92  			add_escape(sbuf, 'r');
    93  			break;
    94  		default:
    95  			if (sbuf->idx + 1 >= sbuf->buf_len) {
    96  				sbuf->buf_len *= 2;
    97  				sbuf->buf = realloc (sbuf->buf, sbuf->buf_len);
    98  			}
    99  			sbuf->buf[sbuf->idx++] = *src;
   100  		}
   101  	}
   102  }
   103  static callinfo_t *callinfo_new()
   104  {
   105  	callinfo_t *callinfo = malloc(sizeof(callinfo_t));
   106  	callinfo->size = 4;
   107  	callinfo->ptrs = malloc(sizeof(void *) * callinfo->size);
   108  	callinfo->curidx = 0;
   109  
   110  	return callinfo;
   111  }
   112  
   113  static void callinfo_del(callinfo_t *callinfo)
   114  {
   115  	if (callinfo == NULL)
   116  		return;
   117  	free (callinfo->ptrs);
   118  	free (callinfo);
   119  }
   120  
   121  static bool register_tcall(callinfo_t *callinfo, void *ptr)
   122  {
   123  	int i;
   124  
   125  	for(i = 0; i < callinfo->curidx; i++) {
   126  		if (callinfo->ptrs[i] == ptr)
   127  			return false;
   128  	}
   129  	if (callinfo->curidx == callinfo->size) {
   130  		callinfo->size *= 2;
   131  		callinfo->ptrs = realloc(callinfo->ptrs, sizeof(void *) * callinfo->size);
   132  	}
   133  	callinfo->ptrs[callinfo->curidx++] = ptr;
   134  	return true;
   135  }
   136  
   137  static void unregister_tcall(callinfo_t *callinfo)
   138  {
   139  	callinfo->curidx--;
   140  }
   141  
   142  static int sort_key_compare (const void *first, const void*second)
   143  {
   144      sort_key_t *key1 = (sort_key_t *)first, *key2 = (sort_key_t *)second;
   145      if (key1->key_len == key2->key_len) {
   146          return strcmp(key1->elem, key2->elem);
   147      }
   148      else {
   149          int comp_len = (key1->key_len > key2->key_len ? key2->key_len : key1->key_len);
   150          int ret = strncmp (key1->elem, key2->elem, comp_len);
   151          if (ret == 0)
   152              return (key1->key_len > key2->key_len ? 1 : -1);
   153          return ret;
   154      }
   155  }
   156  
   157  char *bignum_str = "{\"_bignum\":\"";
   158  
   159  static bool lua_util_dump_json (lua_State *L, int idx, sbuff_t *sbuf, bool json_form, bool iskey,
   160  						 callinfo_t **pcallinfo)
   161  {
   162  	int len;
   163  	char *src_val;
   164  	char tmp[128];
   165  
   166  	switch (lua_type(L, idx)) {
   167  	case LUA_TNUMBER: {
   168  		if (json_form && iskey) {
   169  			if (luaL_isinteger(L, idx)) {
   170  				len = sprintf (tmp, "\"%ld\",", lua_tointeger(L, idx));
   171  			}
   172  			else {
   173  			    double d = lua_tonumber(L, idx);
   174  			    if (isinf(d) || isnan(d)) {
   175  			        lua_pushstring(L, "not support nan or infinity");
   176  			        return false;
   177  			    }
   178  				len = sprintf (tmp, "\"%.14g\",", d);
   179  			}
   180  		}
   181  		else {
   182  			if (luaL_isinteger(L, idx)) {
   183  				len = sprintf (tmp, "%ld,", lua_tointeger(L, idx));
   184  			}
   185  			else {
   186  				double d = lua_tonumber(L, idx);
   187  			    if (isinf(d) || isnan(d)) {
   188  			        lua_pushstring(L, "not support nan or infinity");
   189  			        return false;
   190  			    }
   191  			    len = sprintf (tmp, "%.14g,", lua_tonumber(L, idx));
   192  			}
   193  		}
   194  		src_val = tmp;
   195  		break;
   196  	}
   197  	case LUA_TBOOLEAN: {
   198  		if (lua_toboolean(L, idx))
   199  			src_val = "true,";
   200  		else
   201  			src_val = "false,";
   202  		break;
   203  	}
   204  	case LUA_TNIL:
   205  		if (json_form)
   206  			src_val = "{},";
   207  		else
   208  			src_val = "null,";
   209  		break;
   210  	case LUA_TSTRING: {
   211  		size_t len;
   212  		src_val = (char *)lua_tolstring(L, idx, &len);
   213  		copy_to_buffer ("\"", 1, sbuf);
   214  		copy_str_to_buffer (src_val, len, sbuf);
   215  		src_val = "\",";
   216  		break;
   217  	}
   218  	case LUA_TTABLE: {
   219  		int orig_bidx;
   220  		int table_idx = idx;
   221  		int tbl_len;
   222  		int key_idx;
   223  		bool is_array = false;
   224  		callinfo_t *callinfo = *pcallinfo;
   225  		if (callinfo == NULL) {
   226  			callinfo = callinfo_new();
   227  			*pcallinfo = callinfo;
   228  		}
   229  		if (!register_tcall(callinfo, (void *)lua_topointer(L, idx))) {
   230  			lua_pushstring(L, "nested table error");
   231  			return false;
   232  		}
   233  
   234  		if (table_idx < 0)
   235  			table_idx = lua_gettop(L) + idx + 1;
   236  		tbl_len = lua_objlen(L, table_idx);
   237  		if (json_form && tbl_len > 0) {
   238  			double number;
   239  			char *check_array = calloc(tbl_len, sizeof(char));
   240  			is_array = true;
   241  			lua_pushnil(L);
   242  			while (lua_next(L, table_idx) != 0) {
   243  				lua_pop (L ,1);
   244  				if (!lua_isnumber(L, -1) || lua_tonumber(L, -1) != round(lua_tonumber(L, -1))) {
   245  					is_array = false;
   246  					lua_pop (L ,1);
   247  					break;
   248  				}
   249  				key_idx = lua_tointeger(L, -1) - 1;
   250  				if (key_idx >= tbl_len || key_idx < 0) {
   251  					is_array = false;
   252  					lua_pop (L ,1);
   253  					break;
   254  				}
   255  				check_array[key_idx] = 1;
   256  			}
   257  			if (is_array) {
   258  				for (key_idx = 0; key_idx < tbl_len; ++key_idx) {
   259  					if (check_array[key_idx] != 1) {
   260  						is_array = false;
   261  						break;
   262  					}
   263  				}
   264  			}
   265  			free(check_array);
   266  		}
   267  
   268  		if (is_array) {
   269  			copy_to_buffer ("[", 1, sbuf);
   270  			for (key_idx = 1; key_idx <= tbl_len; ++ key_idx) {
   271  				lua_rawgeti(L, table_idx, key_idx);
   272  				if (!lua_util_dump_json (L, -1, sbuf, true, false, pcallinfo)) {
   273  					return false;
   274  				}
   275  				lua_pop(L, 1);
   276  			}
   277  			--(sbuf->idx);
   278  			src_val = "],";
   279  		}
   280  		else {
   281  		    sbuff_t sort_buf;
   282  		    int idx = 0, max_key = 5;
   283  		    int i;
   284  		    sort_key_t *sort_keys = malloc(sizeof(sort_key_t) * max_key);
   285  		    lua_util_sbuf_init(&sort_buf, 20);
   286  
   287  			copy_to_buffer ("{", 1, sbuf);
   288  			orig_bidx = (sbuf->idx);
   289  			lua_pushnil(L);
   290  			while (lua_next(L, table_idx) != 0) {
   291  				if (idx == max_key) {
   292  				    max_key *= 2;
   293  				    sort_keys = realloc(sort_keys, sizeof(sort_key_t) * max_key);
   294  				}
   295  				sort_keys[idx].start_idx = sort_buf.idx;
   296  				if (!lua_util_dump_json (L, -2, &sort_buf, json_form, true, pcallinfo)) {
   297  					free(sort_keys);
   298  			        free(sort_buf.buf);
   299  					return false;
   300  				}
   301  				sort_keys[idx].key_len = sort_buf.idx - sort_keys[idx].start_idx - 1;
   302  				sort_buf.buf[sort_buf.idx - 1]=':';
   303  				if (!lua_util_dump_json (L, -1, &sort_buf, json_form, false, pcallinfo)) {
   304  					free(sort_keys);
   305  			        free(sort_buf.buf);
   306  					return false;
   307  				}
   308  				sort_buf.buf[sort_buf.idx - 1] = '\0';
   309  				lua_pop(L, 1);
   310  				++idx;
   311  
   312  			}
   313  			if (idx > 0) {
   314  				for (i = 0; i < idx; ++i)
   315  				    sort_keys[i].elem = sort_buf.buf + sort_keys[i].start_idx;
   316                  qsort(sort_keys, idx, sizeof(sort_key_t), sort_key_compare);
   317                  for (i = 0; i < idx; ++i) {
   318                      copy_to_buffer(sort_keys[i].elem, strlen(sort_keys[i].elem), sbuf);
   319                      copy_to_buffer(",", 1, sbuf);
   320                  }
   321              }
   322  			free(sort_keys);
   323  			free(sort_buf.buf);
   324  			if (orig_bidx != sbuf->idx)
   325  				--(sbuf->idx);
   326  			src_val = "},";
   327  		}
   328  		unregister_tcall(callinfo);
   329  		break;
   330  	}
   331  	case LUA_TUSERDATA: {
   332  	    if (lua_isbignumber(L, idx)) {
   333  	        char *s;
   334  	        copy_to_buffer(bignum_str,strlen(bignum_str), sbuf);
   335  	        s = lua_get_bignum_str(L, idx);
   336  	        if (s != NULL) {
   337                  copy_str_to_buffer (s, strlen (s), sbuf);
   338                  free(s);
   339              }
   340  		    src_val = "\"},";
   341  		    break;
   342  	    }
   343  	}
   344  	default:
   345  		lua_pushfstring(L, "\"unsupport type: %s\"", lua_typename (L, lua_type(L, idx)));
   346  		return false;
   347  	}
   348  
   349  	len = strlen (src_val);
   350  	copy_to_buffer (src_val, len, sbuf);
   351  	return true;
   352  
   353  }
   354  static int json_to_lua (lua_State *L, char **start, bool check, bool is_bignum);
   355  
   356  static int json_array_to_lua_table(lua_State *L, char **start, bool check) {
   357  	char *json = (*start) + 1;
   358  	int index = 1;
   359  
   360  	lua_newtable(L);
   361  	while(*json != ']') {
   362  		lua_pushnumber(L, index++);
   363  		if (json_to_lua (L, &json, check, false) != 0)
   364  			return -1;
   365  		if (*json == ',')
   366  			++json;
   367  		else if(*json != ']')
   368  			return -1;
   369  		lua_rawset(L, -3);
   370  	}
   371  	*start = json + 1;
   372  	return 0;
   373  }
   374  
   375  static int json_to_lua_table(lua_State *L, char **start, bool check) {
   376  	char *json = (*start) + 1;
   377  	int index = 1;
   378  	bool is_bignum = false;
   379  	int elem_cnt = 0;
   380  
   381  	lua_newtable(L);
   382  	while(*json != '}') {
   383  		lua_pushnumber(L, index++);
   384  		if (json_to_lua (L, &json, check, false) != 0)
   385  			return -1;
   386  		if (*json == ':') {
   387  			lua_remove(L, -2);
   388  			--index;
   389  			if (check && !lua_isstring(L, -1)) {
   390  				return -1;
   391  			}
   392  			if (elem_cnt == 0 && lua_type(L, -1) == LUA_TSTRING &&
   393  			    strcmp(lua_tostring(L, -1), "_bignum") == 0) {
   394  			    is_bignum = true;
   395  			}
   396  			++json;
   397  			if (json_to_lua (L, &json, check, is_bignum) != 0)
   398  				return -1;
   399  		}
   400  		if (*json == ',') {
   401  			if (is_bignum)
   402  			    return -1;
   403  			++json;
   404  		}
   405  		else if (*json != '}')
   406  			return -1;
   407  
   408  	    if (is_bignum) {
   409  	        if (!lua_isbignumber(L, -1))
   410  	            return -1;
   411  	        lua_replace(L, -3);
   412  	        lua_pop(L, 1);
   413  	    }
   414  	    else
   415  		    lua_rawset(L, -3);
   416  	}
   417  	*start = json + 1;
   418  	return 0;
   419  }
   420  
   421  
   422  int lua_util_utf8_encode(char *s, unsigned ch) {
   423      if (ch < 0x80) {
   424          s[0] = (char)ch;
   425          return 1;
   426      }
   427      if (ch <= 0x7FF) {
   428          s[1] = (char) ((ch | 0x80) & 0xBF);
   429          s[0] = (char) ((ch >> 6) | 0xC0);
   430          return 2;
   431      }
   432      if (ch <= 0xFFFF) {
   433  	    s[2] = (char) ((ch | 0x80) & 0xBF);
   434  	    s[1] = (char) (((ch >> 6) | 0x80) & 0xBF);
   435  	    s[0] = (char) ((ch >> 12) | 0xE0);
   436  	    return 3;
   437      }
   438      {
   439  	    char buff[UTF8_MAX];
   440  	    unsigned mfb = 0x3F;
   441  	    int n = 1;
   442  	    do {
   443  	        if (n > 6)
   444  	            return -1;
   445  	        buff[UTF8_MAX - (n++)] = 0x80 | (ch&0x3F);
   446  	        ch >>= 6;
   447  	        mfb >>= 1;
   448  	    } while (ch > mfb);
   449  	    buff[UTF8_MAX - n] = (~mfb << 1) | ch;
   450  	    memcpy(s, &buff[UTF8_MAX - n], n);
   451  	    return n;
   452      }
   453  }
   454  
   455  static int json_to_lua (lua_State *L, char **start, bool check, bool is_bignum) {
   456  	char *json = *start;
   457  	char special[5];
   458  
   459  	special[4] = '\0';
   460  	while(isspace(*json)) ++json;
   461  	if (*json == '"') {
   462  	    if (is_bignum) {
   463  	        char *end = strchr(json + 1, '"');
   464  	        if (end != NULL) {
   465  	            *end = '\0';
   466  	            lua_set_bignum(L, json + 1);
   467  	            *end = '"';
   468  	            json = end + 1;
   469  	        }
   470  	        else
   471  	            return -1;
   472  	    } else {
   473              char *end = json + 1;
   474              char *target = end;
   475              while ((*end) != '"') {
   476                  if (*end == '\0')
   477                      return -1;
   478                  if ((*end) == '\\') {
   479                      end++;
   480                      switch(*end) {
   481                      case 't':
   482                          *target = '\t';
   483                          break;
   484                      case 'n':
   485                          *target = '\n';
   486                          break;
   487                      case 'b':
   488                          *target = '\b';
   489                          break;
   490                      case 'f':
   491                          *target = '\f';
   492                          break;
   493                      case 'r':
   494                          *target = '\r';
   495                          break;
   496                      case 'u': {
   497                          int i;
   498                          unsigned ch;
   499                          int out;
   500                          for (i = 1; i < 5; ++i) {
   501                              if (!isxdigit(*(end + i)))
   502                                  return -1;
   503                          }
   504                          memcpy (special, end+1, 4);
   505                          ch = strtol(special, NULL, 16);
   506                          out = lua_util_utf8_encode(target, ch);
   507                          if (out < 0)
   508                              return -1;
   509                          target = target + out - 1;
   510                          end += 4;
   511                          break;
   512                      }
   513                      default :
   514                          *target = *end;
   515                      }
   516                  }
   517                  else if (end != target)
   518                      *target = *end;
   519                  end++;
   520                  target++;
   521              }
   522              *target = '\0';
   523              lua_pushlstring(L, json + 1, target - json - 1);
   524              json = end + 1;
   525          }
   526  	} else if (isdigit(*json) || *json == '-' || *json == '+') {
   527  		double d;
   528  		char *end = json + 1;
   529  
   530  	    if (is_bignum)
   531  	        return -1;
   532  		while(*end != '\0') {
   533  			if (!isdigit(*end) && *end != '-' && *end != '.' &&
   534  				*end != 'e' && *end != 'E' && *end != '+') {
   535  				break;
   536  			}
   537  			++end;
   538  		}
   539          sscanf(json, "%lf", &d);
   540          lua_pushnumber(L, d);
   541  		json = end;
   542  	} else if (*json == '{') {
   543  		if (json_to_lua_table(L, &json, check) != 0)
   544  			return -1;
   545  	} else if (*json == '[') {
   546  		if (json_array_to_lua_table(L, &json, check) != 0)
   547  			return -1;
   548  	} else if (strncasecmp(json, "true", 4) == 0) {
   549  		lua_pushboolean(L, 1);
   550  		json = json + 4;
   551  	} else if (strncasecmp(json, "false", 5) == 0) {
   552  		lua_pushboolean(L, 0);
   553  		json = json + 5;
   554  	} else if (strncasecmp(json, "null", 4) == 0) {
   555  		lua_pushnil(L);
   556  		json = json + 4;
   557  	} else {
   558  		return -1;
   559  	}
   560  	while(isspace(*json)) ++json;
   561  	*start = json;
   562  	return 0;
   563  }
   564  
   565  void minus_inst_count(lua_State *L, int count) {
   566      int cnt = luaL_instcount(L);
   567  
   568      cnt -= count;
   569      if (cnt <= 0)
   570          cnt = 1;
   571      luaL_setinstcount(L, cnt);
   572  }
   573  
   574  int lua_util_json_to_lua (lua_State *L, char *json, bool check)
   575  {
   576  	if (json_to_lua (L, &json, check, false) != 0)
   577  		return -1;
   578  	if (check && *json != '\0')
   579  		return -1;
   580  	return 0;
   581  }
   582  
   583  char *lua_util_get_json_from_stack (lua_State *L, int start, int end, bool json_form)
   584  {
   585  	int i;
   586  	sbuff_t sbuf;
   587  	int start_idx;
   588  	callinfo_t *callinfo = NULL;
   589  	lua_util_sbuf_init (&sbuf, 64);
   590  
   591  	if (!json_form || start < end)
   592  		copy_to_buffer ("[", 1, &sbuf);
   593  	start_idx = sbuf.idx;
   594  	for (i = start; i <= end; ++i) {
   595  		if (!lua_util_dump_json (L, i, &sbuf, json_form, false, &callinfo)) {
   596  			callinfo_del(callinfo);
   597  			free(sbuf.buf);
   598  			return NULL;
   599  		}
   600  	}
   601  	callinfo_del(callinfo);
   602  	if (sbuf.idx != start_idx)
   603  		sbuf.idx--;
   604  	if (!json_form || start < end) {
   605  		copy_to_buffer ("]", 2, &sbuf);
   606  	}
   607  	else {
   608  		sbuf.buf[sbuf.idx] = '\0';
   609  	}
   610  
   611      minus_inst_count(L, strlen(sbuf.buf));
   612  	return sbuf.buf;
   613  }
   614  
   615  char *lua_util_get_json (lua_State *L, int idx, bool json_form)
   616  {
   617  	sbuff_t sbuf;
   618  	callinfo_t *callinfo = NULL;
   619  	lua_util_sbuf_init (&sbuf, 64);
   620  
   621  	if(!lua_util_dump_json (L, idx, &sbuf, json_form, false, &callinfo)) {
   622  		callinfo_del(callinfo);
   623  		free(sbuf.buf);
   624  		return NULL;
   625  	}
   626  	callinfo_del(callinfo);
   627  
   628  	if (sbuf.idx != 0)
   629  		sbuf.buf[sbuf.idx - 1] = '\0';
   630  
   631      minus_inst_count(L, strlen(sbuf.buf));
   632  	return sbuf.buf;
   633  }
   634  
   635  static int lua_json_encode (lua_State *L)
   636  {
   637  	char *json = lua_util_get_json(L, -1, true);
   638  	if (json == NULL)
   639  		luaL_throwerror(L);
   640  	lua_pushstring(L, json);
   641  	free(json);
   642  	return 1;
   643  }
   644  
   645  static int lua_json_decode (lua_State *L)
   646  {
   647  	char *org = (char *)luaL_checkstring(L, -1);
   648  	char *json = strdup(org);
   649  
   650      minus_inst_count(L, strlen(json));
   651  	if (lua_util_json_to_lua(L, json, true) != 0) {
   652  		free (json);
   653  		luaL_error(L, "not proper json format");
   654  	}
   655  	free (json);
   656  	return 1;
   657  }
   658  
   659  static const luaL_Reg json_lib[] = {
   660  	{"encode", lua_json_encode},
   661  	{"decode", lua_json_decode},
   662  	{NULL, NULL}
   663  };
   664  
   665  int luaopen_json(lua_State *L)
   666  {
   667  	luaL_register(L, "json", json_lib);
   668  	lua_pop(L, 1);
   669  	return 1;
   670  }