nota
This commit is contained in:
parent
dde71d6c02
commit
46b86a8e92
|
@ -162,9 +162,17 @@ JSValue js_getpropidx(JSValue v, uint32_t i)
|
||||||
|
|
||||||
static inline cpBody *js2body(JSValue v) { return js2gameobject(v)->body; }
|
static inline cpBody *js2body(JSValue v) { return js2gameobject(v)->body; }
|
||||||
|
|
||||||
uint64_t js2uint64(JSValue v) { return JS_VALUE_GET_INT(v); }
|
uint64_t js2uint64(JSValue v) {
|
||||||
|
uint64_t i;
|
||||||
|
JS_ToInt64(js, &i, v);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
int js2int(JSValue v) { return JS_VALUE_GET_INT(v); }
|
int js2int(JSValue v) {
|
||||||
|
int i;
|
||||||
|
JS_ToInt32(js, &i, v);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
JSValue int2js(int i) { return JS_NewInt64(js, i); }
|
JSValue int2js(int i) { return JS_NewInt64(js, i); }
|
||||||
|
|
||||||
|
@ -227,49 +235,61 @@ int js_arrlen(JSValue v) {
|
||||||
char *js_nota_decode(JSValue *tmp, char *nota)
|
char *js_nota_decode(JSValue *tmp, char *nota)
|
||||||
{
|
{
|
||||||
int type = nota_type(nota);
|
int type = nota_type(nota);
|
||||||
JSValue ret;
|
|
||||||
JSValue ret2;
|
JSValue ret2;
|
||||||
long long n;
|
long long n;
|
||||||
double d;
|
double d;
|
||||||
int b;
|
int b;
|
||||||
|
char *str;
|
||||||
char *str = NULL;
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case NOTA_BLOB:
|
case NOTA_BLOB:
|
||||||
break;
|
break;
|
||||||
case NOTA_TEXT:
|
case NOTA_TEXT:
|
||||||
nota = nota_read_text(str, nota);
|
nota = nota_read_text(&str, nota);
|
||||||
*tmp = str2js(str);
|
*tmp = str2js(str);
|
||||||
return nota;
|
break;
|
||||||
case NOTA_ARR:
|
case NOTA_ARR:
|
||||||
nota = nota_read_array(&n, nota);
|
nota = nota_read_array(&n, nota);
|
||||||
ret = JS_NewArray(js);
|
*tmp = JS_NewArray(js);
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
nota = js_nota_decode(&ret2, nota);
|
nota = js_nota_decode(&ret2, nota);
|
||||||
JS_SetPropertyInt64(js, ret, i, ret2);
|
JS_SetPropertyInt64(js, *tmp, i, ret2);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NOTA_REC:
|
case NOTA_REC:
|
||||||
|
nota = nota_read_record(&n, nota);
|
||||||
|
printf("nota object with %d elements\n", n);
|
||||||
|
*tmp = JS_NewObject(js);
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
|
||||||
|
nota = nota_read_text(&str, nota);
|
||||||
|
printf("looking at property %d named %s\n", i, str);
|
||||||
|
nota = js_nota_decode(&ret2, nota);
|
||||||
|
JS_SetPropertyStr(js, *tmp, str, ret2);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case NOTA_FLOAT:
|
|
||||||
nota = nota_read_float(&d, nota);
|
|
||||||
*tmp = number2js(d);
|
|
||||||
return nota;
|
|
||||||
case NOTA_INT:
|
case NOTA_INT:
|
||||||
nota = nota_read_int(&n, nota);
|
nota = nota_read_int(&n, nota);
|
||||||
*tmp = int2js(n);
|
*tmp = int2js(n);
|
||||||
return nota;
|
break;
|
||||||
case NOTA_SYM:
|
case NOTA_SYM:
|
||||||
nota = nota_read_bool(&b, nota);
|
nota = nota_read_bool(&b, nota);
|
||||||
*tmp = bool2js(b);
|
*tmp = bool2js(b);
|
||||||
return nota;
|
break;
|
||||||
|
default:
|
||||||
|
case NOTA_FLOAT:
|
||||||
|
nota = nota_read_float(&d, nota);
|
||||||
|
*tmp = number2js(d);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nota;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *js_nota_encode(JSValue v, char *nota)
|
char *js_nota_encode(JSValue v, char *nota)
|
||||||
{
|
{
|
||||||
int tag = JS_VALUE_GET_TAG(v);
|
int tag = JS_VALUE_GET_TAG(v);
|
||||||
char *str;
|
char *str = NULL;
|
||||||
JSPropertyEnum *ptab;
|
JSPropertyEnum *ptab;
|
||||||
uint32_t plen;
|
uint32_t plen;
|
||||||
int n;
|
int n;
|
||||||
|
@ -277,28 +297,40 @@ char *js_nota_encode(JSValue v, char *nota)
|
||||||
|
|
||||||
switch(tag) {
|
switch(tag) {
|
||||||
case JS_TAG_FLOAT64:
|
case JS_TAG_FLOAT64:
|
||||||
|
// printf("encode float\n");
|
||||||
return nota_write_float(JS_VALUE_GET_FLOAT64(v), nota);
|
return nota_write_float(JS_VALUE_GET_FLOAT64(v), nota);
|
||||||
case JS_TAG_INT:
|
case JS_TAG_INT:
|
||||||
|
// printf("encode int\n");
|
||||||
return nota_write_int(JS_VALUE_GET_INT(v), nota);
|
return nota_write_int(JS_VALUE_GET_INT(v), nota);
|
||||||
case JS_TAG_STRING:
|
case JS_TAG_STRING:
|
||||||
return nota_write_text(JS_VALUE_GET_PTR(v), nota);
|
// printf("encode string\n");
|
||||||
|
str = js2str(v);
|
||||||
|
nota = nota_write_text(str, nota);
|
||||||
|
JS_FreeCString(js, str);
|
||||||
|
return nota;
|
||||||
case JS_TAG_BOOL:
|
case JS_TAG_BOOL:
|
||||||
|
// printf("encode bool\n");
|
||||||
return nota_write_bool(JS_VALUE_GET_BOOL(v), nota);
|
return nota_write_bool(JS_VALUE_GET_BOOL(v), nota);
|
||||||
case JS_TAG_OBJECT:
|
case JS_TAG_OBJECT:
|
||||||
if (JS_IsArray(js, v)) {
|
if (JS_IsArray(js, v)) {
|
||||||
|
// printf("encode array\n");
|
||||||
int n = js_arrlen(v);
|
int n = js_arrlen(v);
|
||||||
nota = nota_write_array(n, nota);
|
nota = nota_write_array(n, nota);
|
||||||
for (int i = 0; i < js_arrlen(v); i++)
|
for (int i = 0; i < js_arrlen(v); i++)
|
||||||
nota = js_nota_encode(js_arridx(v, i), nota);
|
nota = js_nota_encode(js_arridx(v, i), nota);
|
||||||
return nota;
|
return nota;
|
||||||
}
|
}
|
||||||
|
// printf("encode object\n");
|
||||||
|
|
||||||
n = JS_GetOwnPropertyNames(js, &ptab, &plen, v, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK);
|
n = JS_GetOwnPropertyNames(js, &ptab, &plen, v, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK);
|
||||||
nota = nota_write_record(plen, nota);
|
nota = nota_write_record(plen, nota);
|
||||||
for (int i = 0; i < plen; i++) {
|
for (int i = 0; i < plen; i++) {
|
||||||
|
val = JS_GetProperty(js,v,ptab[i].atom);
|
||||||
|
if (JS_IsUndefined(val) || JS_IsNull(val)) continue;
|
||||||
/* todo: slower than atomtocstring */
|
/* todo: slower than atomtocstring */
|
||||||
val = JS_AtomToString(js, ptab[i].atom);
|
str = JS_AtomToCString(js, ptab[i].atom);
|
||||||
nota = nota_write_text(JS_VALUE_GET_PTR(v), nota);
|
// printf("encoding object entry %s\n", str);
|
||||||
|
nota = nota_write_text(str, nota);
|
||||||
nota = js_nota_encode(JS_GetProperty(js, v, ptab[i].atom), nota);
|
nota = js_nota_encode(JS_GetProperty(js, v, ptab[i].atom), nota);
|
||||||
}
|
}
|
||||||
return nota;
|
return nota;
|
||||||
|
@ -492,7 +524,6 @@ struct rect js2rect(JSValue v) {
|
||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
JSValue rect2js(struct rect rect) {
|
JSValue rect2js(struct rect rect) {
|
||||||
JSValue obj = JS_NewObject(js);
|
JSValue obj = JS_NewObject(js);
|
||||||
js_setprop_str(obj, "x", JS_NewFloat64(js, rect.x));
|
js_setprop_str(obj, "x", JS_NewFloat64(js, rect.x));
|
||||||
|
@ -2012,16 +2043,16 @@ JSValue nota_encode(JSContext *js, JSValueConst this, int argc, JSValueConst *ar
|
||||||
JSValue obj = argv[0];
|
JSValue obj = argv[0];
|
||||||
char nota[100000];
|
char nota[100000];
|
||||||
char *e = js_nota_encode(obj, nota);
|
char *e = js_nota_encode(obj, nota);
|
||||||
*e = 0;
|
|
||||||
|
return JS_NewArrayBufferCopy(js, nota, e-nota);
|
||||||
return JS_NewStringLen(js, nota, e-nota);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValue nota_decode(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
JSValue nota_decode(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
||||||
{
|
{
|
||||||
if (argc < 1) return JS_UNDEFINED;
|
if (argc < 1) return JS_UNDEFINED;
|
||||||
|
|
||||||
char *nota = js2str(argv[0]);
|
size_t len;
|
||||||
|
char *nota = JS_GetArrayBuffer(js, &len, argv[0]);
|
||||||
JSValue ret;
|
JSValue ret;
|
||||||
js_nota_decode(&ret, nota);
|
js_nota_decode(&ret, nota);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
|
#include "limits.h"
|
||||||
|
|
||||||
#define NOTA_CONT 0x80
|
#define NOTA_CONT 0x80
|
||||||
#define NOTA_DATA 0x7f
|
#define NOTA_DATA 0x7f
|
||||||
|
@ -31,18 +32,26 @@ char *nota_skip(char *nota)
|
||||||
return nota+1;
|
return nota+1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *nota_read_num(long long *n, char *nota)
|
||||||
|
{
|
||||||
|
if (!n)
|
||||||
|
return nota_skip(nota);
|
||||||
|
|
||||||
|
*n = 0;
|
||||||
|
*n |= (*nota) & NOTA_HEAD_DATA;
|
||||||
|
|
||||||
|
while (CONTINUE(*(nota++)))
|
||||||
|
*n = (*n<<7) | (*nota) & NOTA_DATA;
|
||||||
|
|
||||||
|
return nota;
|
||||||
|
}
|
||||||
|
|
||||||
int nota_bits(long long n, int sb)
|
int nota_bits(long long n, int sb)
|
||||||
{
|
{
|
||||||
int bits;
|
if (n == 0) return sb;
|
||||||
if (n == 0)
|
int bits = sizeof(n)*CHAR_BIT - __builtin_clzll(n);
|
||||||
bits = 0;
|
|
||||||
else
|
|
||||||
bits = ilogb(n)+1;
|
|
||||||
bits-=sb; /* start bit */
|
bits-=sb; /* start bit */
|
||||||
int chars = bits/7;
|
return ((bits + 6) / 7)*7 + sb;
|
||||||
if (bits%7>0) chars++;
|
|
||||||
bits = sb + (chars*7);
|
|
||||||
return bits;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *nota_continue_num(long long n, char *nota, int sb)
|
char *nota_continue_num(long long n, char *nota, int sb)
|
||||||
|
@ -54,10 +63,10 @@ char *nota_continue_num(long long n, char *nota, int sb)
|
||||||
else
|
else
|
||||||
nota[0] &= ~NOTA_CONT;
|
nota[0] &= ~NOTA_CONT;
|
||||||
|
|
||||||
int shex = ~0 << sb;
|
int shex = (~0) << sb;
|
||||||
nota[0] &= shex; /* clear shex bits */
|
nota[0] &= shex; /* clear shex bits */
|
||||||
nota[0] |= ~shex & (n>>bits);
|
nota[0] |= (~shex) & (n>>bits);
|
||||||
|
|
||||||
int i = 1;
|
int i = 1;
|
||||||
while (bits > 0) {
|
while (bits > 0) {
|
||||||
bits -= 7;
|
bits -= 7;
|
||||||
|
@ -109,19 +118,6 @@ char *nota_write_int(long long n, char *nota)
|
||||||
return nota_continue_num(n, nota, 3);
|
return nota_continue_num(n, nota, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *nota_read_num(long long *n, char *nota)
|
|
||||||
{
|
|
||||||
if (!n)
|
|
||||||
return nota_skip(nota);
|
|
||||||
|
|
||||||
*n = 0;
|
|
||||||
*n |= (*nota) & NOTA_HEAD_DATA;
|
|
||||||
|
|
||||||
while (CONTINUE(*(nota++)))
|
|
||||||
*n = (*n<<7) | (*nota) & NOTA_DATA;
|
|
||||||
|
|
||||||
return nota;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define NOTA_DBL_PREC 6
|
#define NOTA_DBL_PREC 6
|
||||||
#define xstr(s) str(s)
|
#define xstr(s) str(s)
|
||||||
|
@ -137,7 +133,7 @@ char *nota_write_float(double n, char *nota)
|
||||||
char ns[2+NOTA_DBL_PREC+5];
|
char ns[2+NOTA_DBL_PREC+5];
|
||||||
snprintf(ns, 2+NOTA_DBL_PREC+5, "%." xstr (NOTA_DBL_PREC) "e", n);
|
snprintf(ns, 2+NOTA_DBL_PREC+5, "%." xstr (NOTA_DBL_PREC) "e", n);
|
||||||
|
|
||||||
int e = atoi(&ns[2+NOTA_DBL_PREC+1]);
|
long long e = atoll(&ns[2+NOTA_DBL_PREC+1]);
|
||||||
ns[2+NOTA_DBL_PREC] = 0;
|
ns[2+NOTA_DBL_PREC] = 0;
|
||||||
|
|
||||||
char *z = ns + 1 + NOTA_DBL_PREC;
|
char *z = ns + 1 + NOTA_DBL_PREC;
|
||||||
|
@ -160,15 +156,13 @@ char *nota_write_float(double n, char *nota)
|
||||||
nota[0] = NOTA_FLOAT;
|
nota[0] = NOTA_FLOAT;
|
||||||
nota[0] |= 0x10 & expsign;
|
nota[0] |= 0x10 & expsign;
|
||||||
nota[0] |= 0x08 & sign;
|
nota[0] |= 0x08 & sign;
|
||||||
|
|
||||||
char *c = nota_continue_num(e, nota, 3);
|
|
||||||
|
|
||||||
|
char *c = nota_continue_num(e, nota, 3);
|
||||||
return nota_continue_num(sig, c, 7);
|
return nota_continue_num(sig, c, 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *nota_read_float(double *d, char *nota)
|
char *nota_read_float(double *d, char *nota)
|
||||||
{
|
{
|
||||||
print_nota_hex(nota);
|
|
||||||
long long sig = 0;
|
long long sig = 0;
|
||||||
long long e = 0;
|
long long e = 0;
|
||||||
|
|
||||||
|
@ -182,17 +176,15 @@ char *nota_read_float(double *d, char *nota)
|
||||||
|
|
||||||
c++;
|
c++;
|
||||||
|
|
||||||
sig = (*c) & NOTA_DATA;
|
do
|
||||||
while (CONTINUE(*c)) {
|
|
||||||
sig = (sig<<7) | *c & NOTA_DATA;
|
sig = (sig<<7) | *c & NOTA_DATA;
|
||||||
c++;
|
while (CONTINUE(*(c++)));
|
||||||
}
|
|
||||||
|
|
||||||
if (NOTA_SIG_SIGN(*nota)) sig *= -1;
|
if (NOTA_SIG_SIGN(*nota)) sig *= -1;
|
||||||
if (NOTA_EXP_SIGN(*nota)) e *= -1;
|
if (NOTA_EXP_SIGN(*nota)) e *= -1;
|
||||||
|
|
||||||
*d = (double)sig * pow(10.0, e);
|
*d = (double)sig * pow(10.0, e);
|
||||||
return nota;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *nota_read_int(long long *n, char *nota)
|
char *nota_read_int(long long *n, char *nota)
|
||||||
|
@ -200,14 +192,15 @@ char *nota_read_int(long long *n, char *nota)
|
||||||
if (!n)
|
if (!n)
|
||||||
return nota_skip(nota);
|
return nota_skip(nota);
|
||||||
|
|
||||||
|
*n = 0;
|
||||||
char *c = nota;
|
char *c = nota;
|
||||||
*n |= (*c) & NOTA_INT_DATA; /* first three bits */
|
*n |= (*c) & NOTA_INT_DATA; /* first three bits */
|
||||||
while (CONTINUE(*(c++)))
|
while (CONTINUE(*(c++)))
|
||||||
*n = (*n<<7) | (*c) & NOTA_DATA;
|
*n = (*n<<7) | (*c) & NOTA_DATA;
|
||||||
|
|
||||||
if (NOTA_INT_SIGN(*nota)) *n *= -1;
|
if (NOTA_INT_SIGN(*nota)) *n *= -1;
|
||||||
|
|
||||||
return c+1;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* n is the number of bits */
|
/* n is the number of bits */
|
||||||
|
@ -310,13 +303,7 @@ void encode_kim(char **s, char *end, int code)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bits = 32 - __builtin_clz(code);
|
int bits = ((32 - __builtin_clz(code) + 6) / 7) * 7;
|
||||||
if (bits <= 7)
|
|
||||||
bits = 7;
|
|
||||||
else if (bits <= 14)
|
|
||||||
bits = 14;
|
|
||||||
else
|
|
||||||
bits = 21;
|
|
||||||
|
|
||||||
while (bits > 7) {
|
while (bits > 7) {
|
||||||
bits -= 7;
|
bits -= 7;
|
||||||
|
@ -339,10 +326,12 @@ int decode_kim(char **s)
|
||||||
return rune;
|
return rune;
|
||||||
}
|
}
|
||||||
|
|
||||||
void utf8_to_kim(char *utf, char *kim)
|
char *utf8_to_kim(char *utf, char *kim)
|
||||||
{
|
{
|
||||||
while (*utf)
|
while (*utf)
|
||||||
encode_kim(&kim, NULL, decode_utf8(&utf));
|
encode_kim(&kim, NULL, decode_utf8(&utf));
|
||||||
|
|
||||||
|
return kim;
|
||||||
}
|
}
|
||||||
|
|
||||||
void kim_to_utf8(char *kim, char *utf, int runes)
|
void kim_to_utf8(char *kim, char *utf, int runes)
|
||||||
|
@ -353,21 +342,20 @@ void kim_to_utf8(char *kim, char *utf, int runes)
|
||||||
*utf = 0;
|
*utf = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *nota_read_text(char *text, char *nota)
|
char *nota_read_text(char **text, char *nota)
|
||||||
{
|
{
|
||||||
long long chars;
|
long long chars;
|
||||||
nota = nota_read_num(&chars, nota);
|
nota = nota_read_num(&chars, nota);
|
||||||
char utf[chars*4];
|
char utf[chars*4];
|
||||||
kim_to_utf8(nota, utf, chars);
|
kim_to_utf8(nota, utf, chars);
|
||||||
text = strdup(utf);
|
*text = strdup(utf);
|
||||||
return nota;
|
return nota;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *nota_write_bool(int b, char *nota)
|
char *nota_write_bool(int b, char *nota)
|
||||||
{
|
{
|
||||||
*nota = NOTA_SYM | (b ? NOTA_TRUE : NOTA_FALSE);
|
*nota = NOTA_SYM | (b ? NOTA_TRUE : NOTA_FALSE);
|
||||||
nota++;
|
return nota+1;
|
||||||
return nota;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *nota_read_bool(int *b, char *nota)
|
char *nota_read_bool(int *b, char *nota)
|
||||||
|
@ -382,7 +370,6 @@ char *nota_write_text(char *s, char *nota)
|
||||||
nota[0] = NOTA_TEXT;
|
nota[0] = NOTA_TEXT;
|
||||||
long long n = utf8_count(s);
|
long long n = utf8_count(s);
|
||||||
nota = nota_continue_num(n,nota,4);
|
nota = nota_continue_num(n,nota,4);
|
||||||
utf8_to_kim(s, nota);
|
return utf8_to_kim(s, nota);
|
||||||
return nota+n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,17 +9,21 @@
|
||||||
#define NOTA_INT 0x60
|
#define NOTA_INT 0x60
|
||||||
#define NOTA_SYM 0x70
|
#define NOTA_SYM 0x70
|
||||||
|
|
||||||
|
typedef struct NOTA {
|
||||||
|
char *head;
|
||||||
|
} NOTA;
|
||||||
|
|
||||||
int nota_type(char *nota);
|
int nota_type(char *nota);
|
||||||
|
|
||||||
char *nota_read_blob(long long *len, char *nota);
|
char *nota_read_blob(long long *len, char *nota);
|
||||||
char *nota_read_text(char *text, char *nota);
|
char *nota_read_text(char **text, char *nota);
|
||||||
char *nota_read_array(long long *len, char *nota);
|
char *nota_read_array(long long *len, char *nota);
|
||||||
char *nota_read_record(long long *len, char *nota);
|
char *nota_read_record(long long *len, char *nota);
|
||||||
char *nota_read_float(double *d, char *nota);
|
char *nota_read_float(double *d, char *nota);
|
||||||
char *nota_read_int(long long *l, char *nota);
|
char *nota_read_int(long long *l, char *nota);
|
||||||
char *nota_read_bool(int *b, char *nota);
|
char *nota_read_bool(int *b, char *nota);
|
||||||
|
|
||||||
char *nota_read_num(long long *n, char *nota);
|
void print_nota_hex(char *nota);
|
||||||
|
|
||||||
char *nota_write_blob(unsigned long long n, char *nota);
|
char *nota_write_blob(unsigned long long n, char *nota);
|
||||||
char *nota_write_text(char *s, char *nota);
|
char *nota_write_text(char *s, char *nota);
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "particle.h"
|
#include "particle.h"
|
||||||
#include "simplex.h"
|
#include "simplex.h"
|
||||||
#include "nota.h"
|
|
||||||
|
|
||||||
#include "datastream.h"
|
#include "datastream.h"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue