├── bin ├── toolm.dll └── libqjs.dll ├── lib ├── toolm.dll ├── libqjs.dll └── libqjs.lib ├── .gitignore ├── examples ├── hello.js ├── fib_module.js ├── libqjs_eval_file.c └── use-module.c ├── include ├── libqjs.h ├── quickjs-libc.h ├── libregexp-opcode.h ├── libregexp.h ├── list.h ├── libunicode.h ├── cutils.h ├── quickjs-atom.h ├── quickjs-opcode.h └── quickjs.h ├── module ├── rhash.h ├── tool_module.c └── md5.c ├── module_ex_compile.bat ├── test.py ├── compile_lib.md ├── libqjs_compile.bat ├── setup.py ├── src ├── libqjs.c ├── cutils.c └── libunicode.c ├── README.md └── QJS.c /bin/toolm.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lcexc/py-quickjs/HEAD/bin/toolm.dll -------------------------------------------------------------------------------- /lib/toolm.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lcexc/py-quickjs/HEAD/lib/toolm.dll -------------------------------------------------------------------------------- /bin/libqjs.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lcexc/py-quickjs/HEAD/bin/libqjs.dll -------------------------------------------------------------------------------- /lib/libqjs.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lcexc/py-quickjs/HEAD/lib/libqjs.dll -------------------------------------------------------------------------------- /lib/libqjs.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lcexc/py-quickjs/HEAD/lib/libqjs.lib -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | build/ 4 | qjs.egg-info/ 5 | dist/ 6 | 7 | *.exe 8 | 9 | -------------------------------------------------------------------------------- /examples/hello.js: -------------------------------------------------------------------------------- 1 | import * as m from './toolm.dll' 2 | 3 | console.log("Hello World 你好"); 4 | 5 | console.log(m.echo("Hello , 哈哈")); 6 | 7 | console.log(m.md5('123456')); 8 | -------------------------------------------------------------------------------- /examples/fib_module.js: -------------------------------------------------------------------------------- 1 | /* fib module */ 2 | export function fib(n) 3 | { 4 | if (n <= 0) 5 | return 0; 6 | else if (n == 1) 7 | return 1; 8 | else 9 | return fib(n - 1) + fib(n - 2); 10 | } 11 | -------------------------------------------------------------------------------- /include/libqjs.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef LIB_QJS_LIBC_H 3 | #define LIB_QJS_LIBC_H 4 | 5 | #include 6 | 7 | #include "quickjs.h" 8 | #include "quickjs-libc.h" 9 | 10 | int eval_buf(JSContext *ctx, const void *buf, int buf_len, 11 | const char *filename, int eval_flags); 12 | 13 | int eval_file(JSContext *ctx, const char *filename, int module); 14 | 15 | #endif /* LIB_QJS_LIBC_H */ 16 | -------------------------------------------------------------------------------- /module/rhash.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __RARCH_HASH_H 3 | #define __RARCH_HASH_H 4 | 5 | #include 6 | #include 7 | 8 | typedef unsigned int MD5_u32plus; 9 | 10 | typedef struct { 11 | MD5_u32plus lo, hi; 12 | MD5_u32plus a, b, c, d; 13 | unsigned char buffer[64]; 14 | MD5_u32plus block[16]; 15 | } MD5_CTX; 16 | 17 | void MD5_Init(MD5_CTX *ctx); 18 | void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size); 19 | void MD5_Final(unsigned char *result, MD5_CTX *ctx); 20 | 21 | #endif -------------------------------------------------------------------------------- /module_ex_compile.bat: -------------------------------------------------------------------------------- 1 | 2 | mkdir bin 3 | 4 | :: 动态库, 在js里import 5 | gcc -shared -I include -I module -L lib -lqjs -DJS_SHARED_LIBRARY -o lib/toolm.dll module/md5.c module/tool_module.c 6 | 7 | :: 将module作为内建库使用 8 | 9 | gcc -I include -I module -L lib -lqjs -o bin/examples_use_module.exe module/md5.c module/tool_module.c examples/use-module.c 10 | 11 | :: 编译运行 example 12 | 13 | gcc -I include -L lib -lqjs -o bin/examples_libqjs_eval_file.exe examples/libqjs_eval_file.c 14 | 15 | copy /Y lib\libqjs.dll bin 16 | copy /Y lib\toolm.dll bin 17 | -------------------------------------------------------------------------------- /examples/libqjs_eval_file.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "libqjs.h" 5 | 6 | 7 | int main(int argc, char **argv){ 8 | if (argc < 2){ 9 | printf("no input file.\n"); 10 | exit(1); 11 | } 12 | JSRuntime *rt; 13 | JSContext *ctx; 14 | 15 | rt = JS_NewRuntime(); 16 | ctx = JS_NewContext(rt); 17 | 18 | /* loader for ES6 modules */ 19 | JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); 20 | 21 | js_std_add_helpers(ctx, 0, NULL); // int argc, char **argv 22 | 23 | /* system modules */ 24 | js_init_module_std(ctx, "std"); 25 | js_init_module_os(ctx, "os"); 26 | 27 | eval_file(ctx, argv[1], -1); 28 | 29 | js_std_free_handlers(rt); 30 | JS_FreeContext(ctx); 31 | JS_FreeRuntime(rt); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | import os 2 | import qjs 3 | 4 | code = '''import * as std from 'std'; 5 | 6 | ((G)=>{ 7 | const sys_path = std.getenv('PATH'); 8 | console.log("run ....."); 9 | G._r = 'result: '+ sys_path; 10 | })(globalThis); 11 | 12 | ''' 13 | 14 | code1 = '(()=>{return Date.now();})();' 15 | 16 | mod_test = '''import * as m from './lib/toolm.dll' 17 | import { fib } from "./examples/fib_module.js"; 18 | 19 | console.log("Hello World 你好"); 20 | 21 | console.log(m.echo("Hello , 哈哈")); 22 | 23 | console.log(m.md5('123456')); 24 | console.log("fib(10)=", fib(10));''' 25 | 26 | # ================================== 27 | 28 | print("work dir:", os.getcwd()) 29 | print(qjs.eval_js(code)) 30 | print(qjs.eval_js(code1)) 31 | 32 | # need libqjs.dll 33 | # print(qjs.eval_js(mod_test)) 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /compile_lib.md: -------------------------------------------------------------------------------- 1 | # 编译指导 2 | 3 | ## 编译 quickjs 动态链接库(windows) 4 | 5 | 环境: win10系统 TDM-GCC-64编译器 6 | 7 | *libqjs.c 文件 实现了 `eval_buf` 和 `eval_file` 函数* 8 | 9 | 在`MinGW Command Prompt` 里依次运行 `libqjs_compile.bat` `module_ex_compile.bat` 即可完成编译 10 | 11 | 生成的dll在lib文件夹里, 例程在bin文件夹下 12 | 13 | 在bin文件夹下打开cmd, 执行下面命令即可看到结果(中文乱码是终端问题,git-shell显示正常). 14 | 15 | ``` 16 | examples_libqjs_eval_file.exe ..\examples\hello.js 17 | 18 | examples_use_module.exe 19 | 20 | ``` 21 | 22 | ## Python 扩展编译 23 | 24 | 目前只测试了3.6+版本(3.8 lib链接失败) 25 | 26 | ### Windows 27 | 在`MinGW Command Prompt` 里运行`python setup.py build -f -c mingw32`即可编译 28 | 29 | 编译后的pyd文件在 `build\lib.win-amdxx-3.x`. 30 | 31 | 执行 `python setup.py install` 即可完成安装 32 | 33 | ### Linux 34 | 35 | ``` 36 | git clone https://github.com/lcexc/py-quickjs.git 37 | 38 | cd py-quickjs 39 | 40 | sudo python setup.py install 41 | 42 | 43 | ``` 44 | 45 | 46 | -------------------------------------------------------------------------------- /libqjs_compile.bat: -------------------------------------------------------------------------------- 1 | mkdir lib obj 2 | 3 | gcc -Wall -Wno-array-bounds -D_GNU_SOURCE -DCONFIG_VERSION=\"2020-01-19\" -O2 -flto -c -I include -o obj/quickjs.o src/quickjs.c 4 | 5 | gcc -Wall -Wno-array-bounds -D_GNU_SOURCE -DCONFIG_VERSION=\"2020-01-19\" -O2 -flto -c -I include -o obj/libunicode.o src/libunicode.c 6 | 7 | gcc -Wall -Wno-array-bounds -D_GNU_SOURCE -DCONFIG_VERSION=\"2020-01-19\" -O2 -flto -c -I include -o obj/quickjs-libc.o src/quickjs-libc.c 8 | 9 | gcc -Wall -Wno-array-bounds -D_GNU_SOURCE -DCONFIG_VERSION=\"2020-01-19\" -O2 -flto -c -I include -o obj/libregexp.o src/libregexp.c 10 | 11 | gcc -Wall -Wno-array-bounds -D_GNU_SOURCE -DCONFIG_VERSION=\"2020-01-19\" -O2 -flto -c -I include -o obj/cutils.o src/cutils.c 12 | 13 | gcc -Wall -O2 -flto -c -I include -o obj/libqjs.o src/libqjs.c 14 | 15 | gcc -shared -o lib/libqjs.dll -Wl,--out-implib,lib/libqjs.lib obj/quickjs.o obj/libregexp.o obj/libunicode.o obj/cutils.o obj/quickjs-libc.o obj/libqjs.o -lm 16 | 17 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from setuptools import setup, Extension 3 | 4 | srcs = ['QJS.c', "src/cutils.c","src/libregexp.c","src/libunicode.c","src/quickjs.c","src/quickjs-libc.c"] 5 | extra_compile_args = ['-flto','-Wno-array-bounds', '-Wno-format-truncation','-w' ] 6 | extra_link_args = ["-Wl,-Bstatic"] 7 | 8 | # python setup.py build -f -c mingw32 9 | # python setup.py bdist_wheel 10 | 11 | if sys.platform == 'win32': 12 | import distutils.cygwinccompiler 13 | distutils.cygwinccompiler.get_msvcr = lambda: [] 14 | 15 | CONFIG_VERSION='\\"2020-01-19\\"' 16 | 17 | else: 18 | CONFIG_VERSION='\"2020-01-19\"' 19 | extra_link_args = [] 20 | 21 | 22 | mod_qjs = Extension('qjs', srcs , 23 | define_macros=[('CONFIG_VERSION', CONFIG_VERSION), ('_GNU_SOURCE','')], 24 | include_dirs = ['include'], 25 | extra_compile_args=extra_compile_args, 26 | extra_link_args = extra_link_args ) 27 | 28 | setup(name='qjs', 29 | version='1.0', 30 | ext_modules=[mod_qjs, ]) 31 | 32 | 33 | -------------------------------------------------------------------------------- /examples/use-module.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "libqjs.h" 4 | 5 | JSModuleDef *js_init_module_toolm(JSContext *ctx, const char *module_name); 6 | 7 | int main(){ 8 | JSRuntime *rt; 9 | JSContext *ctx; 10 | 11 | char s1[255] = "console.log('Hello World');\n" 12 | "console.log(std.getenv('windir'));" 13 | "let a=2;a=m.add(a,3);\n" 14 | "console.log('result:',a); console.log(m.echo('vcmnbxvnmbc..'));"; 15 | 16 | const char *str = "import * as std from 'std';\n" 17 | "import * as os from 'os';\n" 18 | "import * as m from 'm';\n" 19 | "globalThis.std = std;\n" 20 | "globalThis.os = os;\n" 21 | "globalThis.m = m;\n"; 22 | 23 | rt = JS_NewRuntime(); 24 | ctx = JS_NewContext(rt); 25 | 26 | /* loader for ES6 modules */ 27 | JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); 28 | 29 | js_std_add_helpers(ctx, 0, NULL); // int argc, char **argv 30 | 31 | /* system modules */ 32 | js_init_module_std(ctx, "std"); 33 | js_init_module_os(ctx, "os"); 34 | 35 | 36 | // lib 37 | js_init_module_toolm(ctx, "m"); 38 | 39 | eval_buf(ctx, str, strlen(str), "", JS_EVAL_TYPE_MODULE); 40 | 41 | eval_buf(ctx, s1, strlen(s1), "", JS_EVAL_TYPE_GLOBAL); 42 | 43 | js_std_free_handlers(rt); 44 | JS_FreeContext(ctx); 45 | JS_FreeRuntime(rt); 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/libqjs.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "quickjs-libc.h" 4 | 5 | #include "cutils.h" 6 | 7 | int eval_buf(JSContext *ctx, const void *buf, int buf_len, 8 | const char *filename, int eval_flags) 9 | { 10 | JSValue val; 11 | int ret; 12 | 13 | if ((eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_MODULE) { 14 | /* for the modules, we compile then run to be able to set 15 | import.meta */ 16 | val = JS_Eval(ctx, buf, buf_len, filename, 17 | eval_flags | JS_EVAL_FLAG_COMPILE_ONLY); 18 | if (!JS_IsException(val)) { 19 | js_module_set_import_meta(ctx, val, 1, 1); 20 | val = JS_EvalFunction(ctx, val); 21 | } 22 | } else { 23 | val = JS_Eval(ctx, buf, buf_len, filename, eval_flags); 24 | } 25 | if (JS_IsException(val)) { 26 | js_std_dump_error(ctx); 27 | ret = -1; 28 | } else { 29 | ret = 0; 30 | } 31 | JS_FreeValue(ctx, val); 32 | return ret; 33 | } 34 | 35 | int eval_file(JSContext *ctx, const char *filename, int module) 36 | { 37 | uint8_t *buf; 38 | int ret, eval_flags; 39 | size_t buf_len; 40 | 41 | buf = js_load_file(ctx, &buf_len, filename); 42 | if (!buf) { 43 | perror(filename); 44 | exit(1); 45 | } 46 | 47 | if (module < 0) { 48 | module = (has_suffix(filename, ".mjs") || 49 | JS_DetectModule((const char *)buf, buf_len)); 50 | } 51 | if (module) 52 | eval_flags = JS_EVAL_TYPE_MODULE; 53 | else 54 | eval_flags = JS_EVAL_TYPE_GLOBAL; 55 | ret = eval_buf(ctx, buf, buf_len, filename, eval_flags); 56 | js_free(ctx, buf); 57 | return ret; 58 | } 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QuickJS Python 扩展 2 | 3 | quickjs 已经出来一段时间了,因其主要目标是linux,在windows上开发编译不是很友好. 4 | 恰好最近有空研究了下,如果只运行js代码,只需要一部分代码就能编译出来. 5 | 因为有在python里运行js的需求,所以顺手写了个扩展,经过测试,能正常运行. 6 | 由于技术能力和精力有限,细节处理还不是很好,后面慢慢完善. 7 | 8 | 这是我第一个开源项目,希望能帮助到大家,如果对你有帮助,麻烦给个star. 9 | 同时,也希望各位能对项目存在的问题 pull request, 感谢您的使用 !!! 10 | 11 | ## quickjs 说明 12 | 13 | 本项目依赖于 [QuickJS Javascript Engine](https://bellard.org/quickjs/) 目前版本为 2020-01-19. 14 | 15 | 使用到的源码文件(暂不考虑大数运算): `quickjs.c libunicode.c quickjs-libc.c libregexp.c cutils.c` 16 | 17 | 如只想用c库,请参考 [编译指导](compile_lib.md) 18 | 19 | ## 安装 && 使用 20 | 21 | ### Windows 22 | 23 | 目前预编译了3.6 3.7, 其他版本自行编译参考 [编译指导](compile_lib.md) 24 | 25 | 下载 qjs-1.0-cpXX-cpXXm-win_amd64.whl 26 | 27 | 执行 `pip install qjs-xxx.whl` 完成安装 28 | 29 | ### Linux 30 | 31 | ``` 32 | git clone https://github.com/lcexc/py-quickjs.git 33 | 34 | cd py-quickjs 35 | 36 | sudo python setup.py install 37 | 38 | 39 | ``` 40 | ### 使用 41 | 42 | 目前只进行了简单封装,支持一个函数 `eval_js(code)` 43 | 44 | ``` 45 | import qjs 46 | 47 | js_code = ''' 48 | (()=>{ 49 | console.log("Hello World"); 50 | return "Current TimeStamp: " + Date.now() 51 | })(); 52 | ''' 53 | 54 | rt = qjs.eval_js(js_code) 55 | print(rt) 56 | 57 | ``` 58 | 59 | ### 注意事项 60 | 61 | 因为quickjs 执行有两种模式 `JS_EVAL_TYPE_MODULE` 和 `JS_EVAL_TYPE_GLOBAL` 62 | global能直接获取返回值, 如果文件有导入语句,会以module模式运行,无法获取返回值,所以要获取返回值需要按以下格式书写: 63 | 64 | ``` 65 | import xxx 66 | 67 | ((G)=>{ 68 | ...... // your code 69 | const result = XXX; 70 | G._r = result; 71 | })(globalThis); 72 | 73 | ``` 74 | 该方式将返回值放到全局变量 `_r` 执行完后自动将该值传回py 75 | 76 | **test.py 里有几个例子,如果使用第三方js库(dll) 需要把lib下的libqjs.dll放到test.py同目录** 77 | 78 | 出现类似问题 `could not load module filename 'xxx.dll' as shared library, ERR code: 126` 是dll导入失败,请仔细检查路径 79 | 80 | ## 存在问题 81 | 82 | 1. python扩展加载js module(dll) 还需要依赖libqjs 83 | 2. ... 84 | 85 | 86 | -------------------------------------------------------------------------------- /include/quickjs-libc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS C library 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #ifndef QUICKJS_LIBC_H 25 | #define QUICKJS_LIBC_H 26 | 27 | #include 28 | #include 29 | 30 | #include "quickjs.h" 31 | 32 | JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name); 33 | JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name); 34 | void js_std_add_helpers(JSContext *ctx, int argc, char **argv); 35 | void js_std_loop(JSContext *ctx); 36 | void js_std_free_handlers(JSRuntime *rt); 37 | void js_std_dump_error(JSContext *ctx); 38 | uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename); 39 | int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, 40 | JS_BOOL use_realpath, JS_BOOL is_main); 41 | JSModuleDef *js_module_loader(JSContext *ctx, 42 | const char *module_name, void *opaque); 43 | void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len, 44 | int flags); 45 | void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise, 46 | JSValueConst reason, 47 | JS_BOOL is_handled, void *opaque); 48 | 49 | #endif /* QUICKJS_LIBC_H */ 50 | -------------------------------------------------------------------------------- /include/libregexp-opcode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Regular Expression Engine 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #ifdef DEF 26 | 27 | DEF(invalid, 1) /* never used */ 28 | DEF(char, 3) 29 | DEF(char32, 5) 30 | DEF(dot, 1) 31 | DEF(any, 1) /* same as dot but match any character including line terminator */ 32 | DEF(line_start, 1) 33 | DEF(line_end, 1) 34 | DEF(goto, 5) 35 | DEF(split_goto_first, 5) 36 | DEF(split_next_first, 5) 37 | DEF(match, 1) 38 | DEF(save_start, 2) /* save start position */ 39 | DEF(save_end, 2) /* save end position, must come after saved_start */ 40 | DEF(save_reset, 3) /* reset save positions */ 41 | DEF(loop, 5) /* decrement the top the stack and goto if != 0 */ 42 | DEF(push_i32, 5) /* push integer on the stack */ 43 | DEF(drop, 1) 44 | DEF(word_boundary, 1) 45 | DEF(not_word_boundary, 1) 46 | DEF(back_reference, 2) 47 | DEF(backward_back_reference, 2) /* must come after back_reference */ 48 | DEF(range, 3) /* variable length */ 49 | DEF(range32, 3) /* variable length */ 50 | DEF(lookahead, 5) 51 | DEF(negative_lookahead, 5) 52 | DEF(push_char_pos, 1) /* push the character position on the stack */ 53 | DEF(bne_char_pos, 5) /* pop one stack element and jump if equal to the character 54 | position */ 55 | DEF(prev, 1) /* go to the previous char */ 56 | DEF(simple_greedy_quant, 17) 57 | 58 | #endif /* DEF */ 59 | -------------------------------------------------------------------------------- /module/tool_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "libqjs.h" 3 | #include "rhash.h" 4 | 5 | #define countof(x) (sizeof(x) / sizeof((x)[0])) 6 | 7 | static JSValue js_toolm_add(JSContext *ctx, JSValueConst this_val, 8 | int argc, JSValueConst *argv){ 9 | int a,b; 10 | JS_ToInt32(ctx, &a, argv[0]); 11 | JS_ToInt32(ctx, &b, argv[1]); 12 | 13 | return JS_NewInt32(ctx, a+b); 14 | } 15 | 16 | static JSValue js_toolm_echo(JSContext *ctx, JSValueConst this_val, 17 | int argc, JSValueConst *argv){ 18 | const char *s; 19 | s = JS_ToCString(ctx, argv[0]); 20 | if(!s) 21 | return JS_EXCEPTION; 22 | 23 | return JS_NewString(ctx, s); 24 | } 25 | 26 | static JSValue js_toolm_md5(JSContext *ctx, JSValueConst this_val, 27 | int argc, JSValueConst *argv){ 28 | const char *s; 29 | unsigned char result[16], rv[35]; 30 | int slen,i; 31 | MD5_CTX md5_ctx; 32 | MD5_Init(&md5_ctx); 33 | 34 | s = JS_ToCString(ctx, argv[0]); 35 | slen = strlen(s); 36 | MD5_Update(&md5_ctx, (void*)s, slen); 37 | MD5_Final(result, &md5_ctx); 38 | sprintf(rv, "%02x%02x%02x%02x%02x%02x%02x%02x" 39 | "%02x%02x%02x%02x%02x%02x%02x%02x", 40 | result[ 0 ], result[ 1 ], result[ 2 ], result[ 3 ], 41 | result[ 4 ], result[ 5 ], result[ 6 ], result[ 7 ], 42 | result[ 8 ], result[ 9 ], result[ 10 ], result[ 11 ], 43 | result[ 12 ], result[ 13 ], result[ 14 ], result[ 15 ]); 44 | return JS_NewStringLen(ctx,rv, 32); 45 | } 46 | 47 | static const JSCFunctionListEntry js_toolm_funcs[] = { 48 | JS_CFUNC_DEF("add", 2, js_toolm_add ), 49 | JS_CFUNC_DEF("echo", 1, js_toolm_echo ), 50 | JS_CFUNC_DEF("md5", 1, js_toolm_md5 ) 51 | }; 52 | 53 | static int js_toolm_init(JSContext *ctx, JSModuleDef *m) { 54 | JS_SetModuleExportList(ctx, m, js_toolm_funcs, 55 | countof(js_toolm_funcs)); 56 | } 57 | 58 | 59 | #ifdef JS_SHARED_LIBRARY 60 | #define JS_INIT_MODULE js_init_module 61 | #else 62 | #define JS_INIT_MODULE js_init_module_toolm 63 | #endif 64 | 65 | JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name) 66 | { 67 | JSModuleDef *m; 68 | m = JS_NewCModule(ctx, module_name, js_toolm_init); 69 | if (!m) 70 | return NULL; 71 | JS_AddModuleExportList(ctx, m, js_toolm_funcs, countof(js_toolm_funcs)); 72 | 73 | return m; 74 | } 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /QJS.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "libqjs.h" 4 | 5 | 6 | static PyObject* qjs_init(PyObject* self, PyObject *args) { 7 | 8 | return Py_BuildValue("b", 0); 9 | } 10 | 11 | static PyObject* qjs_runcode(PyObject* self, PyObject *args) { 12 | JSRuntime *rt; 13 | JSContext *ctx; 14 | const char *s; 15 | char *code; 16 | JSValue val, global_obj; 17 | int ret, tag, code_len, has_module=0, eval_flags; 18 | 19 | if (!PyArg_ParseTuple(args, "s", &code)) 20 | return NULL; 21 | code_len = strlen(code); 22 | rt = JS_NewRuntime(); 23 | ctx = JS_NewContext(rt); 24 | 25 | /* loader for ES6 modules */ 26 | JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); 27 | 28 | js_std_add_helpers(ctx, 0, NULL); // int argc, char **argv 29 | 30 | /* system modules */ 31 | js_init_module_std(ctx, "std"); 32 | js_init_module_os(ctx, "os"); 33 | 34 | has_module = JS_DetectModule((const char *)code, code_len); 35 | 36 | if (has_module) 37 | eval_flags = JS_EVAL_TYPE_MODULE; 38 | else 39 | eval_flags = JS_EVAL_TYPE_GLOBAL; 40 | 41 | if ((eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_MODULE) { 42 | /* for the modules, we compile then run to be able to set 43 | import.meta */ 44 | val = JS_Eval(ctx, code, code_len, "", 45 | eval_flags | JS_EVAL_FLAG_COMPILE_ONLY); 46 | 47 | if (JS_IsException(val)) { 48 | 49 | js_std_dump_error(ctx); 50 | return NULL; 51 | } 52 | 53 | js_module_set_import_meta(ctx, val, 1, 1); 54 | val = JS_EvalFunction(ctx, val); 55 | // 如果包含模块,返回值要写入全局变量 56 | global_obj = JS_GetGlobalObject(ctx); 57 | val = JS_GetPropertyStr(ctx, global_obj, "_r"); 58 | JS_FreeValue(ctx, global_obj); 59 | } else { // 不包含模块,直接运行 60 | val = JS_Eval(ctx, code, code_len, "", eval_flags); 61 | } 62 | // // buf, buf_len, filename, eval_flags 63 | // val = JS_Eval(ctx, code, strlen(code), "", -1); 64 | 65 | if (JS_IsException(val)) { 66 | js_std_dump_error(ctx); 67 | return NULL; 68 | } 69 | 70 | tag = JS_VALUE_GET_TAG(val); 71 | 72 | s = JS_ToCString(ctx, val); 73 | 74 | JS_FreeValue(ctx, val); 75 | // printf("return val[%d]: %s \n", tag, s); 76 | 77 | js_std_free_handlers(rt); 78 | JS_FreeContext(ctx); 79 | JS_FreeRuntime(rt); 80 | 81 | return Py_BuildValue("s", s); 82 | 83 | } 84 | 85 | static PyMethodDef qjs_funcs[] = { 86 | {"init", (PyCFunction)qjs_init, METH_VARARGS, "helloworld_docs"}, 87 | {"eval_js", (PyCFunction)qjs_runcode, METH_VARARGS, "helloworld_docs"}, 88 | {NULL, NULL, 0, NULL} 89 | }; 90 | 91 | static PyModuleDef qjs_module = { 92 | PyModuleDef_HEAD_INIT, 93 | "qjs", /* name of module */ 94 | NULL, /* module documentation, may be NULL */ 95 | -1, /* size of per-interpreter state of the module, 96 | or -1 if the module keeps state in global variables. */ 97 | qjs_funcs 98 | }; 99 | 100 | 101 | PyMODINIT_FUNC PyInit_qjs() { 102 | return PyModule_Create(&qjs_module); 103 | } 104 | -------------------------------------------------------------------------------- /include/libregexp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Regular Expression Engine 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #ifndef LIBREGEXP_H 25 | #define LIBREGEXP_H 26 | 27 | #include 28 | 29 | #include "libunicode.h" 30 | 31 | #define LRE_BOOL int /* for documentation purposes */ 32 | 33 | #define LRE_FLAG_GLOBAL (1 << 0) 34 | #define LRE_FLAG_IGNORECASE (1 << 1) 35 | #define LRE_FLAG_MULTILINE (1 << 2) 36 | #define LRE_FLAG_DOTALL (1 << 3) 37 | #define LRE_FLAG_UTF16 (1 << 4) 38 | #define LRE_FLAG_STICKY (1 << 5) 39 | 40 | #define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */ 41 | 42 | uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, 43 | const char *buf, size_t buf_len, int re_flags, 44 | void *opaque); 45 | int lre_get_capture_count(const uint8_t *bc_buf); 46 | int lre_get_flags(const uint8_t *bc_buf); 47 | int lre_exec(uint8_t **capture, 48 | const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen, 49 | int cbuf_type, void *opaque); 50 | 51 | int lre_parse_escape(const uint8_t **pp, int allow_utf16); 52 | LRE_BOOL lre_is_space(int c); 53 | 54 | /* must be provided by the user */ 55 | LRE_BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size); 56 | void *lre_realloc(void *opaque, void *ptr, size_t size); 57 | 58 | /* JS identifier test */ 59 | extern uint32_t const lre_id_start_table_ascii[4]; 60 | extern uint32_t const lre_id_continue_table_ascii[4]; 61 | 62 | static inline int lre_js_is_ident_first(int c) 63 | { 64 | if ((uint32_t)c < 128) { 65 | return (lre_id_start_table_ascii[c >> 5] >> (c & 31)) & 1; 66 | } else { 67 | #ifdef CONFIG_ALL_UNICODE 68 | return lre_is_id_start(c); 69 | #else 70 | return !lre_is_space(c); 71 | #endif 72 | } 73 | } 74 | 75 | static inline int lre_js_is_ident_next(int c) 76 | { 77 | if ((uint32_t)c < 128) { 78 | return (lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1; 79 | } else { 80 | /* ZWNJ and ZWJ are accepted in identifiers */ 81 | #ifdef CONFIG_ALL_UNICODE 82 | return lre_is_id_continue(c) || c == 0x200C || c == 0x200D; 83 | #else 84 | return !lre_is_space(c) || c == 0x200C || c == 0x200D; 85 | #endif 86 | } 87 | } 88 | 89 | #undef LRE_BOOL 90 | 91 | #endif /* LIBREGEXP_H */ 92 | -------------------------------------------------------------------------------- /include/list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Linux klist like system 3 | * 4 | * Copyright (c) 2016-2017 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #ifndef LIST_H 25 | #define LIST_H 26 | 27 | #ifndef NULL 28 | #include 29 | #endif 30 | 31 | struct list_head { 32 | struct list_head *prev; 33 | struct list_head *next; 34 | }; 35 | 36 | #define LIST_HEAD_INIT(el) { &(el), &(el) } 37 | 38 | /* return the pointer of type 'type *' containing 'el' as field 'member' */ 39 | #define list_entry(el, type, member) \ 40 | ((type *)((uint8_t *)(el) - offsetof(type, member))) 41 | 42 | static inline void init_list_head(struct list_head *head) 43 | { 44 | head->prev = head; 45 | head->next = head; 46 | } 47 | 48 | /* insert 'el' between 'prev' and 'next' */ 49 | static inline void __list_add(struct list_head *el, 50 | struct list_head *prev, struct list_head *next) 51 | { 52 | prev->next = el; 53 | el->prev = prev; 54 | el->next = next; 55 | next->prev = el; 56 | } 57 | 58 | /* add 'el' at the head of the list 'head' (= after element head) */ 59 | static inline void list_add(struct list_head *el, struct list_head *head) 60 | { 61 | __list_add(el, head, head->next); 62 | } 63 | 64 | /* add 'el' at the end of the list 'head' (= before element head) */ 65 | static inline void list_add_tail(struct list_head *el, struct list_head *head) 66 | { 67 | __list_add(el, head->prev, head); 68 | } 69 | 70 | static inline void list_del(struct list_head *el) 71 | { 72 | struct list_head *prev, *next; 73 | prev = el->prev; 74 | next = el->next; 75 | prev->next = next; 76 | next->prev = prev; 77 | el->prev = NULL; /* fail safe */ 78 | el->next = NULL; /* fail safe */ 79 | } 80 | 81 | static inline int list_empty(struct list_head *el) 82 | { 83 | return el->next == el; 84 | } 85 | 86 | #define list_for_each(el, head) \ 87 | for(el = (head)->next; el != (head); el = el->next) 88 | 89 | #define list_for_each_safe(el, el1, head) \ 90 | for(el = (head)->next, el1 = el->next; el != (head); \ 91 | el = el1, el1 = el->next) 92 | 93 | #define list_for_each_prev(el, head) \ 94 | for(el = (head)->prev; el != (head); el = el->prev) 95 | 96 | #define list_for_each_prev_safe(el, el1, head) \ 97 | for(el = (head)->prev, el1 = el->prev; el != (head); \ 98 | el = el1, el1 = el->prev) 99 | 100 | #endif /* LIST_H */ 101 | -------------------------------------------------------------------------------- /include/libunicode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Unicode utilities 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #ifndef LIBUNICODE_H 25 | #define LIBUNICODE_H 26 | 27 | #include 28 | 29 | #define LRE_BOOL int /* for documentation purposes */ 30 | 31 | /* define it to include all the unicode tables (40KB larger) */ 32 | #define CONFIG_ALL_UNICODE 33 | 34 | #define LRE_CC_RES_LEN_MAX 3 35 | 36 | typedef enum { 37 | UNICODE_NFC, 38 | UNICODE_NFD, 39 | UNICODE_NFKC, 40 | UNICODE_NFKD, 41 | } UnicodeNormalizationEnum; 42 | 43 | int lre_case_conv(uint32_t *res, uint32_t c, int conv_type); 44 | LRE_BOOL lre_is_cased(uint32_t c); 45 | LRE_BOOL lre_is_case_ignorable(uint32_t c); 46 | 47 | /* char ranges */ 48 | 49 | typedef struct { 50 | int len; /* in points, always even */ 51 | int size; 52 | uint32_t *points; /* points sorted by increasing value */ 53 | void *mem_opaque; 54 | void *(*realloc_func)(void *opaque, void *ptr, size_t size); 55 | } CharRange; 56 | 57 | typedef enum { 58 | CR_OP_UNION, 59 | CR_OP_INTER, 60 | CR_OP_XOR, 61 | } CharRangeOpEnum; 62 | 63 | void cr_init(CharRange *cr, void *mem_opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size)); 64 | void cr_free(CharRange *cr); 65 | int cr_realloc(CharRange *cr, int size); 66 | int cr_copy(CharRange *cr, const CharRange *cr1); 67 | 68 | static inline int cr_add_point(CharRange *cr, uint32_t v) 69 | { 70 | if (cr->len >= cr->size) { 71 | if (cr_realloc(cr, cr->len + 1)) 72 | return -1; 73 | } 74 | cr->points[cr->len++] = v; 75 | return 0; 76 | } 77 | 78 | static inline int cr_add_interval(CharRange *cr, uint32_t c1, uint32_t c2) 79 | { 80 | if ((cr->len + 2) > cr->size) { 81 | if (cr_realloc(cr, cr->len + 2)) 82 | return -1; 83 | } 84 | cr->points[cr->len++] = c1; 85 | cr->points[cr->len++] = c2; 86 | return 0; 87 | } 88 | 89 | int cr_union1(CharRange *cr, const uint32_t *b_pt, int b_len); 90 | 91 | static inline int cr_union_interval(CharRange *cr, uint32_t c1, uint32_t c2) 92 | { 93 | uint32_t b_pt[2]; 94 | b_pt[0] = c1; 95 | b_pt[1] = c2 + 1; 96 | return cr_union1(cr, b_pt, 2); 97 | } 98 | 99 | int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len, 100 | const uint32_t *b_pt, int b_len, int op); 101 | 102 | int cr_invert(CharRange *cr); 103 | 104 | #ifdef CONFIG_ALL_UNICODE 105 | 106 | LRE_BOOL lre_is_id_start(uint32_t c); 107 | LRE_BOOL lre_is_id_continue(uint32_t c); 108 | 109 | int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len, 110 | UnicodeNormalizationEnum n_type, 111 | void *opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size)); 112 | 113 | /* Unicode character range functions */ 114 | 115 | int unicode_script(CharRange *cr, 116 | const char *script_name, LRE_BOOL is_ext); 117 | int unicode_general_category(CharRange *cr, const char *gc_name); 118 | int unicode_prop(CharRange *cr, const char *prop_name); 119 | 120 | #endif /* CONFIG_ALL_UNICODE */ 121 | 122 | #undef LRE_BOOL 123 | 124 | #endif /* LIBUNICODE_H */ 125 | -------------------------------------------------------------------------------- /include/cutils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * C utilities 3 | * 4 | * Copyright (c) 2017 Fabrice Bellard 5 | * Copyright (c) 2018 Charlie Gordon 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | #ifndef CUTILS_H 26 | #define CUTILS_H 27 | 28 | #include 29 | #include 30 | 31 | /* set if CPU is big endian */ 32 | #undef WORDS_BIGENDIAN 33 | 34 | #define likely(x) __builtin_expect(!!(x), 1) 35 | #define unlikely(x) __builtin_expect(!!(x), 0) 36 | #define force_inline inline __attribute__((always_inline)) 37 | #define no_inline __attribute__((noinline)) 38 | #define __maybe_unused __attribute__((unused)) 39 | 40 | #define xglue(x, y) x ## y 41 | #define glue(x, y) xglue(x, y) 42 | #define stringify(s) tostring(s) 43 | #define tostring(s) #s 44 | 45 | #ifndef offsetof 46 | #define offsetof(type, field) ((size_t) &((type *)0)->field) 47 | #endif 48 | #ifndef countof 49 | #define countof(x) (sizeof(x) / sizeof((x)[0])) 50 | #endif 51 | 52 | typedef int BOOL; 53 | 54 | #ifndef FALSE 55 | enum { 56 | FALSE = 0, 57 | TRUE = 1, 58 | }; 59 | #endif 60 | 61 | void pstrcpy(char *buf, int buf_size, const char *str); 62 | char *pstrcat(char *buf, int buf_size, const char *s); 63 | int strstart(const char *str, const char *val, const char **ptr); 64 | int has_suffix(const char *str, const char *suffix); 65 | 66 | static inline int max_int(int a, int b) 67 | { 68 | if (a > b) 69 | return a; 70 | else 71 | return b; 72 | } 73 | 74 | static inline int min_int(int a, int b) 75 | { 76 | if (a < b) 77 | return a; 78 | else 79 | return b; 80 | } 81 | 82 | static inline uint32_t max_uint32(uint32_t a, uint32_t b) 83 | { 84 | if (a > b) 85 | return a; 86 | else 87 | return b; 88 | } 89 | 90 | static inline uint32_t min_uint32(uint32_t a, uint32_t b) 91 | { 92 | if (a < b) 93 | return a; 94 | else 95 | return b; 96 | } 97 | 98 | static inline int64_t max_int64(int64_t a, int64_t b) 99 | { 100 | if (a > b) 101 | return a; 102 | else 103 | return b; 104 | } 105 | 106 | static inline int64_t min_int64(int64_t a, int64_t b) 107 | { 108 | if (a < b) 109 | return a; 110 | else 111 | return b; 112 | } 113 | 114 | /* WARNING: undefined if a = 0 */ 115 | static inline int clz32(unsigned int a) 116 | { 117 | return __builtin_clz(a); 118 | } 119 | 120 | /* WARNING: undefined if a = 0 */ 121 | static inline int clz64(uint64_t a) 122 | { 123 | return __builtin_clzll(a); 124 | } 125 | 126 | /* WARNING: undefined if a = 0 */ 127 | static inline int ctz32(unsigned int a) 128 | { 129 | return __builtin_ctz(a); 130 | } 131 | 132 | /* WARNING: undefined if a = 0 */ 133 | static inline int ctz64(uint64_t a) 134 | { 135 | return __builtin_ctzll(a); 136 | } 137 | 138 | struct __attribute__((packed)) packed_u64 { 139 | uint64_t v; 140 | }; 141 | 142 | struct __attribute__((packed)) packed_u32 { 143 | uint32_t v; 144 | }; 145 | 146 | struct __attribute__((packed)) packed_u16 { 147 | uint16_t v; 148 | }; 149 | 150 | static inline uint64_t get_u64(const uint8_t *tab) 151 | { 152 | return ((const struct packed_u64 *)tab)->v; 153 | } 154 | 155 | static inline int64_t get_i64(const uint8_t *tab) 156 | { 157 | return (int64_t)((const struct packed_u64 *)tab)->v; 158 | } 159 | 160 | static inline void put_u64(uint8_t *tab, uint64_t val) 161 | { 162 | ((struct packed_u64 *)tab)->v = val; 163 | } 164 | 165 | static inline uint32_t get_u32(const uint8_t *tab) 166 | { 167 | return ((const struct packed_u32 *)tab)->v; 168 | } 169 | 170 | static inline int32_t get_i32(const uint8_t *tab) 171 | { 172 | return (int32_t)((const struct packed_u32 *)tab)->v; 173 | } 174 | 175 | static inline void put_u32(uint8_t *tab, uint32_t val) 176 | { 177 | ((struct packed_u32 *)tab)->v = val; 178 | } 179 | 180 | static inline uint32_t get_u16(const uint8_t *tab) 181 | { 182 | return ((const struct packed_u16 *)tab)->v; 183 | } 184 | 185 | static inline int32_t get_i16(const uint8_t *tab) 186 | { 187 | return (int16_t)((const struct packed_u16 *)tab)->v; 188 | } 189 | 190 | static inline void put_u16(uint8_t *tab, uint16_t val) 191 | { 192 | ((struct packed_u16 *)tab)->v = val; 193 | } 194 | 195 | static inline uint32_t get_u8(const uint8_t *tab) 196 | { 197 | return *tab; 198 | } 199 | 200 | static inline int32_t get_i8(const uint8_t *tab) 201 | { 202 | return (int8_t)*tab; 203 | } 204 | 205 | static inline void put_u8(uint8_t *tab, uint8_t val) 206 | { 207 | *tab = val; 208 | } 209 | 210 | static inline uint16_t bswap16(uint16_t x) 211 | { 212 | return (x >> 8) | (x << 8); 213 | } 214 | 215 | static inline uint32_t bswap32(uint32_t v) 216 | { 217 | return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) | 218 | ((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24); 219 | } 220 | 221 | static inline uint64_t bswap64(uint64_t v) 222 | { 223 | return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) | 224 | ((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) | 225 | ((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) | 226 | ((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) | 227 | ((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) | 228 | ((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) | 229 | ((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) | 230 | ((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8)); 231 | } 232 | 233 | /* XXX: should take an extra argument to pass slack information to the caller */ 234 | typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size); 235 | 236 | typedef struct DynBuf { 237 | uint8_t *buf; 238 | size_t size; 239 | size_t allocated_size; 240 | BOOL error; /* true if a memory allocation error occurred */ 241 | DynBufReallocFunc *realloc_func; 242 | void *opaque; /* for realloc_func */ 243 | } DynBuf; 244 | 245 | void dbuf_init(DynBuf *s); 246 | void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func); 247 | int dbuf_realloc(DynBuf *s, size_t new_size); 248 | int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len); 249 | int dbuf_put(DynBuf *s, const uint8_t *data, size_t len); 250 | int dbuf_put_self(DynBuf *s, size_t offset, size_t len); 251 | int dbuf_putc(DynBuf *s, uint8_t c); 252 | int dbuf_putstr(DynBuf *s, const char *str); 253 | static inline int dbuf_put_u16(DynBuf *s, uint16_t val) 254 | { 255 | return dbuf_put(s, (uint8_t *)&val, 2); 256 | } 257 | static inline int dbuf_put_u32(DynBuf *s, uint32_t val) 258 | { 259 | return dbuf_put(s, (uint8_t *)&val, 4); 260 | } 261 | static inline int dbuf_put_u64(DynBuf *s, uint64_t val) 262 | { 263 | return dbuf_put(s, (uint8_t *)&val, 8); 264 | } 265 | int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s, 266 | const char *fmt, ...); 267 | void dbuf_free(DynBuf *s); 268 | static inline BOOL dbuf_error(DynBuf *s) { 269 | return s->error; 270 | } 271 | 272 | #define UTF8_CHAR_LEN_MAX 6 273 | 274 | int unicode_to_utf8(uint8_t *buf, unsigned int c); 275 | int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp); 276 | 277 | static inline int from_hex(int c) 278 | { 279 | if (c >= '0' && c <= '9') 280 | return c - '0'; 281 | else if (c >= 'A' && c <= 'F') 282 | return c - 'A' + 10; 283 | else if (c >= 'a' && c <= 'f') 284 | return c - 'a' + 10; 285 | else 286 | return -1; 287 | } 288 | 289 | void rqsort(void *base, size_t nmemb, size_t size, 290 | int (*cmp)(const void *, const void *, void *), 291 | void *arg); 292 | 293 | #endif /* CUTILS_H */ 294 | -------------------------------------------------------------------------------- /include/quickjs-atom.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS atom definitions 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * Copyright (c) 2017-2018 Charlie Gordon 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | #ifdef DEF 27 | 28 | /* Note: first atoms are considered as keywords in the parser */ 29 | DEF(null, "null") /* must be first */ 30 | DEF(false, "false") 31 | DEF(true, "true") 32 | DEF(if, "if") 33 | DEF(else, "else") 34 | DEF(return, "return") 35 | DEF(var, "var") 36 | DEF(this, "this") 37 | DEF(delete, "delete") 38 | DEF(void, "void") 39 | DEF(typeof, "typeof") 40 | DEF(new, "new") 41 | DEF(in, "in") 42 | DEF(instanceof, "instanceof") 43 | DEF(do, "do") 44 | DEF(while, "while") 45 | DEF(for, "for") 46 | DEF(break, "break") 47 | DEF(continue, "continue") 48 | DEF(switch, "switch") 49 | DEF(case, "case") 50 | DEF(default, "default") 51 | DEF(throw, "throw") 52 | DEF(try, "try") 53 | DEF(catch, "catch") 54 | DEF(finally, "finally") 55 | DEF(function, "function") 56 | DEF(debugger, "debugger") 57 | DEF(with, "with") 58 | /* FutureReservedWord */ 59 | DEF(class, "class") 60 | DEF(const, "const") 61 | DEF(enum, "enum") 62 | DEF(export, "export") 63 | DEF(extends, "extends") 64 | DEF(import, "import") 65 | DEF(super, "super") 66 | /* FutureReservedWords when parsing strict mode code */ 67 | DEF(implements, "implements") 68 | DEF(interface, "interface") 69 | DEF(let, "let") 70 | DEF(package, "package") 71 | DEF(private, "private") 72 | DEF(protected, "protected") 73 | DEF(public, "public") 74 | DEF(static, "static") 75 | DEF(yield, "yield") 76 | DEF(await, "await") 77 | 78 | /* empty string */ 79 | DEF(empty_string, "") 80 | /* identifiers */ 81 | DEF(length, "length") 82 | DEF(fileName, "fileName") 83 | DEF(lineNumber, "lineNumber") 84 | DEF(message, "message") 85 | DEF(stack, "stack") 86 | DEF(name, "name") 87 | DEF(toString, "toString") 88 | DEF(toLocaleString, "toLocaleString") 89 | DEF(valueOf, "valueOf") 90 | DEF(eval, "eval") 91 | DEF(prototype, "prototype") 92 | DEF(constructor, "constructor") 93 | DEF(configurable, "configurable") 94 | DEF(writable, "writable") 95 | DEF(enumerable, "enumerable") 96 | DEF(value, "value") 97 | DEF(get, "get") 98 | DEF(set, "set") 99 | DEF(of, "of") 100 | DEF(__proto__, "__proto__") 101 | DEF(undefined, "undefined") 102 | DEF(number, "number") 103 | DEF(boolean, "boolean") 104 | DEF(string, "string") 105 | DEF(object, "object") 106 | DEF(symbol, "symbol") 107 | DEF(integer, "integer") 108 | DEF(unknown, "unknown") 109 | DEF(arguments, "arguments") 110 | DEF(callee, "callee") 111 | DEF(caller, "caller") 112 | DEF(_eval_, "") 113 | DEF(_ret_, "") 114 | DEF(_var_, "") 115 | DEF(_with_, "") 116 | DEF(lastIndex, "lastIndex") 117 | DEF(target, "target") 118 | DEF(index, "index") 119 | DEF(input, "input") 120 | DEF(defineProperties, "defineProperties") 121 | DEF(apply, "apply") 122 | DEF(join, "join") 123 | DEF(concat, "concat") 124 | DEF(split, "split") 125 | DEF(construct, "construct") 126 | DEF(getPrototypeOf, "getPrototypeOf") 127 | DEF(setPrototypeOf, "setPrototypeOf") 128 | DEF(isExtensible, "isExtensible") 129 | DEF(preventExtensions, "preventExtensions") 130 | DEF(has, "has") 131 | DEF(deleteProperty, "deleteProperty") 132 | DEF(defineProperty, "defineProperty") 133 | DEF(getOwnPropertyDescriptor, "getOwnPropertyDescriptor") 134 | DEF(ownKeys, "ownKeys") 135 | DEF(add, "add") 136 | DEF(done, "done") 137 | DEF(next, "next") 138 | DEF(values, "values") 139 | DEF(source, "source") 140 | DEF(flags, "flags") 141 | DEF(global, "global") 142 | DEF(unicode, "unicode") 143 | DEF(raw, "raw") 144 | DEF(new_target, "new.target") 145 | DEF(this_active_func, "this.active_func") 146 | DEF(home_object, "") 147 | DEF(computed_field, "") 148 | DEF(static_computed_field, "") /* must come after computed_fields */ 149 | DEF(class_fields_init, "") 150 | DEF(brand, "") 151 | DEF(hash_constructor, "#constructor") 152 | DEF(as, "as") 153 | DEF(from, "from") 154 | DEF(meta, "meta") 155 | DEF(_default_, "*default*") 156 | DEF(_star_, "*") 157 | DEF(Module, "Module") 158 | DEF(then, "then") 159 | DEF(resolve, "resolve") 160 | DEF(reject, "reject") 161 | DEF(promise, "promise") 162 | DEF(proxy, "proxy") 163 | DEF(revoke, "revoke") 164 | DEF(async, "async") 165 | DEF(exec, "exec") 166 | DEF(groups, "groups") 167 | DEF(status, "status") 168 | DEF(reason, "reason") 169 | DEF(globalThis, "globalThis") 170 | #ifdef CONFIG_BIGNUM 171 | DEF(bigint, "bigint") 172 | DEF(bigfloat, "bigfloat") 173 | DEF(bigdecimal, "bigdecimal") 174 | DEF(roundingMode, "roundingMode") 175 | DEF(maximumSignificantDigits, "maximumSignificantDigits") 176 | DEF(maximumFractionDigits, "maximumFractionDigits") 177 | #endif 178 | #ifdef CONFIG_ATOMICS 179 | DEF(not_equal, "not-equal") 180 | DEF(timed_out, "timed-out") 181 | DEF(ok, "ok") 182 | #endif 183 | DEF(toJSON, "toJSON") 184 | /* class names */ 185 | DEF(Object, "Object") 186 | DEF(Array, "Array") 187 | DEF(Error, "Error") 188 | DEF(Number, "Number") 189 | DEF(String, "String") 190 | DEF(Boolean, "Boolean") 191 | DEF(Symbol, "Symbol") 192 | DEF(Arguments, "Arguments") 193 | DEF(Math, "Math") 194 | DEF(JSON, "JSON") 195 | DEF(Date, "Date") 196 | DEF(Function, "Function") 197 | DEF(GeneratorFunction, "GeneratorFunction") 198 | DEF(ForInIterator, "ForInIterator") 199 | DEF(RegExp, "RegExp") 200 | DEF(ArrayBuffer, "ArrayBuffer") 201 | DEF(SharedArrayBuffer, "SharedArrayBuffer") 202 | /* must keep same order as class IDs for typed arrays */ 203 | DEF(Uint8ClampedArray, "Uint8ClampedArray") 204 | DEF(Int8Array, "Int8Array") 205 | DEF(Uint8Array, "Uint8Array") 206 | DEF(Int16Array, "Int16Array") 207 | DEF(Uint16Array, "Uint16Array") 208 | DEF(Int32Array, "Int32Array") 209 | DEF(Uint32Array, "Uint32Array") 210 | #ifdef CONFIG_BIGNUM 211 | DEF(BigInt64Array, "BigInt64Array") 212 | DEF(BigUint64Array, "BigUint64Array") 213 | #endif 214 | DEF(Float32Array, "Float32Array") 215 | DEF(Float64Array, "Float64Array") 216 | DEF(DataView, "DataView") 217 | #ifdef CONFIG_BIGNUM 218 | DEF(BigInt, "BigInt") 219 | DEF(BigFloat, "BigFloat") 220 | DEF(BigFloatEnv, "BigFloatEnv") 221 | DEF(BigDecimal, "BigDecimal") 222 | DEF(OperatorSet, "OperatorSet") 223 | DEF(Operators, "Operators") 224 | #endif 225 | DEF(Map, "Map") 226 | DEF(Set, "Set") /* Map + 1 */ 227 | DEF(WeakMap, "WeakMap") /* Map + 2 */ 228 | DEF(WeakSet, "WeakSet") /* Map + 3 */ 229 | DEF(Map_Iterator, "Map Iterator") 230 | DEF(Set_Iterator, "Set Iterator") 231 | DEF(Array_Iterator, "Array Iterator") 232 | DEF(String_Iterator, "String Iterator") 233 | DEF(RegExp_String_Iterator, "RegExp String Iterator") 234 | DEF(Generator, "Generator") 235 | DEF(Proxy, "Proxy") 236 | DEF(Promise, "Promise") 237 | DEF(PromiseResolveFunction, "PromiseResolveFunction") 238 | DEF(PromiseRejectFunction, "PromiseRejectFunction") 239 | DEF(AsyncFunction, "AsyncFunction") 240 | DEF(AsyncFunctionResolve, "AsyncFunctionResolve") 241 | DEF(AsyncFunctionReject, "AsyncFunctionReject") 242 | DEF(AsyncGeneratorFunction, "AsyncGeneratorFunction") 243 | DEF(AsyncGenerator, "AsyncGenerator") 244 | DEF(EvalError, "EvalError") 245 | DEF(RangeError, "RangeError") 246 | DEF(ReferenceError, "ReferenceError") 247 | DEF(SyntaxError, "SyntaxError") 248 | DEF(TypeError, "TypeError") 249 | DEF(URIError, "URIError") 250 | DEF(InternalError, "InternalError") 251 | /* private symbols */ 252 | DEF(Private_brand, "") 253 | /* symbols */ 254 | DEF(Symbol_toPrimitive, "Symbol.toPrimitive") 255 | DEF(Symbol_iterator, "Symbol.iterator") 256 | DEF(Symbol_match, "Symbol.match") 257 | DEF(Symbol_matchAll, "Symbol.matchAll") 258 | DEF(Symbol_replace, "Symbol.replace") 259 | DEF(Symbol_search, "Symbol.search") 260 | DEF(Symbol_split, "Symbol.split") 261 | DEF(Symbol_toStringTag, "Symbol.toStringTag") 262 | DEF(Symbol_isConcatSpreadable, "Symbol.isConcatSpreadable") 263 | DEF(Symbol_hasInstance, "Symbol.hasInstance") 264 | DEF(Symbol_species, "Symbol.species") 265 | DEF(Symbol_unscopables, "Symbol.unscopables") 266 | DEF(Symbol_asyncIterator, "Symbol.asyncIterator") 267 | #ifdef CONFIG_BIGNUM 268 | DEF(Symbol_operatorSet, "Symbol.operatorSet") 269 | #endif 270 | 271 | #endif /* DEF */ 272 | -------------------------------------------------------------------------------- /module/md5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rhash.h" 3 | /* 4 | * The basic MD5 functions. 5 | * 6 | * F and G are optimized compared to their RFC 1321 definitions for 7 | * architectures that lack an AND-NOT instruction, just like in Colin Plumb's 8 | * implementation. 9 | */ 10 | #define MD5_F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) 11 | #define MD5_G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) 12 | #define MD5_H(x, y, z) (((x) ^ (y)) ^ (z)) 13 | #define MD5_H2(x, y, z) ((x) ^ ((y) ^ (z))) 14 | #define MD5_I(x, y, z) ((y) ^ ((x) | ~(z))) 15 | 16 | /* 17 | * The MD5 transformation for all four rounds. 18 | */ 19 | #define MD5_STEP(f, a, b, c, d, x, t, s) \ 20 | (a) += f((b), (c), (d)) + (x) + (t); \ 21 | (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ 22 | (a) += (b); 23 | 24 | /* 25 | * MD5_SET reads 4 input bytes in little-endian byte order and stores them 26 | * in a properly aligned word in host byte order. 27 | * 28 | * The check for little-endian architectures that tolerate unaligned 29 | * memory accesses is just an optimization. Nothing will break if it 30 | * doesn't work. 31 | */ 32 | #if defined(__i386__) || defined(__x86_64__) || defined(__vax__) 33 | #define MD5_SET(n) \ 34 | (*(MD5_u32plus *)&ptr[(n) * 4]) 35 | #define MD5_GET(n) \ 36 | MD5_SET(n) 37 | #else 38 | #define MD5_SET(n) \ 39 | (ctx->block[(n)] = \ 40 | (MD5_u32plus)ptr[(n) * 4] | \ 41 | ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \ 42 | ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \ 43 | ((MD5_u32plus)ptr[(n) * 4 + 3] << 24)) 44 | #define MD5_GET(n) \ 45 | (ctx->block[(n)]) 46 | #endif 47 | 48 | /* 49 | * This processes one or more 64-byte data blocks, but does NOT update 50 | * the bit counters. There are no alignment requirements. 51 | */ 52 | static const void *MD5_body(MD5_CTX *ctx, const void *data, unsigned long size) 53 | { 54 | const unsigned char *ptr; 55 | MD5_u32plus a, b, c, d; 56 | MD5_u32plus saved_a, saved_b, saved_c, saved_d; 57 | 58 | ptr = (const unsigned char *)data; 59 | 60 | a = ctx->a; 61 | b = ctx->b; 62 | c = ctx->c; 63 | d = ctx->d; 64 | 65 | do { 66 | saved_a = a; 67 | saved_b = b; 68 | saved_c = c; 69 | saved_d = d; 70 | 71 | /* Round 1 */ 72 | MD5_STEP(MD5_F, a, b, c, d, MD5_SET(0), 0xd76aa478, 7) 73 | MD5_STEP(MD5_F, d, a, b, c, MD5_SET(1), 0xe8c7b756, 12) 74 | MD5_STEP(MD5_F, c, d, a, b, MD5_SET(2), 0x242070db, 17) 75 | MD5_STEP(MD5_F, b, c, d, a, MD5_SET(3), 0xc1bdceee, 22) 76 | MD5_STEP(MD5_F, a, b, c, d, MD5_SET(4), 0xf57c0faf, 7) 77 | MD5_STEP(MD5_F, d, a, b, c, MD5_SET(5), 0x4787c62a, 12) 78 | MD5_STEP(MD5_F, c, d, a, b, MD5_SET(6), 0xa8304613, 17) 79 | MD5_STEP(MD5_F, b, c, d, a, MD5_SET(7), 0xfd469501, 22) 80 | MD5_STEP(MD5_F, a, b, c, d, MD5_SET(8), 0x698098d8, 7) 81 | MD5_STEP(MD5_F, d, a, b, c, MD5_SET(9), 0x8b44f7af, 12) 82 | MD5_STEP(MD5_F, c, d, a, b, MD5_SET(10), 0xffff5bb1, 17) 83 | MD5_STEP(MD5_F, b, c, d, a, MD5_SET(11), 0x895cd7be, 22) 84 | MD5_STEP(MD5_F, a, b, c, d, MD5_SET(12), 0x6b901122, 7) 85 | MD5_STEP(MD5_F, d, a, b, c, MD5_SET(13), 0xfd987193, 12) 86 | MD5_STEP(MD5_F, c, d, a, b, MD5_SET(14), 0xa679438e, 17) 87 | MD5_STEP(MD5_F, b, c, d, a, MD5_SET(15), 0x49b40821, 22) 88 | 89 | /* Round 2 */ 90 | MD5_STEP(MD5_G, a, b, c, d, MD5_GET(1), 0xf61e2562, 5) 91 | MD5_STEP(MD5_G, d, a, b, c, MD5_GET(6), 0xc040b340, 9) 92 | MD5_STEP(MD5_G, c, d, a, b, MD5_GET(11), 0x265e5a51, 14) 93 | MD5_STEP(MD5_G, b, c, d, a, MD5_GET(0), 0xe9b6c7aa, 20) 94 | MD5_STEP(MD5_G, a, b, c, d, MD5_GET(5), 0xd62f105d, 5) 95 | MD5_STEP(MD5_G, d, a, b, c, MD5_GET(10), 0x02441453, 9) 96 | MD5_STEP(MD5_G, c, d, a, b, MD5_GET(15), 0xd8a1e681, 14) 97 | MD5_STEP(MD5_G, b, c, d, a, MD5_GET(4), 0xe7d3fbc8, 20) 98 | MD5_STEP(MD5_G, a, b, c, d, MD5_GET(9), 0x21e1cde6, 5) 99 | MD5_STEP(MD5_G, d, a, b, c, MD5_GET(14), 0xc33707d6, 9) 100 | MD5_STEP(MD5_G, c, d, a, b, MD5_GET(3), 0xf4d50d87, 14) 101 | MD5_STEP(MD5_G, b, c, d, a, MD5_GET(8), 0x455a14ed, 20) 102 | MD5_STEP(MD5_G, a, b, c, d, MD5_GET(13), 0xa9e3e905, 5) 103 | MD5_STEP(MD5_G, d, a, b, c, MD5_GET(2), 0xfcefa3f8, 9) 104 | MD5_STEP(MD5_G, c, d, a, b, MD5_GET(7), 0x676f02d9, 14) 105 | MD5_STEP(MD5_G, b, c, d, a, MD5_GET(12), 0x8d2a4c8a, 20) 106 | 107 | /* Round 3 */ 108 | MD5_STEP(MD5_H, a, b, c, d, MD5_GET(5), 0xfffa3942, 4) 109 | MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(8), 0x8771f681, 11) 110 | MD5_STEP(MD5_H, c, d, a, b, MD5_GET(11), 0x6d9d6122, 16) 111 | MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(14), 0xfde5380c, 23) 112 | MD5_STEP(MD5_H, a, b, c, d, MD5_GET(1), 0xa4beea44, 4) 113 | MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(4), 0x4bdecfa9, 11) 114 | MD5_STEP(MD5_H, c, d, a, b, MD5_GET(7), 0xf6bb4b60, 16) 115 | MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(10), 0xbebfbc70, 23) 116 | MD5_STEP(MD5_H, a, b, c, d, MD5_GET(13), 0x289b7ec6, 4) 117 | MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(0), 0xeaa127fa, 11) 118 | MD5_STEP(MD5_H, c, d, a, b, MD5_GET(3), 0xd4ef3085, 16) 119 | MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(6), 0x04881d05, 23) 120 | MD5_STEP(MD5_H, a, b, c, d, MD5_GET(9), 0xd9d4d039, 4) 121 | MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(12), 0xe6db99e5, 11) 122 | MD5_STEP(MD5_H, c, d, a, b, MD5_GET(15), 0x1fa27cf8, 16) 123 | MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(2), 0xc4ac5665, 23) 124 | 125 | /* Round 4 */ 126 | MD5_STEP(MD5_I, a, b, c, d, MD5_GET(0), 0xf4292244, 6) 127 | MD5_STEP(MD5_I, d, a, b, c, MD5_GET(7), 0x432aff97, 10) 128 | MD5_STEP(MD5_I, c, d, a, b, MD5_GET(14), 0xab9423a7, 15) 129 | MD5_STEP(MD5_I, b, c, d, a, MD5_GET(5), 0xfc93a039, 21) 130 | MD5_STEP(MD5_I, a, b, c, d, MD5_GET(12), 0x655b59c3, 6) 131 | MD5_STEP(MD5_I, d, a, b, c, MD5_GET(3), 0x8f0ccc92, 10) 132 | MD5_STEP(MD5_I, c, d, a, b, MD5_GET(10), 0xffeff47d, 15) 133 | MD5_STEP(MD5_I, b, c, d, a, MD5_GET(1), 0x85845dd1, 21) 134 | MD5_STEP(MD5_I, a, b, c, d, MD5_GET(8), 0x6fa87e4f, 6) 135 | MD5_STEP(MD5_I, d, a, b, c, MD5_GET(15), 0xfe2ce6e0, 10) 136 | MD5_STEP(MD5_I, c, d, a, b, MD5_GET(6), 0xa3014314, 15) 137 | MD5_STEP(MD5_I, b, c, d, a, MD5_GET(13), 0x4e0811a1, 21) 138 | MD5_STEP(MD5_I, a, b, c, d, MD5_GET(4), 0xf7537e82, 6) 139 | MD5_STEP(MD5_I, d, a, b, c, MD5_GET(11), 0xbd3af235, 10) 140 | MD5_STEP(MD5_I, c, d, a, b, MD5_GET(2), 0x2ad7d2bb, 15) 141 | MD5_STEP(MD5_I, b, c, d, a, MD5_GET(9), 0xeb86d391, 21) 142 | 143 | a += saved_a; 144 | b += saved_b; 145 | c += saved_c; 146 | d += saved_d; 147 | 148 | ptr += 64; 149 | } while (size -= 64); 150 | 151 | ctx->a = a; 152 | ctx->b = b; 153 | ctx->c = c; 154 | ctx->d = d; 155 | 156 | return ptr; 157 | } 158 | 159 | void MD5_Init(MD5_CTX *ctx) 160 | { 161 | ctx->a = 0x67452301; 162 | ctx->b = 0xefcdab89; 163 | ctx->c = 0x98badcfe; 164 | ctx->d = 0x10325476; 165 | 166 | ctx->lo = 0; 167 | ctx->hi = 0; 168 | } 169 | 170 | void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size) 171 | { 172 | MD5_u32plus saved_lo; 173 | unsigned long used, available; 174 | 175 | saved_lo = ctx->lo; 176 | if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) 177 | ctx->hi++; 178 | ctx->hi += size >> 29; 179 | 180 | used = saved_lo & 0x3f; 181 | 182 | if (used) { 183 | available = 64 - used; 184 | 185 | if (size < available) { 186 | memcpy(&ctx->buffer[used], data, size); 187 | return; 188 | } 189 | 190 | memcpy(&ctx->buffer[used], data, available); 191 | data = (const unsigned char *)data + available; 192 | size -= available; 193 | MD5_body(ctx, ctx->buffer, 64); 194 | } 195 | 196 | if (size >= 64) { 197 | data = MD5_body(ctx, data, size & ~(unsigned long)0x3f); 198 | size &= 0x3f; 199 | } 200 | 201 | memcpy(ctx->buffer, data, size); 202 | } 203 | 204 | void MD5_Final(unsigned char *result, MD5_CTX *ctx) 205 | { 206 | unsigned long used, available; 207 | 208 | used = ctx->lo & 0x3f; 209 | 210 | ctx->buffer[used++] = 0x80; 211 | 212 | available = 64 - used; 213 | 214 | if (available < 8) { 215 | memset(&ctx->buffer[used], 0, available); 216 | MD5_body(ctx, ctx->buffer, 64); 217 | used = 0; 218 | available = 64; 219 | } 220 | 221 | memset(&ctx->buffer[used], 0, available - 8); 222 | 223 | ctx->lo <<= 3; 224 | ctx->buffer[56] = ctx->lo; 225 | ctx->buffer[57] = ctx->lo >> 8; 226 | ctx->buffer[58] = ctx->lo >> 16; 227 | ctx->buffer[59] = ctx->lo >> 24; 228 | ctx->buffer[60] = ctx->hi; 229 | ctx->buffer[61] = ctx->hi >> 8; 230 | ctx->buffer[62] = ctx->hi >> 16; 231 | ctx->buffer[63] = ctx->hi >> 24; 232 | 233 | MD5_body(ctx, ctx->buffer, 64); 234 | 235 | result[0] = ctx->a; 236 | result[1] = ctx->a >> 8; 237 | result[2] = ctx->a >> 16; 238 | result[3] = ctx->a >> 24; 239 | result[4] = ctx->b; 240 | result[5] = ctx->b >> 8; 241 | result[6] = ctx->b >> 16; 242 | result[7] = ctx->b >> 24; 243 | result[8] = ctx->c; 244 | result[9] = ctx->c >> 8; 245 | result[10] = ctx->c >> 16; 246 | result[11] = ctx->c >> 24; 247 | result[12] = ctx->d; 248 | result[13] = ctx->d >> 8; 249 | result[14] = ctx->d >> 16; 250 | result[15] = ctx->d >> 24; 251 | 252 | memset(ctx, 0, sizeof(*ctx)); 253 | } 254 | 255 | #ifdef __NOT_INCLUDE__ 256 | 257 | #include 258 | 259 | int main (int argc, char *argv[]) 260 | { 261 | /* For each command line argument in turn: 262 | ** filename -- prints message digest and name of file 263 | */ 264 | int i; 265 | MD5_CTX ctx; 266 | FILE* file; 267 | size_t numread; 268 | char buffer[16384]; 269 | unsigned char result[16]; 270 | 271 | for (i = 1; i < argc; i++) 272 | { 273 | MD5_Init(&ctx); 274 | file = fopen(argv[i], "rb"); 275 | 276 | if (file) 277 | { 278 | do 279 | { 280 | numread = fread((void*)buffer, 1, sizeof(buffer), file); 281 | 282 | if (numread) 283 | { 284 | MD5_Update(&ctx,(void*)buffer, numread); 285 | } 286 | } 287 | while (numread); 288 | 289 | fclose(file); 290 | MD5_Final(result, &ctx); 291 | printf("%02x%02x%02x%02x%02x%02x%02x%02x" 292 | "%02x%02x%02x%02x%02x%02x%02x%02x %s\n", 293 | result[ 0 ], result[ 1 ], result[ 2 ], result[ 3 ], 294 | result[ 4 ], result[ 5 ], result[ 6 ], result[ 7 ], 295 | result[ 8 ], result[ 9 ], result[ 10 ], result[ 11 ], 296 | result[ 12 ], result[ 13 ], result[ 14 ], result[ 15 ], 297 | argv[i]); 298 | } 299 | } 300 | 301 | return 0; 302 | } 303 | 304 | #endif -------------------------------------------------------------------------------- /include/quickjs-opcode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS opcode definitions 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * Copyright (c) 2017-2018 Charlie Gordon 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | #ifdef FMT 27 | FMT(none) 28 | FMT(none_int) 29 | FMT(none_loc) 30 | FMT(none_arg) 31 | FMT(none_var_ref) 32 | FMT(u8) 33 | FMT(i8) 34 | FMT(loc8) 35 | FMT(const8) 36 | FMT(label8) 37 | FMT(u16) 38 | FMT(i16) 39 | FMT(label16) 40 | FMT(npop) 41 | FMT(npopx) 42 | FMT(npop_u16) 43 | FMT(loc) 44 | FMT(arg) 45 | FMT(var_ref) 46 | FMT(u32) 47 | FMT(i32) 48 | FMT(const) 49 | FMT(label) 50 | FMT(atom) 51 | FMT(atom_u8) 52 | FMT(atom_u16) 53 | FMT(atom_label_u8) 54 | FMT(atom_label_u16) 55 | FMT(label_u16) 56 | #undef FMT 57 | #endif /* FMT */ 58 | 59 | #ifdef DEF 60 | 61 | #ifndef def 62 | #define def(id, size, n_pop, n_push, f) DEF(id, size, n_pop, n_push, f) 63 | #endif 64 | 65 | DEF(invalid, 1, 0, 0, none) /* never emitted */ 66 | 67 | /* push values */ 68 | DEF( push_i32, 5, 0, 1, i32) 69 | DEF( push_const, 5, 0, 1, const) 70 | DEF( fclosure, 5, 0, 1, const) /* must follow push_const */ 71 | DEF(push_atom_value, 5, 0, 1, atom) 72 | DEF( private_symbol, 5, 0, 1, atom) 73 | DEF( undefined, 1, 0, 1, none) 74 | DEF( null, 1, 0, 1, none) 75 | DEF( push_this, 1, 0, 1, none) /* only used at the start of a function */ 76 | DEF( push_false, 1, 0, 1, none) 77 | DEF( push_true, 1, 0, 1, none) 78 | DEF( object, 1, 0, 1, none) 79 | DEF( special_object, 2, 0, 1, u8) /* only used at the start of a function */ 80 | DEF( rest, 3, 0, 1, u16) /* only used at the start of a function */ 81 | 82 | DEF( drop, 1, 1, 0, none) /* a -> */ 83 | DEF( nip, 1, 2, 1, none) /* a b -> b */ 84 | DEF( nip1, 1, 3, 2, none) /* a b c -> b c */ 85 | DEF( dup, 1, 1, 2, none) /* a -> a a */ 86 | DEF( dup1, 1, 2, 3, none) /* a b -> a a b */ 87 | DEF( dup2, 1, 2, 4, none) /* a b -> a b a b */ 88 | DEF( dup3, 1, 3, 6, none) /* a b c -> a b c a b c */ 89 | DEF( insert2, 1, 2, 3, none) /* obj a -> a obj a (dup_x1) */ 90 | DEF( insert3, 1, 3, 4, none) /* obj prop a -> a obj prop a (dup_x2) */ 91 | DEF( insert4, 1, 4, 5, none) /* this obj prop a -> a this obj prop a */ 92 | DEF( perm3, 1, 3, 3, none) /* obj a b -> a obj b */ 93 | DEF( perm4, 1, 4, 4, none) /* obj prop a b -> a obj prop b */ 94 | DEF( perm5, 1, 5, 5, none) /* this obj prop a b -> a this obj prop b */ 95 | DEF( swap, 1, 2, 2, none) /* a b -> b a */ 96 | DEF( swap2, 1, 4, 4, none) /* a b c d -> c d a b */ 97 | DEF( rot3l, 1, 3, 3, none) /* x a b -> a b x */ 98 | DEF( rot3r, 1, 3, 3, none) /* a b x -> x a b */ 99 | DEF( rot4l, 1, 4, 4, none) /* x a b c -> a b c x */ 100 | DEF( rot5l, 1, 5, 5, none) /* x a b c d -> a b c d x */ 101 | 102 | DEF(call_constructor, 3, 2, 1, npop) /* func new.target args -> ret. arguments are not counted in n_pop */ 103 | DEF( call, 3, 1, 1, npop) /* arguments are not counted in n_pop */ 104 | DEF( tail_call, 3, 1, 0, npop) /* arguments are not counted in n_pop */ 105 | DEF( call_method, 3, 2, 1, npop) /* arguments are not counted in n_pop */ 106 | DEF(tail_call_method, 3, 2, 0, npop) /* arguments are not counted in n_pop */ 107 | DEF( array_from, 3, 0, 1, npop) /* arguments are not counted in n_pop */ 108 | DEF( apply, 3, 3, 1, u16) 109 | DEF( return, 1, 1, 0, none) 110 | DEF( return_undef, 1, 0, 0, none) 111 | DEF(check_ctor_return, 1, 1, 2, none) 112 | DEF( check_ctor, 1, 0, 0, none) 113 | DEF( check_brand, 1, 2, 2, none) /* this_obj func -> this_obj func */ 114 | DEF( add_brand, 1, 2, 0, none) /* this_obj home_obj -> */ 115 | DEF( return_async, 1, 1, 0, none) 116 | DEF( throw, 1, 1, 0, none) 117 | DEF( throw_var, 6, 0, 0, atom_u8) 118 | DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */ 119 | DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */ 120 | DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a 121 | bytecode string */ 122 | DEF( get_super_ctor, 1, 1, 1, none) 123 | DEF( get_super, 1, 1, 1, none) 124 | DEF( import, 1, 1, 1, none) /* dynamic module import */ 125 | 126 | DEF( check_var, 5, 0, 1, atom) /* check if a variable exists */ 127 | DEF( get_var_undef, 5, 0, 1, atom) /* push undefined if the variable does not exist */ 128 | DEF( get_var, 5, 0, 1, atom) /* throw an exception if the variable does not exist */ 129 | DEF( put_var, 5, 1, 0, atom) /* must come after get_var */ 130 | DEF( put_var_init, 5, 1, 0, atom) /* must come after put_var. Used to initialize a global lexical variable */ 131 | DEF( put_var_strict, 5, 2, 0, atom) /* for strict mode variable write */ 132 | 133 | DEF( get_ref_value, 1, 2, 3, none) 134 | DEF( put_ref_value, 1, 3, 0, none) 135 | 136 | DEF( define_var, 6, 0, 0, atom_u8) 137 | DEF(check_define_var, 6, 0, 0, atom_u8) 138 | DEF( define_func, 6, 1, 0, atom_u8) 139 | DEF( get_field, 5, 1, 1, atom) 140 | DEF( get_field2, 5, 1, 2, atom) 141 | DEF( put_field, 5, 2, 0, atom) 142 | DEF( get_private_field, 1, 2, 1, none) /* obj prop -> value */ 143 | DEF( put_private_field, 1, 3, 0, none) /* obj value prop -> */ 144 | DEF(define_private_field, 1, 3, 1, none) /* obj prop value -> obj */ 145 | DEF( get_array_el, 1, 2, 1, none) 146 | DEF( get_array_el2, 1, 2, 2, none) /* obj prop -> obj value */ 147 | DEF( put_array_el, 1, 3, 0, none) 148 | DEF(get_super_value, 1, 3, 1, none) /* this obj prop -> value */ 149 | DEF(put_super_value, 1, 4, 0, none) /* this obj prop value -> */ 150 | DEF( define_field, 5, 2, 1, atom) 151 | DEF( set_name, 5, 1, 1, atom) 152 | DEF(set_name_computed, 1, 2, 2, none) 153 | DEF( set_proto, 1, 2, 1, none) 154 | DEF(set_home_object, 1, 2, 2, none) 155 | DEF(define_array_el, 1, 3, 2, none) 156 | DEF( append, 1, 3, 2, none) /* append enumerated object, update length */ 157 | DEF(copy_data_properties, 2, 3, 3, u8) 158 | DEF( define_method, 6, 2, 1, atom_u8) 159 | DEF(define_method_computed, 2, 3, 1, u8) /* must come after define_method */ 160 | DEF( define_class, 6, 2, 2, atom_u8) /* parent ctor -> ctor proto */ 161 | DEF( define_class_computed, 6, 3, 3, atom_u8) /* field_name parent ctor -> field_name ctor proto (class with computed name) */ 162 | 163 | DEF( get_loc, 3, 0, 1, loc) 164 | DEF( put_loc, 3, 1, 0, loc) /* must come after get_loc */ 165 | DEF( set_loc, 3, 1, 1, loc) /* must come after put_loc */ 166 | DEF( get_arg, 3, 0, 1, arg) 167 | DEF( put_arg, 3, 1, 0, arg) /* must come after get_arg */ 168 | DEF( set_arg, 3, 1, 1, arg) /* must come after put_arg */ 169 | DEF( get_var_ref, 3, 0, 1, var_ref) 170 | DEF( put_var_ref, 3, 1, 0, var_ref) /* must come after get_var_ref */ 171 | DEF( set_var_ref, 3, 1, 1, var_ref) /* must come after put_var_ref */ 172 | DEF(set_loc_uninitialized, 3, 0, 0, loc) 173 | DEF( get_loc_check, 3, 0, 1, loc) 174 | DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */ 175 | DEF( put_loc_check_init, 3, 1, 0, loc) 176 | DEF(get_var_ref_check, 3, 0, 1, var_ref) 177 | DEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */ 178 | DEF(put_var_ref_check_init, 3, 1, 0, var_ref) 179 | DEF( close_loc, 3, 0, 0, loc) 180 | DEF( if_false, 5, 1, 0, label) 181 | DEF( if_true, 5, 1, 0, label) /* must come after if_false */ 182 | DEF( goto, 5, 0, 0, label) /* must come after if_true */ 183 | DEF( catch, 5, 0, 1, label) 184 | DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */ 185 | DEF( ret, 1, 1, 0, none) /* used to return from the finally block */ 186 | 187 | DEF( to_object, 1, 1, 1, none) 188 | //DEF( to_string, 1, 1, 1, none) 189 | DEF( to_propkey, 1, 1, 1, none) 190 | DEF( to_propkey2, 1, 2, 2, none) 191 | 192 | DEF( with_get_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ 193 | DEF( with_put_var, 10, 2, 1, atom_label_u8) /* must be in the same order as scope_xxx */ 194 | DEF(with_delete_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ 195 | DEF( with_make_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ 196 | DEF( with_get_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ 197 | DEF(with_get_ref_undef, 10, 1, 0, atom_label_u8) 198 | 199 | DEF( make_loc_ref, 7, 0, 2, atom_u16) 200 | DEF( make_arg_ref, 7, 0, 2, atom_u16) 201 | DEF(make_var_ref_ref, 7, 0, 2, atom_u16) 202 | DEF( make_var_ref, 5, 0, 2, atom) 203 | 204 | DEF( for_in_start, 1, 1, 1, none) 205 | DEF( for_of_start, 1, 1, 3, none) 206 | DEF(for_await_of_start, 1, 1, 3, none) 207 | DEF( for_in_next, 1, 1, 3, none) 208 | DEF( for_of_next, 2, 3, 5, u8) 209 | DEF(for_await_of_next, 1, 3, 4, none) 210 | DEF(iterator_get_value_done, 1, 1, 2, none) 211 | DEF( iterator_close, 1, 3, 0, none) 212 | DEF(iterator_close_return, 1, 4, 4, none) 213 | DEF(async_iterator_close, 1, 3, 2, none) 214 | DEF(async_iterator_next, 1, 4, 4, none) 215 | DEF(async_iterator_get, 2, 4, 5, u8) 216 | DEF( initial_yield, 1, 0, 0, none) 217 | DEF( yield, 1, 1, 2, none) 218 | DEF( yield_star, 1, 2, 2, none) 219 | DEF(async_yield_star, 1, 1, 2, none) 220 | DEF( await, 1, 1, 1, none) 221 | 222 | /* arithmetic/logic operations */ 223 | DEF( neg, 1, 1, 1, none) 224 | DEF( plus, 1, 1, 1, none) 225 | DEF( dec, 1, 1, 1, none) 226 | DEF( inc, 1, 1, 1, none) 227 | DEF( post_dec, 1, 1, 2, none) 228 | DEF( post_inc, 1, 1, 2, none) 229 | DEF( dec_loc, 2, 0, 0, loc8) 230 | DEF( inc_loc, 2, 0, 0, loc8) 231 | DEF( add_loc, 2, 1, 0, loc8) 232 | DEF( not, 1, 1, 1, none) 233 | DEF( lnot, 1, 1, 1, none) 234 | DEF( typeof, 1, 1, 1, none) 235 | DEF( delete, 1, 2, 1, none) 236 | DEF( delete_var, 5, 0, 1, atom) 237 | 238 | DEF( mul, 1, 2, 1, none) 239 | DEF( div, 1, 2, 1, none) 240 | DEF( mod, 1, 2, 1, none) 241 | DEF( add, 1, 2, 1, none) 242 | DEF( sub, 1, 2, 1, none) 243 | DEF( pow, 1, 2, 1, none) 244 | DEF( shl, 1, 2, 1, none) 245 | DEF( sar, 1, 2, 1, none) 246 | DEF( shr, 1, 2, 1, none) 247 | DEF( lt, 1, 2, 1, none) 248 | DEF( lte, 1, 2, 1, none) 249 | DEF( gt, 1, 2, 1, none) 250 | DEF( gte, 1, 2, 1, none) 251 | DEF( instanceof, 1, 2, 1, none) 252 | DEF( in, 1, 2, 1, none) 253 | DEF( eq, 1, 2, 1, none) 254 | DEF( neq, 1, 2, 1, none) 255 | DEF( strict_eq, 1, 2, 1, none) 256 | DEF( strict_neq, 1, 2, 1, none) 257 | DEF( and, 1, 2, 1, none) 258 | DEF( xor, 1, 2, 1, none) 259 | DEF( or, 1, 2, 1, none) 260 | DEF(is_undefined_or_null, 1, 1, 1, none) 261 | #ifdef CONFIG_BIGNUM 262 | DEF( mul_pow10, 1, 2, 1, none) 263 | DEF( math_mod, 1, 2, 1, none) 264 | #endif 265 | /* must be the last non short and non temporary opcode */ 266 | DEF( nop, 1, 0, 0, none) 267 | 268 | /* temporary opcodes: never emitted in the final bytecode */ 269 | 270 | def(set_arg_valid_upto, 3, 0, 0, arg) /* emitted in phase 1, removed in phase 2 */ 271 | 272 | def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ 273 | def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ 274 | 275 | def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */ 276 | 277 | def(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ 278 | def( scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ 279 | def( scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */ 280 | def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ 281 | def( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */ 282 | def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ 283 | def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ 284 | def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */ 285 | def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */ 286 | def(scope_put_private_field, 7, 1, 1, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */ 287 | 288 | def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */ 289 | 290 | def( line_num, 5, 0, 0, u32) /* emitted in phase 1, removed in phase 3 */ 291 | 292 | #if SHORT_OPCODES 293 | DEF( push_minus1, 1, 0, 1, none_int) 294 | DEF( push_0, 1, 0, 1, none_int) 295 | DEF( push_1, 1, 0, 1, none_int) 296 | DEF( push_2, 1, 0, 1, none_int) 297 | DEF( push_3, 1, 0, 1, none_int) 298 | DEF( push_4, 1, 0, 1, none_int) 299 | DEF( push_5, 1, 0, 1, none_int) 300 | DEF( push_6, 1, 0, 1, none_int) 301 | DEF( push_7, 1, 0, 1, none_int) 302 | DEF( push_i8, 2, 0, 1, i8) 303 | DEF( push_i16, 3, 0, 1, i16) 304 | DEF( push_const8, 2, 0, 1, const8) 305 | DEF( fclosure8, 2, 0, 1, const8) /* must follow push_const8 */ 306 | DEF(push_empty_string, 1, 0, 1, none) 307 | 308 | DEF( get_loc8, 2, 0, 1, loc8) 309 | DEF( put_loc8, 2, 1, 0, loc8) 310 | DEF( set_loc8, 2, 1, 1, loc8) 311 | 312 | DEF( get_loc0, 1, 0, 1, none_loc) 313 | DEF( get_loc1, 1, 0, 1, none_loc) 314 | DEF( get_loc2, 1, 0, 1, none_loc) 315 | DEF( get_loc3, 1, 0, 1, none_loc) 316 | DEF( put_loc0, 1, 1, 0, none_loc) 317 | DEF( put_loc1, 1, 1, 0, none_loc) 318 | DEF( put_loc2, 1, 1, 0, none_loc) 319 | DEF( put_loc3, 1, 1, 0, none_loc) 320 | DEF( set_loc0, 1, 1, 1, none_loc) 321 | DEF( set_loc1, 1, 1, 1, none_loc) 322 | DEF( set_loc2, 1, 1, 1, none_loc) 323 | DEF( set_loc3, 1, 1, 1, none_loc) 324 | DEF( get_arg0, 1, 0, 1, none_arg) 325 | DEF( get_arg1, 1, 0, 1, none_arg) 326 | DEF( get_arg2, 1, 0, 1, none_arg) 327 | DEF( get_arg3, 1, 0, 1, none_arg) 328 | DEF( put_arg0, 1, 1, 0, none_arg) 329 | DEF( put_arg1, 1, 1, 0, none_arg) 330 | DEF( put_arg2, 1, 1, 0, none_arg) 331 | DEF( put_arg3, 1, 1, 0, none_arg) 332 | DEF( set_arg0, 1, 1, 1, none_arg) 333 | DEF( set_arg1, 1, 1, 1, none_arg) 334 | DEF( set_arg2, 1, 1, 1, none_arg) 335 | DEF( set_arg3, 1, 1, 1, none_arg) 336 | DEF( get_var_ref0, 1, 0, 1, none_var_ref) 337 | DEF( get_var_ref1, 1, 0, 1, none_var_ref) 338 | DEF( get_var_ref2, 1, 0, 1, none_var_ref) 339 | DEF( get_var_ref3, 1, 0, 1, none_var_ref) 340 | DEF( put_var_ref0, 1, 1, 0, none_var_ref) 341 | DEF( put_var_ref1, 1, 1, 0, none_var_ref) 342 | DEF( put_var_ref2, 1, 1, 0, none_var_ref) 343 | DEF( put_var_ref3, 1, 1, 0, none_var_ref) 344 | DEF( set_var_ref0, 1, 1, 1, none_var_ref) 345 | DEF( set_var_ref1, 1, 1, 1, none_var_ref) 346 | DEF( set_var_ref2, 1, 1, 1, none_var_ref) 347 | DEF( set_var_ref3, 1, 1, 1, none_var_ref) 348 | 349 | DEF( get_length, 1, 1, 1, none) 350 | 351 | DEF( if_false8, 2, 1, 0, label8) 352 | DEF( if_true8, 2, 1, 0, label8) /* must come after if_false8 */ 353 | DEF( goto8, 2, 0, 0, label8) /* must come after if_true8 */ 354 | DEF( goto16, 3, 0, 0, label16) 355 | 356 | DEF( call0, 1, 1, 1, npopx) 357 | DEF( call1, 1, 1, 1, npopx) 358 | DEF( call2, 1, 1, 1, npopx) 359 | DEF( call3, 1, 1, 1, npopx) 360 | 361 | DEF( is_undefined, 1, 1, 1, none) 362 | DEF( is_null, 1, 1, 1, none) 363 | DEF( is_function, 1, 1, 1, none) 364 | #endif 365 | 366 | #undef DEF 367 | #undef def 368 | #endif /* DEF */ 369 | -------------------------------------------------------------------------------- /src/cutils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * C utilities 3 | * 4 | * Copyright (c) 2017 Fabrice Bellard 5 | * Copyright (c) 2018 Charlie Gordon 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "cutils.h" 31 | 32 | void pstrcpy(char *buf, int buf_size, const char *str) 33 | { 34 | int c; 35 | char *q = buf; 36 | 37 | if (buf_size <= 0) 38 | return; 39 | 40 | for(;;) { 41 | c = *str++; 42 | if (c == 0 || q >= buf + buf_size - 1) 43 | break; 44 | *q++ = c; 45 | } 46 | *q = '\0'; 47 | } 48 | 49 | /* strcat and truncate. */ 50 | char *pstrcat(char *buf, int buf_size, const char *s) 51 | { 52 | int len; 53 | len = strlen(buf); 54 | if (len < buf_size) 55 | pstrcpy(buf + len, buf_size - len, s); 56 | return buf; 57 | } 58 | 59 | int strstart(const char *str, const char *val, const char **ptr) 60 | { 61 | const char *p, *q; 62 | p = str; 63 | q = val; 64 | while (*q != '\0') { 65 | if (*p != *q) 66 | return 0; 67 | p++; 68 | q++; 69 | } 70 | if (ptr) 71 | *ptr = p; 72 | return 1; 73 | } 74 | 75 | int has_suffix(const char *str, const char *suffix) 76 | { 77 | size_t len = strlen(str); 78 | size_t slen = strlen(suffix); 79 | return (len >= slen && !memcmp(str + len - slen, suffix, slen)); 80 | } 81 | 82 | /* Dynamic buffer package */ 83 | 84 | static void *dbuf_default_realloc(void *opaque, void *ptr, size_t size) 85 | { 86 | return realloc(ptr, size); 87 | } 88 | 89 | void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func) 90 | { 91 | memset(s, 0, sizeof(*s)); 92 | if (!realloc_func) 93 | realloc_func = dbuf_default_realloc; 94 | s->opaque = opaque; 95 | s->realloc_func = realloc_func; 96 | } 97 | 98 | void dbuf_init(DynBuf *s) 99 | { 100 | dbuf_init2(s, NULL, NULL); 101 | } 102 | 103 | /* return < 0 if error */ 104 | int dbuf_realloc(DynBuf *s, size_t new_size) 105 | { 106 | size_t size; 107 | uint8_t *new_buf; 108 | if (new_size > s->allocated_size) { 109 | if (s->error) 110 | return -1; 111 | size = s->allocated_size * 3 / 2; 112 | if (size > new_size) 113 | new_size = size; 114 | new_buf = s->realloc_func(s->opaque, s->buf, new_size); 115 | if (!new_buf) { 116 | s->error = TRUE; 117 | return -1; 118 | } 119 | s->buf = new_buf; 120 | s->allocated_size = new_size; 121 | } 122 | return 0; 123 | } 124 | 125 | int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len) 126 | { 127 | size_t end; 128 | end = offset + len; 129 | if (dbuf_realloc(s, end)) 130 | return -1; 131 | memcpy(s->buf + offset, data, len); 132 | if (end > s->size) 133 | s->size = end; 134 | return 0; 135 | } 136 | 137 | int dbuf_put(DynBuf *s, const uint8_t *data, size_t len) 138 | { 139 | if (unlikely((s->size + len) > s->allocated_size)) { 140 | if (dbuf_realloc(s, s->size + len)) 141 | return -1; 142 | } 143 | memcpy(s->buf + s->size, data, len); 144 | s->size += len; 145 | return 0; 146 | } 147 | 148 | int dbuf_put_self(DynBuf *s, size_t offset, size_t len) 149 | { 150 | if (unlikely((s->size + len) > s->allocated_size)) { 151 | if (dbuf_realloc(s, s->size + len)) 152 | return -1; 153 | } 154 | memcpy(s->buf + s->size, s->buf + offset, len); 155 | s->size += len; 156 | return 0; 157 | } 158 | 159 | int dbuf_putc(DynBuf *s, uint8_t c) 160 | { 161 | return dbuf_put(s, &c, 1); 162 | } 163 | 164 | int dbuf_putstr(DynBuf *s, const char *str) 165 | { 166 | return dbuf_put(s, (const uint8_t *)str, strlen(str)); 167 | } 168 | 169 | int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s, 170 | const char *fmt, ...) 171 | { 172 | va_list ap; 173 | char buf[128]; 174 | int len; 175 | 176 | va_start(ap, fmt); 177 | len = vsnprintf(buf, sizeof(buf), fmt, ap); 178 | va_end(ap); 179 | if (len < sizeof(buf)) { 180 | /* fast case */ 181 | return dbuf_put(s, (uint8_t *)buf, len); 182 | } else { 183 | if (dbuf_realloc(s, s->size + len + 1)) 184 | return -1; 185 | va_start(ap, fmt); 186 | vsnprintf((char *)(s->buf + s->size), s->allocated_size - s->size, 187 | fmt, ap); 188 | va_end(ap); 189 | s->size += len; 190 | } 191 | return 0; 192 | } 193 | 194 | void dbuf_free(DynBuf *s) 195 | { 196 | /* we test s->buf as a fail safe to avoid crashing if dbuf_free() 197 | is called twice */ 198 | if (s->buf) { 199 | s->realloc_func(s->opaque, s->buf, 0); 200 | } 201 | memset(s, 0, sizeof(*s)); 202 | } 203 | 204 | /* Note: at most 31 bits are encoded. At most UTF8_CHAR_LEN_MAX bytes 205 | are output. */ 206 | int unicode_to_utf8(uint8_t *buf, unsigned int c) 207 | { 208 | uint8_t *q = buf; 209 | 210 | if (c < 0x80) { 211 | *q++ = c; 212 | } else { 213 | if (c < 0x800) { 214 | *q++ = (c >> 6) | 0xc0; 215 | } else { 216 | if (c < 0x10000) { 217 | *q++ = (c >> 12) | 0xe0; 218 | } else { 219 | if (c < 0x00200000) { 220 | *q++ = (c >> 18) | 0xf0; 221 | } else { 222 | if (c < 0x04000000) { 223 | *q++ = (c >> 24) | 0xf8; 224 | } else if (c < 0x80000000) { 225 | *q++ = (c >> 30) | 0xfc; 226 | *q++ = ((c >> 24) & 0x3f) | 0x80; 227 | } else { 228 | return 0; 229 | } 230 | *q++ = ((c >> 18) & 0x3f) | 0x80; 231 | } 232 | *q++ = ((c >> 12) & 0x3f) | 0x80; 233 | } 234 | *q++ = ((c >> 6) & 0x3f) | 0x80; 235 | } 236 | *q++ = (c & 0x3f) | 0x80; 237 | } 238 | return q - buf; 239 | } 240 | 241 | static const unsigned int utf8_min_code[5] = { 242 | 0x80, 0x800, 0x10000, 0x00200000, 0x04000000, 243 | }; 244 | 245 | static const unsigned char utf8_first_code_mask[5] = { 246 | 0x1f, 0xf, 0x7, 0x3, 0x1, 247 | }; 248 | 249 | /* return -1 if error. *pp is not updated in this case. max_len must 250 | be >= 1. The maximum length for a UTF8 byte sequence is 6 bytes. */ 251 | int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp) 252 | { 253 | int l, c, b, i; 254 | 255 | c = *p++; 256 | if (c < 0x80) { 257 | *pp = p; 258 | return c; 259 | } 260 | switch(c) { 261 | case 0xc0 ... 0xdf: 262 | l = 1; 263 | break; 264 | case 0xe0 ... 0xef: 265 | l = 2; 266 | break; 267 | case 0xf0 ... 0xf7: 268 | l = 3; 269 | break; 270 | case 0xf8 ... 0xfb: 271 | l = 4; 272 | break; 273 | case 0xfc ... 0xfd: 274 | l = 5; 275 | break; 276 | default: 277 | return -1; 278 | } 279 | /* check that we have enough characters */ 280 | if (l > (max_len - 1)) 281 | return -1; 282 | c &= utf8_first_code_mask[l - 1]; 283 | for(i = 0; i < l; i++) { 284 | b = *p++; 285 | if (b < 0x80 || b >= 0xc0) 286 | return -1; 287 | c = (c << 6) | (b & 0x3f); 288 | } 289 | if (c < utf8_min_code[l - 1]) 290 | return -1; 291 | *pp = p; 292 | return c; 293 | } 294 | 295 | #if 0 296 | 297 | #if defined(EMSCRIPTEN) || defined(__ANDROID__) 298 | 299 | static void *rqsort_arg; 300 | static int (*rqsort_cmp)(const void *, const void *, void *); 301 | 302 | static int rqsort_cmp2(const void *p1, const void *p2) 303 | { 304 | return rqsort_cmp(p1, p2, rqsort_arg); 305 | } 306 | 307 | /* not reentrant, but not needed with emscripten */ 308 | void rqsort(void *base, size_t nmemb, size_t size, 309 | int (*cmp)(const void *, const void *, void *), 310 | void *arg) 311 | { 312 | rqsort_arg = arg; 313 | rqsort_cmp = cmp; 314 | qsort(base, nmemb, size, rqsort_cmp2); 315 | } 316 | 317 | #endif 318 | 319 | #else 320 | 321 | typedef void (*exchange_f)(void *a, void *b, size_t size); 322 | typedef int (*cmp_f)(const void *, const void *, void *opaque); 323 | 324 | static void exchange_bytes(void *a, void *b, size_t size) { 325 | uint8_t *ap = (uint8_t *)a; 326 | uint8_t *bp = (uint8_t *)b; 327 | 328 | while (size-- != 0) { 329 | uint8_t t = *ap; 330 | *ap++ = *bp; 331 | *bp++ = t; 332 | } 333 | } 334 | 335 | static void exchange_one_byte(void *a, void *b, size_t size) { 336 | uint8_t *ap = (uint8_t *)a; 337 | uint8_t *bp = (uint8_t *)b; 338 | uint8_t t = *ap; 339 | *ap = *bp; 340 | *bp = t; 341 | } 342 | 343 | static void exchange_int16s(void *a, void *b, size_t size) { 344 | uint16_t *ap = (uint16_t *)a; 345 | uint16_t *bp = (uint16_t *)b; 346 | 347 | for (size /= sizeof(uint16_t); size-- != 0;) { 348 | uint16_t t = *ap; 349 | *ap++ = *bp; 350 | *bp++ = t; 351 | } 352 | } 353 | 354 | static void exchange_one_int16(void *a, void *b, size_t size) { 355 | uint16_t *ap = (uint16_t *)a; 356 | uint16_t *bp = (uint16_t *)b; 357 | uint16_t t = *ap; 358 | *ap = *bp; 359 | *bp = t; 360 | } 361 | 362 | static void exchange_int32s(void *a, void *b, size_t size) { 363 | uint32_t *ap = (uint32_t *)a; 364 | uint32_t *bp = (uint32_t *)b; 365 | 366 | for (size /= sizeof(uint32_t); size-- != 0;) { 367 | uint32_t t = *ap; 368 | *ap++ = *bp; 369 | *bp++ = t; 370 | } 371 | } 372 | 373 | static void exchange_one_int32(void *a, void *b, size_t size) { 374 | uint32_t *ap = (uint32_t *)a; 375 | uint32_t *bp = (uint32_t *)b; 376 | uint32_t t = *ap; 377 | *ap = *bp; 378 | *bp = t; 379 | } 380 | 381 | static void exchange_int64s(void *a, void *b, size_t size) { 382 | uint64_t *ap = (uint64_t *)a; 383 | uint64_t *bp = (uint64_t *)b; 384 | 385 | for (size /= sizeof(uint64_t); size-- != 0;) { 386 | uint64_t t = *ap; 387 | *ap++ = *bp; 388 | *bp++ = t; 389 | } 390 | } 391 | 392 | static void exchange_one_int64(void *a, void *b, size_t size) { 393 | uint64_t *ap = (uint64_t *)a; 394 | uint64_t *bp = (uint64_t *)b; 395 | uint64_t t = *ap; 396 | *ap = *bp; 397 | *bp = t; 398 | } 399 | 400 | static void exchange_int128s(void *a, void *b, size_t size) { 401 | uint64_t *ap = (uint64_t *)a; 402 | uint64_t *bp = (uint64_t *)b; 403 | 404 | for (size /= sizeof(uint64_t) * 2; size-- != 0; ap += 2, bp += 2) { 405 | uint64_t t = ap[0]; 406 | uint64_t u = ap[1]; 407 | ap[0] = bp[0]; 408 | ap[1] = bp[1]; 409 | bp[0] = t; 410 | bp[1] = u; 411 | } 412 | } 413 | 414 | static void exchange_one_int128(void *a, void *b, size_t size) { 415 | uint64_t *ap = (uint64_t *)a; 416 | uint64_t *bp = (uint64_t *)b; 417 | uint64_t t = ap[0]; 418 | uint64_t u = ap[1]; 419 | ap[0] = bp[0]; 420 | ap[1] = bp[1]; 421 | bp[0] = t; 422 | bp[1] = u; 423 | } 424 | 425 | static inline exchange_f exchange_func(const void *base, size_t size) { 426 | switch (((uintptr_t)base | (uintptr_t)size) & 15) { 427 | case 0: 428 | if (size == sizeof(uint64_t) * 2) 429 | return exchange_one_int128; 430 | else 431 | return exchange_int128s; 432 | case 8: 433 | if (size == sizeof(uint64_t)) 434 | return exchange_one_int64; 435 | else 436 | return exchange_int64s; 437 | case 4: 438 | case 12: 439 | if (size == sizeof(uint32_t)) 440 | return exchange_one_int32; 441 | else 442 | return exchange_int32s; 443 | case 2: 444 | case 6: 445 | case 10: 446 | case 14: 447 | if (size == sizeof(uint16_t)) 448 | return exchange_one_int16; 449 | else 450 | return exchange_int16s; 451 | default: 452 | if (size == 1) 453 | return exchange_one_byte; 454 | else 455 | return exchange_bytes; 456 | } 457 | } 458 | 459 | static void heapsortx(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque) 460 | { 461 | uint8_t *basep = (uint8_t *)base; 462 | size_t i, n, c, r; 463 | exchange_f swap = exchange_func(base, size); 464 | 465 | if (nmemb > 1) { 466 | i = (nmemb / 2) * size; 467 | n = nmemb * size; 468 | 469 | while (i > 0) { 470 | i -= size; 471 | for (r = i; (c = r * 2 + size) < n; r = c) { 472 | if (c < n - size && cmp(basep + c, basep + c + size, opaque) <= 0) 473 | c += size; 474 | if (cmp(basep + r, basep + c, opaque) > 0) 475 | break; 476 | swap(basep + r, basep + c, size); 477 | } 478 | } 479 | for (i = n - size; i > 0; i -= size) { 480 | swap(basep, basep + i, size); 481 | 482 | for (r = 0; (c = r * 2 + size) < i; r = c) { 483 | if (c < i - size && cmp(basep + c, basep + c + size, opaque) <= 0) 484 | c += size; 485 | if (cmp(basep + r, basep + c, opaque) > 0) 486 | break; 487 | swap(basep + r, basep + c, size); 488 | } 489 | } 490 | } 491 | } 492 | 493 | static inline void *med3(void *a, void *b, void *c, cmp_f cmp, void *opaque) 494 | { 495 | return cmp(a, b, opaque) < 0 ? 496 | (cmp(b, c, opaque) < 0 ? b : (cmp(a, c, opaque) < 0 ? c : a )) : 497 | (cmp(b, c, opaque) > 0 ? b : (cmp(a, c, opaque) < 0 ? a : c )); 498 | } 499 | 500 | /* pointer based version with local stack and insertion sort threshhold */ 501 | void rqsort(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque) 502 | { 503 | struct { uint8_t *base; size_t count; int depth; } stack[50], *sp = stack; 504 | uint8_t *ptr, *pi, *pj, *plt, *pgt, *top, *m; 505 | size_t m4, i, lt, gt, span, span2; 506 | int c, depth; 507 | exchange_f swap = exchange_func(base, size); 508 | exchange_f swap_block = exchange_func(base, size | 128); 509 | 510 | if (nmemb < 2 || size <= 0) 511 | return; 512 | 513 | sp->base = (uint8_t *)base; 514 | sp->count = nmemb; 515 | sp->depth = 0; 516 | sp++; 517 | 518 | while (sp > stack) { 519 | sp--; 520 | ptr = sp->base; 521 | nmemb = sp->count; 522 | depth = sp->depth; 523 | 524 | while (nmemb > 6) { 525 | if (++depth > 50) { 526 | /* depth check to ensure worst case logarithmic time */ 527 | heapsortx(ptr, nmemb, size, cmp, opaque); 528 | nmemb = 0; 529 | break; 530 | } 531 | /* select median of 3 from 1/4, 1/2, 3/4 positions */ 532 | /* should use median of 5 or 9? */ 533 | m4 = (nmemb >> 2) * size; 534 | m = med3(ptr + m4, ptr + 2 * m4, ptr + 3 * m4, cmp, opaque); 535 | swap(ptr, m, size); /* move the pivot to the start or the array */ 536 | i = lt = 1; 537 | pi = plt = ptr + size; 538 | gt = nmemb; 539 | pj = pgt = top = ptr + nmemb * size; 540 | for (;;) { 541 | while (pi < pj && (c = cmp(ptr, pi, opaque)) >= 0) { 542 | if (c == 0) { 543 | swap(plt, pi, size); 544 | lt++; 545 | plt += size; 546 | } 547 | i++; 548 | pi += size; 549 | } 550 | while (pi < (pj -= size) && (c = cmp(ptr, pj, opaque)) <= 0) { 551 | if (c == 0) { 552 | gt--; 553 | pgt -= size; 554 | swap(pgt, pj, size); 555 | } 556 | } 557 | if (pi >= pj) 558 | break; 559 | swap(pi, pj, size); 560 | i++; 561 | pi += size; 562 | } 563 | /* array has 4 parts: 564 | * from 0 to lt excluded: elements identical to pivot 565 | * from lt to pi excluded: elements smaller than pivot 566 | * from pi to gt excluded: elements greater than pivot 567 | * from gt to n excluded: elements identical to pivot 568 | */ 569 | /* move elements identical to pivot in the middle of the array: */ 570 | /* swap values in ranges [0..lt[ and [i-lt..i[ 571 | swapping the smallest span between lt and i-lt is sufficient 572 | */ 573 | span = plt - ptr; 574 | span2 = pi - plt; 575 | lt = i - lt; 576 | if (span > span2) 577 | span = span2; 578 | swap_block(ptr, pi - span, span); 579 | /* swap values in ranges [gt..top[ and [i..top-(top-gt)[ 580 | swapping the smallest span between top-gt and gt-i is sufficient 581 | */ 582 | span = top - pgt; 583 | span2 = pgt - pi; 584 | pgt = top - span2; 585 | gt = nmemb - (gt - i); 586 | if (span > span2) 587 | span = span2; 588 | swap_block(pi, top - span, span); 589 | 590 | /* now array has 3 parts: 591 | * from 0 to lt excluded: elements smaller than pivot 592 | * from lt to gt excluded: elements identical to pivot 593 | * from gt to n excluded: elements greater than pivot 594 | */ 595 | /* stack the larger segment and keep processing the smaller one 596 | to minimize stack use for pathological distributions */ 597 | if (lt > nmemb - gt) { 598 | sp->base = ptr; 599 | sp->count = lt; 600 | sp->depth = depth; 601 | sp++; 602 | ptr = pgt; 603 | nmemb -= gt; 604 | } else { 605 | sp->base = pgt; 606 | sp->count = nmemb - gt; 607 | sp->depth = depth; 608 | sp++; 609 | nmemb = lt; 610 | } 611 | } 612 | /* Use insertion sort for small fragments */ 613 | for (pi = ptr + size, top = ptr + nmemb * size; pi < top; pi += size) { 614 | for (pj = pi; pj > ptr && cmp(pj - size, pj, opaque) > 0; pj -= size) 615 | swap(pj, pj - size, size); 616 | } 617 | } 618 | } 619 | 620 | #endif 621 | -------------------------------------------------------------------------------- /include/quickjs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS Javascript Engine 3 | * 4 | * Copyright (c) 2017-2020 Fabrice Bellard 5 | * Copyright (c) 2017-2020 Charlie Gordon 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | #ifndef QUICKJS_H 26 | #define QUICKJS_H 27 | 28 | #include 29 | #include 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | #if defined(__GNUC__) || defined(__clang__) 36 | #define js_likely(x) __builtin_expect(!!(x), 1) 37 | #define js_unlikely(x) __builtin_expect(!!(x), 0) 38 | #define js_force_inline inline __attribute__((always_inline)) 39 | #define __js_printf_like(f, a) __attribute__((format(printf, f, a))) 40 | #else 41 | #define js_likely(x) (x) 42 | #define js_unlikely(x) (x) 43 | #define js_force_inline inline 44 | #define __js_printf_like(a, b) 45 | #endif 46 | 47 | #define JS_BOOL int 48 | 49 | typedef struct JSRuntime JSRuntime; 50 | typedef struct JSContext JSContext; 51 | typedef struct JSObject JSObject; 52 | typedef struct JSClass JSClass; 53 | typedef uint32_t JSClassID; 54 | typedef uint32_t JSAtom; 55 | 56 | #if INTPTR_MAX >= INT64_MAX 57 | #define JS_PTR64 58 | #define JS_PTR64_DEF(a) a 59 | #else 60 | #define JS_PTR64_DEF(a) 61 | #endif 62 | 63 | #ifndef JS_PTR64 64 | #define JS_NAN_BOXING 65 | #endif 66 | 67 | enum { 68 | /* all tags with a reference count are negative */ 69 | JS_TAG_FIRST = -11, /* first negative tag */ 70 | JS_TAG_BIG_DECIMAL = -11, 71 | JS_TAG_BIG_INT = -10, 72 | JS_TAG_BIG_FLOAT = -9, 73 | JS_TAG_SYMBOL = -8, 74 | JS_TAG_STRING = -7, 75 | JS_TAG_MODULE = -3, /* used internally */ 76 | JS_TAG_FUNCTION_BYTECODE = -2, /* used internally */ 77 | JS_TAG_OBJECT = -1, 78 | 79 | JS_TAG_INT = 0, 80 | JS_TAG_BOOL = 1, 81 | JS_TAG_NULL = 2, 82 | JS_TAG_UNDEFINED = 3, 83 | JS_TAG_UNINITIALIZED = 4, 84 | JS_TAG_CATCH_OFFSET = 5, 85 | JS_TAG_EXCEPTION = 6, 86 | JS_TAG_FLOAT64 = 7, 87 | /* any larger tag is FLOAT64 if JS_NAN_BOXING */ 88 | }; 89 | 90 | typedef struct JSRefCountHeader { 91 | int ref_count; 92 | } JSRefCountHeader; 93 | 94 | #define JS_FLOAT64_NAN NAN 95 | 96 | #ifdef CONFIG_CHECK_JSVALUE 97 | /* JSValue consistency : it is not possible to run the code in this 98 | mode, but it is useful to detect simple reference counting 99 | errors. It would be interesting to modify a static C analyzer to 100 | handle specific annotations (clang has such annotations but only 101 | for objective C) */ 102 | typedef struct __JSValue *JSValue; 103 | typedef const struct __JSValue *JSValueConst; 104 | 105 | #define JS_VALUE_GET_TAG(v) (int)((uintptr_t)(v) & 0xf) 106 | /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ 107 | #define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v) 108 | #define JS_VALUE_GET_INT(v) (int)((intptr_t)(v) >> 4) 109 | #define JS_VALUE_GET_BOOL(v) JS_VALUE_GET_INT(v) 110 | #define JS_VALUE_GET_FLOAT64(v) (double)JS_VALUE_GET_INT(v) 111 | #define JS_VALUE_GET_PTR(v) (void *)((intptr_t)(v) & ~0xf) 112 | 113 | #define JS_MKVAL(tag, val) (JSValue)(intptr_t)(((val) << 4) | (tag)) 114 | #define JS_MKPTR(tag, p) (JSValue)((intptr_t)(p) | (tag)) 115 | 116 | #define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64) 117 | 118 | #define JS_NAN JS_MKVAL(JS_TAG_FLOAT64, 1) 119 | 120 | static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) 121 | { 122 | return JS_MKVAL(JS_TAG_FLOAT64, (int)d); 123 | } 124 | 125 | static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) 126 | { 127 | return 0; 128 | } 129 | 130 | #elif defined(JS_NAN_BOXING) 131 | 132 | typedef uint64_t JSValue; 133 | 134 | #define JSValueConst JSValue 135 | 136 | #define JS_VALUE_GET_TAG(v) (int)((v) >> 32) 137 | #define JS_VALUE_GET_INT(v) (int)(v) 138 | #define JS_VALUE_GET_BOOL(v) (int)(v) 139 | #define JS_VALUE_GET_PTR(v) (void *)(intptr_t)(v) 140 | 141 | #define JS_MKVAL(tag, val) (((uint64_t)(tag) << 32) | (uint32_t)(val)) 142 | #define JS_MKPTR(tag, ptr) (((uint64_t)(tag) << 32) | (uintptr_t)(ptr)) 143 | 144 | #define JS_FLOAT64_TAG_ADDEND (0x7ff80000 - JS_TAG_FIRST + 1) /* quiet NaN encoding */ 145 | 146 | static inline double JS_VALUE_GET_FLOAT64(JSValue v) 147 | { 148 | union { 149 | JSValue v; 150 | double d; 151 | } u; 152 | u.v = v; 153 | u.v += (uint64_t)JS_FLOAT64_TAG_ADDEND << 32; 154 | return u.d; 155 | } 156 | 157 | #define JS_NAN (0x7ff8000000000000 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32)) 158 | 159 | static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) 160 | { 161 | union { 162 | double d; 163 | uint64_t u64; 164 | } u; 165 | JSValue v; 166 | u.d = d; 167 | /* normalize NaN */ 168 | if (js_unlikely((u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000)) 169 | v = JS_NAN; 170 | else 171 | v = u.u64 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32); 172 | return v; 173 | } 174 | 175 | #define JS_TAG_IS_FLOAT64(tag) ((unsigned)((tag) - JS_TAG_FIRST) >= (JS_TAG_FLOAT64 - JS_TAG_FIRST)) 176 | 177 | /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ 178 | static inline int JS_VALUE_GET_NORM_TAG(JSValue v) 179 | { 180 | uint32_t tag; 181 | tag = JS_VALUE_GET_TAG(v); 182 | if (JS_TAG_IS_FLOAT64(tag)) 183 | return JS_TAG_FLOAT64; 184 | else 185 | return tag; 186 | } 187 | 188 | static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) 189 | { 190 | uint32_t tag; 191 | tag = JS_VALUE_GET_TAG(v); 192 | return tag == (JS_NAN >> 32); 193 | } 194 | 195 | #else /* !JS_NAN_BOXING */ 196 | 197 | typedef union JSValueUnion { 198 | int32_t int32; 199 | double float64; 200 | void *ptr; 201 | } JSValueUnion; 202 | 203 | typedef struct JSValue { 204 | JSValueUnion u; 205 | int64_t tag; 206 | } JSValue; 207 | 208 | #define JSValueConst JSValue 209 | 210 | #define JS_VALUE_GET_TAG(v) ((int32_t)(v).tag) 211 | /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ 212 | #define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v) 213 | #define JS_VALUE_GET_INT(v) ((v).u.int32) 214 | #define JS_VALUE_GET_BOOL(v) ((v).u.int32) 215 | #define JS_VALUE_GET_FLOAT64(v) ((v).u.float64) 216 | #define JS_VALUE_GET_PTR(v) ((v).u.ptr) 217 | 218 | #define JS_MKVAL(tag, val) (JSValue){ (JSValueUnion){ .int32 = val }, tag } 219 | #define JS_MKPTR(tag, p) (JSValue){ (JSValueUnion){ .ptr = p }, tag } 220 | 221 | #define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64) 222 | 223 | #define JS_NAN (JSValue){ .u.float64 = JS_FLOAT64_NAN, JS_TAG_FLOAT64 } 224 | 225 | static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) 226 | { 227 | JSValue v; 228 | v.tag = JS_TAG_FLOAT64; 229 | v.u.float64 = d; 230 | return v; 231 | } 232 | 233 | static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) 234 | { 235 | union { 236 | double d; 237 | uint64_t u64; 238 | } u; 239 | if (v.tag != JS_TAG_FLOAT64) 240 | return 0; 241 | u.d = v.u.float64; 242 | return (u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000; 243 | } 244 | 245 | #endif /* !JS_NAN_BOXING */ 246 | 247 | #define JS_VALUE_IS_BOTH_INT(v1, v2) ((JS_VALUE_GET_TAG(v1) | JS_VALUE_GET_TAG(v2)) == 0) 248 | #define JS_VALUE_IS_BOTH_FLOAT(v1, v2) (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v1)) && JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v2))) 249 | 250 | #define JS_VALUE_GET_OBJ(v) ((JSObject *)JS_VALUE_GET_PTR(v)) 251 | #define JS_VALUE_GET_STRING(v) ((JSString *)JS_VALUE_GET_PTR(v)) 252 | #define JS_VALUE_HAS_REF_COUNT(v) ((unsigned)JS_VALUE_GET_TAG(v) >= (unsigned)JS_TAG_FIRST) 253 | 254 | /* special values */ 255 | #define JS_NULL JS_MKVAL(JS_TAG_NULL, 0) 256 | #define JS_UNDEFINED JS_MKVAL(JS_TAG_UNDEFINED, 0) 257 | #define JS_FALSE JS_MKVAL(JS_TAG_BOOL, 0) 258 | #define JS_TRUE JS_MKVAL(JS_TAG_BOOL, 1) 259 | #define JS_EXCEPTION JS_MKVAL(JS_TAG_EXCEPTION, 0) 260 | #define JS_UNINITIALIZED JS_MKVAL(JS_TAG_UNINITIALIZED, 0) 261 | 262 | /* flags for object properties */ 263 | #define JS_PROP_CONFIGURABLE (1 << 0) 264 | #define JS_PROP_WRITABLE (1 << 1) 265 | #define JS_PROP_ENUMERABLE (1 << 2) 266 | #define JS_PROP_C_W_E (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE | JS_PROP_ENUMERABLE) 267 | #define JS_PROP_LENGTH (1 << 3) /* used internally in Arrays */ 268 | #define JS_PROP_TMASK (3 << 4) /* mask for NORMAL, GETSET, VARREF, AUTOINIT */ 269 | #define JS_PROP_NORMAL (0 << 4) 270 | #define JS_PROP_GETSET (1 << 4) 271 | #define JS_PROP_VARREF (2 << 4) /* used internally */ 272 | #define JS_PROP_AUTOINIT (3 << 4) /* used internally */ 273 | 274 | /* flags for JS_DefineProperty */ 275 | #define JS_PROP_HAS_SHIFT 8 276 | #define JS_PROP_HAS_CONFIGURABLE (1 << 8) 277 | #define JS_PROP_HAS_WRITABLE (1 << 9) 278 | #define JS_PROP_HAS_ENUMERABLE (1 << 10) 279 | #define JS_PROP_HAS_GET (1 << 11) 280 | #define JS_PROP_HAS_SET (1 << 12) 281 | #define JS_PROP_HAS_VALUE (1 << 13) 282 | 283 | /* throw an exception if false would be returned 284 | (JS_DefineProperty/JS_SetProperty) */ 285 | #define JS_PROP_THROW (1 << 14) 286 | /* throw an exception if false would be returned in strict mode 287 | (JS_SetProperty) */ 288 | #define JS_PROP_THROW_STRICT (1 << 15) 289 | 290 | #define JS_PROP_NO_ADD (1 << 16) /* internal use */ 291 | #define JS_PROP_NO_EXOTIC (1 << 17) /* internal use */ 292 | 293 | #define JS_DEFAULT_STACK_SIZE (256 * 1024) 294 | 295 | /* JS_Eval() flags */ 296 | #define JS_EVAL_TYPE_GLOBAL (0 << 0) /* global code (default) */ 297 | #define JS_EVAL_TYPE_MODULE (1 << 0) /* module code */ 298 | #define JS_EVAL_TYPE_DIRECT (2 << 0) /* direct call (internal use) */ 299 | #define JS_EVAL_TYPE_INDIRECT (3 << 0) /* indirect call (internal use) */ 300 | #define JS_EVAL_TYPE_MASK (3 << 0) 301 | 302 | #define JS_EVAL_FLAG_STRICT (1 << 3) /* force 'strict' mode */ 303 | #define JS_EVAL_FLAG_STRIP (1 << 4) /* force 'strip' mode */ 304 | /* compile but do not run. The result is an object with a 305 | JS_TAG_FUNCTION_BYTECODE or JS_TAG_MODULE tag. It can be executed 306 | with JS_EvalFunction(). */ 307 | #define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5) 308 | /* don't include the stack frames before this eval in the Error() backtraces */ 309 | #define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6) 310 | 311 | typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); 312 | typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); 313 | typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data); 314 | 315 | typedef struct JSMallocState { 316 | size_t malloc_count; 317 | size_t malloc_size; 318 | size_t malloc_limit; 319 | void *opaque; /* user opaque */ 320 | } JSMallocState; 321 | 322 | typedef struct JSMallocFunctions { 323 | void *(*js_malloc)(JSMallocState *s, size_t size); 324 | void (*js_free)(JSMallocState *s, void *ptr); 325 | void *(*js_realloc)(JSMallocState *s, void *ptr, size_t size); 326 | size_t (*js_malloc_usable_size)(const void *ptr); 327 | } JSMallocFunctions; 328 | 329 | typedef struct JSGCObjectHeader JSGCObjectHeader; 330 | 331 | JSRuntime *JS_NewRuntime(void); 332 | /* info lifetime must exceed that of rt */ 333 | void JS_SetRuntimeInfo(JSRuntime *rt, const char *info); 334 | void JS_SetMemoryLimit(JSRuntime *rt, size_t limit); 335 | void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold); 336 | JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque); 337 | void JS_FreeRuntime(JSRuntime *rt); 338 | typedef void JS_MarkFunc(JSRuntime *rt, JSGCObjectHeader *gp); 339 | void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); 340 | void JS_RunGC(JSRuntime *rt); 341 | JS_BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj); 342 | 343 | JSContext *JS_NewContext(JSRuntime *rt); 344 | void JS_FreeContext(JSContext *s); 345 | void *JS_GetContextOpaque(JSContext *ctx); 346 | void JS_SetContextOpaque(JSContext *ctx, void *opaque); 347 | JSRuntime *JS_GetRuntime(JSContext *ctx); 348 | void JS_SetMaxStackSize(JSContext *ctx, size_t stack_size); 349 | void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj); 350 | JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id); 351 | 352 | /* the following functions are used to select the intrinsic object to 353 | save memory */ 354 | JSContext *JS_NewContextRaw(JSRuntime *rt); 355 | void JS_AddIntrinsicBaseObjects(JSContext *ctx); 356 | void JS_AddIntrinsicDate(JSContext *ctx); 357 | void JS_AddIntrinsicEval(JSContext *ctx); 358 | void JS_AddIntrinsicStringNormalize(JSContext *ctx); 359 | void JS_AddIntrinsicRegExpCompiler(JSContext *ctx); 360 | void JS_AddIntrinsicRegExp(JSContext *ctx); 361 | void JS_AddIntrinsicJSON(JSContext *ctx); 362 | void JS_AddIntrinsicProxy(JSContext *ctx); 363 | void JS_AddIntrinsicMapSet(JSContext *ctx); 364 | void JS_AddIntrinsicTypedArrays(JSContext *ctx); 365 | void JS_AddIntrinsicPromise(JSContext *ctx); 366 | void JS_AddIntrinsicBigInt(JSContext *ctx); 367 | void JS_AddIntrinsicBigFloat(JSContext *ctx); 368 | void JS_AddIntrinsicBigDecimal(JSContext *ctx); 369 | /* enable operator overloading */ 370 | void JS_AddIntrinsicOperators(JSContext *ctx); 371 | /* enable "use math" */ 372 | void JS_EnableBignumExt(JSContext *ctx, JS_BOOL enable); 373 | 374 | JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val, 375 | int argc, JSValueConst *argv); 376 | 377 | void *js_malloc_rt(JSRuntime *rt, size_t size); 378 | void js_free_rt(JSRuntime *rt, void *ptr); 379 | void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size); 380 | size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr); 381 | void *js_mallocz_rt(JSRuntime *rt, size_t size); 382 | 383 | void *js_malloc(JSContext *ctx, size_t size); 384 | void js_free(JSContext *ctx, void *ptr); 385 | void *js_realloc(JSContext *ctx, void *ptr, size_t size); 386 | size_t js_malloc_usable_size(JSContext *ctx, const void *ptr); 387 | void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack); 388 | void *js_mallocz(JSContext *ctx, size_t size); 389 | char *js_strdup(JSContext *ctx, const char *str); 390 | char *js_strndup(JSContext *ctx, const char *s, size_t n); 391 | 392 | typedef struct JSMemoryUsage { 393 | int64_t malloc_size, malloc_limit, memory_used_size; 394 | int64_t malloc_count; 395 | int64_t memory_used_count; 396 | int64_t atom_count, atom_size; 397 | int64_t str_count, str_size; 398 | int64_t obj_count, obj_size; 399 | int64_t prop_count, prop_size; 400 | int64_t shape_count, shape_size; 401 | int64_t js_func_count, js_func_size, js_func_code_size; 402 | int64_t js_func_pc2line_count, js_func_pc2line_size; 403 | int64_t c_func_count, array_count; 404 | int64_t fast_array_count, fast_array_elements; 405 | int64_t binary_object_count, binary_object_size; 406 | } JSMemoryUsage; 407 | 408 | void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s); 409 | void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt); 410 | 411 | /* atom support */ 412 | JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len); 413 | JSAtom JS_NewAtom(JSContext *ctx, const char *str); 414 | JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n); 415 | JSAtom JS_DupAtom(JSContext *ctx, JSAtom v); 416 | void JS_FreeAtom(JSContext *ctx, JSAtom v); 417 | void JS_FreeAtomRT(JSRuntime *rt, JSAtom v); 418 | JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom); 419 | JSValue JS_AtomToString(JSContext *ctx, JSAtom atom); 420 | const char *JS_AtomToCString(JSContext *ctx, JSAtom atom); 421 | JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val); 422 | 423 | /* object class support */ 424 | 425 | typedef struct JSPropertyEnum { 426 | JS_BOOL is_enumerable; 427 | JSAtom atom; 428 | } JSPropertyEnum; 429 | 430 | typedef struct JSPropertyDescriptor { 431 | int flags; 432 | JSValue value; 433 | JSValue getter; 434 | JSValue setter; 435 | } JSPropertyDescriptor; 436 | 437 | typedef struct JSClassExoticMethods { 438 | /* Return -1 if exception (can only happen in case of Proxy object), 439 | FALSE if the property does not exists, TRUE if it exists. If 1 is 440 | returned, the property descriptor 'desc' is filled if != NULL. */ 441 | int (*get_own_property)(JSContext *ctx, JSPropertyDescriptor *desc, 442 | JSValueConst obj, JSAtom prop); 443 | /* '*ptab' should hold the '*plen' property keys. Return 0 if OK, 444 | -1 if exception. The 'is_enumerable' field is ignored. 445 | */ 446 | int (*get_own_property_names)(JSContext *ctx, JSPropertyEnum **ptab, 447 | uint32_t *plen, 448 | JSValueConst obj); 449 | /* return < 0 if exception, or TRUE/FALSE */ 450 | int (*delete_property)(JSContext *ctx, JSValueConst obj, JSAtom prop); 451 | /* return < 0 if exception or TRUE/FALSE */ 452 | int (*define_own_property)(JSContext *ctx, JSValueConst this_obj, 453 | JSAtom prop, JSValueConst val, 454 | JSValueConst getter, JSValueConst setter, 455 | int flags); 456 | /* The following methods can be emulated with the previous ones, 457 | so they are usually not needed */ 458 | /* return < 0 if exception or TRUE/FALSE */ 459 | int (*has_property)(JSContext *ctx, JSValueConst obj, JSAtom atom); 460 | JSValue (*get_property)(JSContext *ctx, JSValueConst obj, JSAtom atom, 461 | JSValueConst receiver); 462 | /* return < 0 if exception or TRUE/FALSE */ 463 | int (*set_property)(JSContext *ctx, JSValueConst obj, JSAtom atom, 464 | JSValueConst value, JSValueConst receiver, int flags); 465 | } JSClassExoticMethods; 466 | 467 | typedef void JSClassFinalizer(JSRuntime *rt, JSValue val); 468 | typedef void JSClassGCMark(JSRuntime *rt, JSValueConst val, 469 | JS_MarkFunc *mark_func); 470 | #define JS_CALL_FLAG_CONSTRUCTOR (1 << 0) 471 | typedef JSValue JSClassCall(JSContext *ctx, JSValueConst func_obj, 472 | JSValueConst this_val, int argc, JSValueConst *argv, 473 | int flags); 474 | 475 | typedef struct JSClassDef { 476 | const char *class_name; 477 | JSClassFinalizer *finalizer; 478 | JSClassGCMark *gc_mark; 479 | /* if call != NULL, the object is a function. If (flags & 480 | JS_CALL_FLAG_CONSTRUCTOR) != 0, the function is called as a 481 | constructor. In this case, 'this_val' is new.target. A 482 | constructor call only happens if the object constructor bit is 483 | set (see JS_SetConstructorBit()). */ 484 | JSClassCall *call; 485 | /* XXX: suppress this indirection ? It is here only to save memory 486 | because only a few classes need these methods */ 487 | JSClassExoticMethods *exotic; 488 | } JSClassDef; 489 | 490 | JSClassID JS_NewClassID(JSClassID *pclass_id); 491 | int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def); 492 | int JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id); 493 | 494 | /* value handling */ 495 | 496 | static js_force_inline JSValue JS_NewBool(JSContext *ctx, JS_BOOL val) 497 | { 498 | return JS_MKVAL(JS_TAG_BOOL, val); 499 | } 500 | 501 | static js_force_inline JSValue JS_NewInt32(JSContext *ctx, int32_t val) 502 | { 503 | return JS_MKVAL(JS_TAG_INT, val); 504 | } 505 | 506 | static js_force_inline JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val) 507 | { 508 | return JS_MKVAL(JS_TAG_CATCH_OFFSET, val); 509 | } 510 | 511 | JSValue JS_NewInt64(JSContext *ctx, int64_t v); 512 | JSValue JS_NewBigInt64(JSContext *ctx, int64_t v); 513 | JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v); 514 | 515 | static js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double d) 516 | { 517 | JSValue v; 518 | int32_t val; 519 | union { 520 | double d; 521 | uint64_t u; 522 | } u, t; 523 | u.d = d; 524 | val = (int32_t)d; 525 | t.d = val; 526 | /* -0 cannot be represented as integer, so we compare the bit 527 | representation */ 528 | if (u.u == t.u) { 529 | v = JS_MKVAL(JS_TAG_INT, val); 530 | } else { 531 | v = __JS_NewFloat64(ctx, d); 532 | } 533 | return v; 534 | } 535 | 536 | static inline JS_BOOL JS_IsNumber(JSValueConst v) 537 | { 538 | int tag = JS_VALUE_GET_TAG(v); 539 | return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag); 540 | } 541 | 542 | static inline JS_BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v) 543 | { 544 | int tag = JS_VALUE_GET_TAG(v); 545 | return tag == JS_TAG_BIG_INT; 546 | } 547 | 548 | static inline JS_BOOL JS_IsBigFloat(JSValueConst v) 549 | { 550 | int tag = JS_VALUE_GET_TAG(v); 551 | return tag == JS_TAG_BIG_FLOAT; 552 | } 553 | 554 | static inline JS_BOOL JS_IsBigDecimal(JSValueConst v) 555 | { 556 | int tag = JS_VALUE_GET_TAG(v); 557 | return tag == JS_TAG_BIG_DECIMAL; 558 | } 559 | 560 | static inline JS_BOOL JS_IsBool(JSValueConst v) 561 | { 562 | return JS_VALUE_GET_TAG(v) == JS_TAG_BOOL; 563 | } 564 | 565 | static inline JS_BOOL JS_IsNull(JSValueConst v) 566 | { 567 | return JS_VALUE_GET_TAG(v) == JS_TAG_NULL; 568 | } 569 | 570 | static inline JS_BOOL JS_IsUndefined(JSValueConst v) 571 | { 572 | return JS_VALUE_GET_TAG(v) == JS_TAG_UNDEFINED; 573 | } 574 | 575 | static inline JS_BOOL JS_IsException(JSValueConst v) 576 | { 577 | return js_unlikely(JS_VALUE_GET_TAG(v) == JS_TAG_EXCEPTION); 578 | } 579 | 580 | static inline JS_BOOL JS_IsUninitialized(JSValueConst v) 581 | { 582 | return js_unlikely(JS_VALUE_GET_TAG(v) == JS_TAG_UNINITIALIZED); 583 | } 584 | 585 | static inline JS_BOOL JS_IsString(JSValueConst v) 586 | { 587 | return JS_VALUE_GET_TAG(v) == JS_TAG_STRING; 588 | } 589 | 590 | static inline JS_BOOL JS_IsSymbol(JSValueConst v) 591 | { 592 | return JS_VALUE_GET_TAG(v) == JS_TAG_SYMBOL; 593 | } 594 | 595 | static inline JS_BOOL JS_IsObject(JSValueConst v) 596 | { 597 | return JS_VALUE_GET_TAG(v) == JS_TAG_OBJECT; 598 | } 599 | 600 | JSValue JS_Throw(JSContext *ctx, JSValue obj); 601 | JSValue JS_GetException(JSContext *ctx); 602 | JS_BOOL JS_IsError(JSContext *ctx, JSValueConst val); 603 | void JS_ResetUncatchableError(JSContext *ctx); 604 | JSValue JS_NewError(JSContext *ctx); 605 | JSValue __js_printf_like(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...); 606 | JSValue __js_printf_like(2, 3) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...); 607 | JSValue __js_printf_like(2, 3) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...); 608 | JSValue __js_printf_like(2, 3) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...); 609 | JSValue __js_printf_like(2, 3) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...); 610 | JSValue JS_ThrowOutOfMemory(JSContext *ctx); 611 | 612 | void __JS_FreeValue(JSContext *ctx, JSValue v); 613 | static inline void JS_FreeValue(JSContext *ctx, JSValue v) 614 | { 615 | if (JS_VALUE_HAS_REF_COUNT(v)) { 616 | JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); 617 | if (--p->ref_count <= 0) { 618 | __JS_FreeValue(ctx, v); 619 | } 620 | } 621 | } 622 | void __JS_FreeValueRT(JSRuntime *rt, JSValue v); 623 | static inline void JS_FreeValueRT(JSRuntime *rt, JSValue v) 624 | { 625 | if (JS_VALUE_HAS_REF_COUNT(v)) { 626 | JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); 627 | if (--p->ref_count <= 0) { 628 | __JS_FreeValueRT(rt, v); 629 | } 630 | } 631 | } 632 | 633 | static inline JSValue JS_DupValue(JSContext *ctx, JSValueConst v) 634 | { 635 | if (JS_VALUE_HAS_REF_COUNT(v)) { 636 | JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); 637 | p->ref_count++; 638 | } 639 | return (JSValue)v; 640 | } 641 | 642 | static inline JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v) 643 | { 644 | if (JS_VALUE_HAS_REF_COUNT(v)) { 645 | JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); 646 | p->ref_count++; 647 | } 648 | return (JSValue)v; 649 | } 650 | 651 | int JS_ToBool(JSContext *ctx, JSValueConst val); /* return -1 for JS_EXCEPTION */ 652 | int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val); 653 | static int inline JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val) 654 | { 655 | return JS_ToInt32(ctx, (int32_t*)pres, val); 656 | } 657 | int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val); 658 | int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val); 659 | int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val); 660 | int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val); 661 | 662 | JSValue JS_NewStringLen(JSContext *ctx, const char *str1, size_t len1); 663 | JSValue JS_NewString(JSContext *ctx, const char *str); 664 | JSValue JS_NewAtomString(JSContext *ctx, const char *str); 665 | JSValue JS_ToString(JSContext *ctx, JSValueConst val); 666 | JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val); 667 | const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, JS_BOOL cesu8); 668 | static inline const char *JS_ToCStringLen(JSContext *ctx, size_t *plen, JSValueConst val1) 669 | { 670 | return JS_ToCStringLen2(ctx, plen, val1, 0); 671 | } 672 | static inline const char *JS_ToCString(JSContext *ctx, JSValueConst val1) 673 | { 674 | return JS_ToCStringLen2(ctx, NULL, val1, 0); 675 | } 676 | void JS_FreeCString(JSContext *ctx, const char *ptr); 677 | 678 | JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto, JSClassID class_id); 679 | JSValue JS_NewObjectClass(JSContext *ctx, int class_id); 680 | JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto); 681 | JSValue JS_NewObject(JSContext *ctx); 682 | 683 | JS_BOOL JS_IsFunction(JSContext* ctx, JSValueConst val); 684 | JS_BOOL JS_IsConstructor(JSContext* ctx, JSValueConst val); 685 | JS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, JS_BOOL val); 686 | 687 | JSValue JS_NewArray(JSContext *ctx); 688 | int JS_IsArray(JSContext *ctx, JSValueConst val); 689 | 690 | JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, 691 | JSAtom prop, JSValueConst receiver, 692 | JS_BOOL throw_ref_error); 693 | static js_force_inline JSValue JS_GetProperty(JSContext *ctx, JSValueConst this_obj, 694 | JSAtom prop) 695 | { 696 | return JS_GetPropertyInternal(ctx, this_obj, prop, this_obj, 0); 697 | } 698 | JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj, 699 | const char *prop); 700 | JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj, 701 | uint32_t idx); 702 | 703 | int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, 704 | JSAtom prop, JSValue val, 705 | int flags); 706 | static inline int JS_SetProperty(JSContext *ctx, JSValueConst this_obj, 707 | JSAtom prop, JSValue val) 708 | { 709 | return JS_SetPropertyInternal(ctx, this_obj, prop, val, JS_PROP_THROW); 710 | } 711 | int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj, 712 | uint32_t idx, JSValue val); 713 | int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj, 714 | int64_t idx, JSValue val); 715 | int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj, 716 | const char *prop, JSValue val); 717 | int JS_HasProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop); 718 | int JS_IsExtensible(JSContext *ctx, JSValueConst obj); 719 | int JS_PreventExtensions(JSContext *ctx, JSValueConst obj); 720 | int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags); 721 | int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val); 722 | JSValueConst JS_GetPrototype(JSContext *ctx, JSValueConst val); 723 | 724 | #define JS_GPN_STRING_MASK (1 << 0) 725 | #define JS_GPN_SYMBOL_MASK (1 << 1) 726 | #define JS_GPN_PRIVATE_MASK (1 << 2) 727 | /* only include the enumerable properties */ 728 | #define JS_GPN_ENUM_ONLY (1 << 4) 729 | /* set theJSPropertyEnum.is_enumerable field */ 730 | #define JS_GPN_SET_ENUM (1 << 5) 731 | 732 | int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, 733 | uint32_t *plen, JSValueConst obj, int flags); 734 | int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc, 735 | JSValueConst obj, JSAtom prop); 736 | 737 | JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, 738 | int argc, JSValueConst *argv); 739 | JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom, 740 | int argc, JSValueConst *argv); 741 | JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj, 742 | int argc, JSValueConst *argv); 743 | JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj, 744 | JSValueConst new_target, 745 | int argc, JSValueConst *argv); 746 | JS_BOOL JS_DetectModule(const char *input, size_t input_len); 747 | /* 'input' must be zero terminated i.e. input[input_len] = '\0'. */ 748 | JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len, 749 | const char *filename, int eval_flags); 750 | JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj); 751 | JSValue JS_GetGlobalObject(JSContext *ctx); 752 | int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj); 753 | int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, 754 | JSAtom prop, JSValueConst val, 755 | JSValueConst getter, JSValueConst setter, int flags); 756 | int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj, 757 | JSAtom prop, JSValue val, int flags); 758 | int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj, 759 | uint32_t idx, JSValue val, int flags); 760 | int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj, 761 | const char *prop, JSValue val, int flags); 762 | int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj, 763 | JSAtom prop, JSValue getter, JSValue setter, 764 | int flags); 765 | void JS_SetOpaque(JSValue obj, void *opaque); 766 | void *JS_GetOpaque(JSValueConst obj, JSClassID class_id); 767 | void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id); 768 | 769 | /* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */ 770 | JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, 771 | const char *filename); 772 | JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj, 773 | JSValueConst replacer, JSValueConst space0); 774 | 775 | typedef void JSFreeArrayBufferDataFunc(JSRuntime *rt, void *opaque, void *ptr); 776 | JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len, 777 | JSFreeArrayBufferDataFunc *free_func, void *opaque, 778 | JS_BOOL is_shared); 779 | JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len); 780 | void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj); 781 | uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj); 782 | JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj, 783 | size_t *pbyte_offset, 784 | size_t *pbyte_length, 785 | size_t *pbytes_per_element); 786 | 787 | JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs); 788 | 789 | /* is_handled = TRUE means that the rejection is handled */ 790 | typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValueConst promise, 791 | JSValueConst reason, 792 | JS_BOOL is_handled, void *opaque); 793 | void JS_SetHostPromiseRejectionTracker(JSRuntime *rt, JSHostPromiseRejectionTracker *cb, void *opaque); 794 | 795 | /* return != 0 if the JS code needs to be interrupted */ 796 | typedef int JSInterruptHandler(JSRuntime *rt, void *opaque); 797 | void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque); 798 | /* if can_block is TRUE, Atomics.wait() can be used */ 799 | void JS_SetCanBlock(JSRuntime *rt, JS_BOOL can_block); 800 | 801 | typedef struct JSModuleDef JSModuleDef; 802 | 803 | /* return the module specifier (allocated with js_malloc()) or NULL if 804 | exception */ 805 | typedef char *JSModuleNormalizeFunc(JSContext *ctx, 806 | const char *module_base_name, 807 | const char *module_name, void *opaque); 808 | typedef JSModuleDef *JSModuleLoaderFunc(JSContext *ctx, 809 | const char *module_name, void *opaque); 810 | 811 | /* module_normalize = NULL is allowed and invokes the default module 812 | filename normalizer */ 813 | void JS_SetModuleLoaderFunc(JSRuntime *rt, 814 | JSModuleNormalizeFunc *module_normalize, 815 | JSModuleLoaderFunc *module_loader, void *opaque); 816 | /* return the import.meta object of a module */ 817 | JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m); 818 | JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m); 819 | 820 | /* JS Job support */ 821 | 822 | typedef JSValue JSJobFunc(JSContext *ctx, int argc, JSValueConst *argv); 823 | int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, int argc, JSValueConst *argv); 824 | 825 | JS_BOOL JS_IsJobPending(JSRuntime *rt); 826 | int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx); 827 | 828 | /* Object Writer/Reader (currently only used to handle precompiled code) */ 829 | #define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */ 830 | #define JS_WRITE_OBJ_BSWAP (1 << 1) /* byte swapped output */ 831 | uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj, 832 | int flags); 833 | #define JS_READ_OBJ_BYTECODE (1 << 0) /* allow function/module */ 834 | #define JS_READ_OBJ_ROM_DATA (1 << 1) /* avoid duplicating 'buf' data */ 835 | JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, 836 | int flags); 837 | /* load the dependencies of the module 'obj'. Useful when JS_ReadObject() 838 | returns a module. */ 839 | int JS_ResolveModule(JSContext *ctx, JSValueConst obj); 840 | 841 | /* C function definition */ 842 | typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */ 843 | JS_CFUNC_generic, 844 | JS_CFUNC_generic_magic, 845 | JS_CFUNC_constructor, 846 | JS_CFUNC_constructor_magic, 847 | JS_CFUNC_constructor_or_func, 848 | JS_CFUNC_constructor_or_func_magic, 849 | JS_CFUNC_f_f, 850 | JS_CFUNC_f_f_f, 851 | JS_CFUNC_getter, 852 | JS_CFUNC_setter, 853 | JS_CFUNC_getter_magic, 854 | JS_CFUNC_setter_magic, 855 | JS_CFUNC_iterator_next, 856 | } JSCFunctionEnum; 857 | 858 | typedef union JSCFunctionType { 859 | JSCFunction *generic; 860 | JSValue (*generic_magic)(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); 861 | JSCFunction *constructor; 862 | JSValue (*constructor_magic)(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv, int magic); 863 | JSCFunction *constructor_or_func; 864 | double (*f_f)(double); 865 | double (*f_f_f)(double, double); 866 | JSValue (*getter)(JSContext *ctx, JSValueConst this_val); 867 | JSValue (*setter)(JSContext *ctx, JSValueConst this_val, JSValueConst val); 868 | JSValue (*getter_magic)(JSContext *ctx, JSValueConst this_val, int magic); 869 | JSValue (*setter_magic)(JSContext *ctx, JSValueConst this_val, JSValueConst val, int magic); 870 | JSValue (*iterator_next)(JSContext *ctx, JSValueConst this_val, 871 | int argc, JSValueConst *argv, int *pdone, int magic); 872 | } JSCFunctionType; 873 | 874 | JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func, 875 | const char *name, 876 | int length, JSCFunctionEnum cproto, int magic); 877 | JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func, 878 | int length, int magic, int data_len, 879 | JSValueConst *data); 880 | 881 | static inline JSValue JS_NewCFunction(JSContext *ctx, JSCFunction *func, const char *name, 882 | int length) 883 | { 884 | return JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_generic, 0); 885 | } 886 | 887 | static inline JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *func, 888 | const char *name, 889 | int length, JSCFunctionEnum cproto, int magic) 890 | { 891 | return JS_NewCFunction2(ctx, (JSCFunction *)func, name, length, cproto, magic); 892 | } 893 | void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, 894 | JSValueConst proto); 895 | 896 | /* C property definition */ 897 | 898 | typedef struct JSCFunctionListEntry { 899 | const char *name; 900 | uint8_t prop_flags; 901 | uint8_t def_type; 902 | int16_t magic; 903 | union { 904 | struct { 905 | uint8_t length; /* XXX: should move outside union */ 906 | uint8_t cproto; /* XXX: should move outside union */ 907 | JSCFunctionType cfunc; 908 | } func; 909 | struct { 910 | JSCFunctionType get; 911 | JSCFunctionType set; 912 | } getset; 913 | struct { 914 | const char *name; 915 | int base; 916 | } alias; 917 | struct { 918 | const struct JSCFunctionListEntry *tab; 919 | int len; 920 | } prop_list; 921 | const char *str; 922 | int32_t i32; 923 | int64_t i64; 924 | double f64; 925 | } u; 926 | } JSCFunctionListEntry; 927 | 928 | #define JS_DEF_CFUNC 0 929 | #define JS_DEF_CGETSET 1 930 | #define JS_DEF_CGETSET_MAGIC 2 931 | #define JS_DEF_PROP_STRING 3 932 | #define JS_DEF_PROP_INT32 4 933 | #define JS_DEF_PROP_INT64 5 934 | #define JS_DEF_PROP_DOUBLE 6 935 | #define JS_DEF_PROP_UNDEFINED 7 936 | #define JS_DEF_OBJECT 8 937 | #define JS_DEF_ALIAS 9 938 | 939 | /* Note: c++ does not like nested designators */ 940 | #define JS_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } } 941 | #define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } } } 942 | #define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_ ## cproto, { .cproto = func1 } } } } 943 | #define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } } } 944 | #define JS_CGETSET_DEF(name, fgetter, fsetter) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET, 0, .u = { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } } 945 | #define JS_CGETSET_MAGIC_DEF(name, fgetter, fsetter, magic) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET_MAGIC, magic, .u = { .getset = { .get = { .getter_magic = fgetter }, .set = { .setter_magic = fsetter } } } } 946 | #define JS_PROP_STRING_DEF(name, cstr, prop_flags) { name, prop_flags, JS_DEF_PROP_STRING, 0, .u = { .str = cstr } } 947 | #define JS_PROP_INT32_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT32, 0, .u = { .i32 = val } } 948 | #define JS_PROP_INT64_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT64, 0, .u = { .i64 = val } } 949 | #define JS_PROP_DOUBLE_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_DOUBLE, 0, .u = { .f64 = val } } 950 | #define JS_PROP_UNDEFINED_DEF(name, prop_flags) { name, prop_flags, JS_DEF_PROP_UNDEFINED, 0, .u = { .i32 = 0 } } 951 | #define JS_OBJECT_DEF(name, tab, len, prop_flags) { name, prop_flags, JS_DEF_OBJECT, 0, .u = { .prop_list = { tab, len } } } 952 | #define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, -1 } } } 953 | #define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, base } } } 954 | 955 | void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj, 956 | const JSCFunctionListEntry *tab, 957 | int len); 958 | 959 | /* C module definition */ 960 | 961 | typedef int JSModuleInitFunc(JSContext *ctx, JSModuleDef *m); 962 | 963 | JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str, 964 | JSModuleInitFunc *func); 965 | /* can only be called before the module is instantiated */ 966 | int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *name_str); 967 | int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m, 968 | const JSCFunctionListEntry *tab, int len); 969 | /* can only be called after the module is instantiated */ 970 | int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name, 971 | JSValue val); 972 | int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m, 973 | const JSCFunctionListEntry *tab, int len); 974 | 975 | #undef js_unlikely 976 | #undef js_force_inline 977 | 978 | #ifdef __cplusplus 979 | } /* extern "C" { */ 980 | #endif 981 | 982 | #endif /* QUICKJS_H */ 983 | -------------------------------------------------------------------------------- /src/libunicode.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Unicode utilities 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "cutils.h" 31 | #include "libunicode.h" 32 | #include "libunicode-table.h" 33 | 34 | enum { 35 | RUN_TYPE_U, 36 | RUN_TYPE_L, 37 | RUN_TYPE_UF, 38 | RUN_TYPE_LF, 39 | RUN_TYPE_UL, 40 | RUN_TYPE_LSU, 41 | RUN_TYPE_U2L_399_EXT2, 42 | RUN_TYPE_UF_D20, 43 | RUN_TYPE_UF_D1_EXT, 44 | RUN_TYPE_U_EXT, 45 | RUN_TYPE_LF_EXT, 46 | RUN_TYPE_U_EXT2, 47 | RUN_TYPE_L_EXT2, 48 | RUN_TYPE_U_EXT3, 49 | }; 50 | 51 | /* conv_type: 52 | 0 = to upper 53 | 1 = to lower 54 | 2 = case folding (= to lower with modifications) 55 | */ 56 | int lre_case_conv(uint32_t *res, uint32_t c, int conv_type) 57 | { 58 | if (c < 128) { 59 | if (conv_type) { 60 | if (c >= 'A' && c <= 'Z') { 61 | c = c - 'A' + 'a'; 62 | } 63 | } else { 64 | if (c >= 'a' && c <= 'z') { 65 | c = c - 'a' + 'A'; 66 | } 67 | } 68 | } else { 69 | uint32_t v, code, data, type, len, a, is_lower; 70 | int idx, idx_min, idx_max; 71 | 72 | is_lower = (conv_type != 0); 73 | idx_min = 0; 74 | idx_max = countof(case_conv_table1) - 1; 75 | while (idx_min <= idx_max) { 76 | idx = (unsigned)(idx_max + idx_min) / 2; 77 | v = case_conv_table1[idx]; 78 | code = v >> (32 - 17); 79 | len = (v >> (32 - 17 - 7)) & 0x7f; 80 | if (c < code) { 81 | idx_max = idx - 1; 82 | } else if (c >= code + len) { 83 | idx_min = idx + 1; 84 | } else { 85 | type = (v >> (32 - 17 - 7 - 4)) & 0xf; 86 | data = ((v & 0xf) << 8) | case_conv_table2[idx]; 87 | switch(type) { 88 | case RUN_TYPE_U: 89 | case RUN_TYPE_L: 90 | case RUN_TYPE_UF: 91 | case RUN_TYPE_LF: 92 | if (conv_type == (type & 1) || 93 | (type >= RUN_TYPE_UF && conv_type == 2)) { 94 | c = c - code + (case_conv_table1[data] >> (32 - 17)); 95 | } 96 | break; 97 | case RUN_TYPE_UL: 98 | a = c - code; 99 | if ((a & 1) != (1 - is_lower)) 100 | break; 101 | c = (a ^ 1) + code; 102 | break; 103 | case RUN_TYPE_LSU: 104 | a = c - code; 105 | if (a == 1) { 106 | c += 2 * is_lower - 1; 107 | } else if (a == (1 - is_lower) * 2) { 108 | c += (2 * is_lower - 1) * 2; 109 | } 110 | break; 111 | case RUN_TYPE_U2L_399_EXT2: 112 | if (!is_lower) { 113 | res[0] = c - code + case_conv_ext[data >> 6]; 114 | res[1] = 0x399; 115 | return 2; 116 | } else { 117 | c = c - code + case_conv_ext[data & 0x3f]; 118 | } 119 | break; 120 | case RUN_TYPE_UF_D20: 121 | if (conv_type == 1) 122 | break; 123 | c = data + (conv_type == 2) * 0x20; 124 | break; 125 | case RUN_TYPE_UF_D1_EXT: 126 | if (conv_type == 1) 127 | break; 128 | c = case_conv_ext[data] + (conv_type == 2); 129 | break; 130 | case RUN_TYPE_U_EXT: 131 | case RUN_TYPE_LF_EXT: 132 | if (is_lower != (type - RUN_TYPE_U_EXT)) 133 | break; 134 | c = case_conv_ext[data]; 135 | break; 136 | case RUN_TYPE_U_EXT2: 137 | case RUN_TYPE_L_EXT2: 138 | if (conv_type != (type - RUN_TYPE_U_EXT2)) 139 | break; 140 | res[0] = c - code + case_conv_ext[data >> 6]; 141 | res[1] = case_conv_ext[data & 0x3f]; 142 | return 2; 143 | default: 144 | case RUN_TYPE_U_EXT3: 145 | if (conv_type != 0) 146 | break; 147 | res[0] = case_conv_ext[data >> 8]; 148 | res[1] = case_conv_ext[(data >> 4) & 0xf]; 149 | res[2] = case_conv_ext[data & 0xf]; 150 | return 3; 151 | } 152 | break; 153 | } 154 | } 155 | } 156 | res[0] = c; 157 | return 1; 158 | } 159 | 160 | static uint32_t get_le24(const uint8_t *ptr) 161 | { 162 | #if defined(__x86__) || defined(__x86_64__) 163 | return *(uint16_t *)ptr | (ptr[2] << 16); 164 | #else 165 | return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16); 166 | #endif 167 | } 168 | 169 | #define UNICODE_INDEX_BLOCK_LEN 32 170 | 171 | /* return -1 if not in table, otherwise the offset in the block */ 172 | static int get_index_pos(uint32_t *pcode, uint32_t c, 173 | const uint8_t *index_table, int index_table_len) 174 | { 175 | uint32_t code, v; 176 | int idx_min, idx_max, idx; 177 | 178 | idx_min = 0; 179 | v = get_le24(index_table); 180 | code = v & ((1 << 21) - 1); 181 | if (c < code) { 182 | *pcode = 0; 183 | return 0; 184 | } 185 | idx_max = index_table_len - 1; 186 | code = get_le24(index_table + idx_max * 3); 187 | if (c >= code) 188 | return -1; 189 | /* invariant: tab[idx_min] <= c < tab2[idx_max] */ 190 | while ((idx_max - idx_min) > 1) { 191 | idx = (idx_max + idx_min) / 2; 192 | v = get_le24(index_table + idx * 3); 193 | code = v & ((1 << 21) - 1); 194 | if (c < code) { 195 | idx_max = idx; 196 | } else { 197 | idx_min = idx; 198 | } 199 | } 200 | v = get_le24(index_table + idx_min * 3); 201 | *pcode = v & ((1 << 21) - 1); 202 | return (idx_min + 1) * UNICODE_INDEX_BLOCK_LEN + (v >> 21); 203 | } 204 | 205 | static BOOL lre_is_in_table(uint32_t c, const uint8_t *table, 206 | const uint8_t *index_table, int index_table_len) 207 | { 208 | uint32_t code, b, bit; 209 | int pos; 210 | const uint8_t *p; 211 | 212 | pos = get_index_pos(&code, c, index_table, index_table_len); 213 | if (pos < 0) 214 | return FALSE; /* outside the table */ 215 | p = table + pos; 216 | bit = 0; 217 | for(;;) { 218 | b = *p++; 219 | if (b < 64) { 220 | code += (b >> 3) + 1; 221 | if (c < code) 222 | return bit; 223 | bit ^= 1; 224 | code += (b & 7) + 1; 225 | } else if (b >= 0x80) { 226 | code += b - 0x80 + 1; 227 | } else if (b < 0x60) { 228 | code += (((b - 0x40) << 8) | p[0]) + 1; 229 | p++; 230 | } else { 231 | code += (((b - 0x60) << 16) | (p[0] << 8) | p[1]) + 1; 232 | p += 2; 233 | } 234 | if (c < code) 235 | return bit; 236 | bit ^= 1; 237 | } 238 | } 239 | 240 | BOOL lre_is_cased(uint32_t c) 241 | { 242 | uint32_t v, code, len; 243 | int idx, idx_min, idx_max; 244 | 245 | idx_min = 0; 246 | idx_max = countof(case_conv_table1) - 1; 247 | while (idx_min <= idx_max) { 248 | idx = (unsigned)(idx_max + idx_min) / 2; 249 | v = case_conv_table1[idx]; 250 | code = v >> (32 - 17); 251 | len = (v >> (32 - 17 - 7)) & 0x7f; 252 | if (c < code) { 253 | idx_max = idx - 1; 254 | } else if (c >= code + len) { 255 | idx_min = idx + 1; 256 | } else { 257 | return TRUE; 258 | } 259 | } 260 | return lre_is_in_table(c, unicode_prop_Cased1_table, 261 | unicode_prop_Cased1_index, 262 | sizeof(unicode_prop_Cased1_index) / 3); 263 | } 264 | 265 | BOOL lre_is_case_ignorable(uint32_t c) 266 | { 267 | return lre_is_in_table(c, unicode_prop_Case_Ignorable_table, 268 | unicode_prop_Case_Ignorable_index, 269 | sizeof(unicode_prop_Case_Ignorable_index) / 3); 270 | } 271 | 272 | /* character range */ 273 | 274 | static __maybe_unused void cr_dump(CharRange *cr) 275 | { 276 | int i; 277 | for(i = 0; i < cr->len; i++) 278 | printf("%d: 0x%04x\n", i, cr->points[i]); 279 | } 280 | 281 | static void *cr_default_realloc(void *opaque, void *ptr, size_t size) 282 | { 283 | return realloc(ptr, size); 284 | } 285 | 286 | void cr_init(CharRange *cr, void *mem_opaque, DynBufReallocFunc *realloc_func) 287 | { 288 | cr->len = cr->size = 0; 289 | cr->points = NULL; 290 | cr->mem_opaque = mem_opaque; 291 | cr->realloc_func = realloc_func ? realloc_func : cr_default_realloc; 292 | } 293 | 294 | void cr_free(CharRange *cr) 295 | { 296 | cr->realloc_func(cr->mem_opaque, cr->points, 0); 297 | } 298 | 299 | int cr_realloc(CharRange *cr, int size) 300 | { 301 | int new_size; 302 | uint32_t *new_buf; 303 | 304 | if (size > cr->size) { 305 | new_size = max_int(size, cr->size * 3 / 2); 306 | new_buf = cr->realloc_func(cr->mem_opaque, cr->points, 307 | new_size * sizeof(cr->points[0])); 308 | if (!new_buf) 309 | return -1; 310 | cr->points = new_buf; 311 | cr->size = new_size; 312 | } 313 | return 0; 314 | } 315 | 316 | int cr_copy(CharRange *cr, const CharRange *cr1) 317 | { 318 | if (cr_realloc(cr, cr1->len)) 319 | return -1; 320 | memcpy(cr->points, cr1->points, sizeof(cr->points[0]) * cr1->len); 321 | cr->len = cr1->len; 322 | return 0; 323 | } 324 | 325 | /* merge consecutive intervals and remove empty intervals */ 326 | static void cr_compress(CharRange *cr) 327 | { 328 | int i, j, k, len; 329 | uint32_t *pt; 330 | 331 | pt = cr->points; 332 | len = cr->len; 333 | i = 0; 334 | j = 0; 335 | k = 0; 336 | while ((i + 1) < len) { 337 | if (pt[i] == pt[i + 1]) { 338 | /* empty interval */ 339 | i += 2; 340 | } else { 341 | j = i; 342 | while ((j + 3) < len && pt[j + 1] == pt[j + 2]) 343 | j += 2; 344 | /* just copy */ 345 | pt[k] = pt[i]; 346 | pt[k + 1] = pt[j + 1]; 347 | k += 2; 348 | i = j + 2; 349 | } 350 | } 351 | cr->len = k; 352 | } 353 | 354 | /* union or intersection */ 355 | int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len, 356 | const uint32_t *b_pt, int b_len, int op) 357 | { 358 | int a_idx, b_idx, is_in; 359 | uint32_t v; 360 | 361 | a_idx = 0; 362 | b_idx = 0; 363 | for(;;) { 364 | /* get one more point from a or b in increasing order */ 365 | if (a_idx < a_len && b_idx < b_len) { 366 | if (a_pt[a_idx] < b_pt[b_idx]) { 367 | goto a_add; 368 | } else if (a_pt[a_idx] == b_pt[b_idx]) { 369 | v = a_pt[a_idx]; 370 | a_idx++; 371 | b_idx++; 372 | } else { 373 | goto b_add; 374 | } 375 | } else if (a_idx < a_len) { 376 | a_add: 377 | v = a_pt[a_idx++]; 378 | } else if (b_idx < b_len) { 379 | b_add: 380 | v = b_pt[b_idx++]; 381 | } else { 382 | break; 383 | } 384 | /* add the point if the in/out status changes */ 385 | switch(op) { 386 | case CR_OP_UNION: 387 | is_in = (a_idx & 1) | (b_idx & 1); 388 | break; 389 | case CR_OP_INTER: 390 | is_in = (a_idx & 1) & (b_idx & 1); 391 | break; 392 | case CR_OP_XOR: 393 | is_in = (a_idx & 1) ^ (b_idx & 1); 394 | break; 395 | default: 396 | abort(); 397 | } 398 | if (is_in != (cr->len & 1)) { 399 | if (cr_add_point(cr, v)) 400 | return -1; 401 | } 402 | } 403 | cr_compress(cr); 404 | return 0; 405 | } 406 | 407 | int cr_union1(CharRange *cr, const uint32_t *b_pt, int b_len) 408 | { 409 | CharRange a = *cr; 410 | int ret; 411 | cr->len = 0; 412 | cr->size = 0; 413 | cr->points = NULL; 414 | ret = cr_op(cr, a.points, a.len, b_pt, b_len, CR_OP_UNION); 415 | cr_free(&a); 416 | return ret; 417 | } 418 | 419 | int cr_invert(CharRange *cr) 420 | { 421 | int len; 422 | len = cr->len; 423 | if (cr_realloc(cr, len + 2)) 424 | return -1; 425 | memmove(cr->points + 1, cr->points, len * sizeof(cr->points[0])); 426 | cr->points[0] = 0; 427 | cr->points[len + 1] = UINT32_MAX; 428 | cr->len = len + 2; 429 | cr_compress(cr); 430 | return 0; 431 | } 432 | 433 | #ifdef CONFIG_ALL_UNICODE 434 | 435 | BOOL lre_is_id_start(uint32_t c) 436 | { 437 | return lre_is_in_table(c, unicode_prop_ID_Start_table, 438 | unicode_prop_ID_Start_index, 439 | sizeof(unicode_prop_ID_Start_index) / 3); 440 | } 441 | 442 | BOOL lre_is_id_continue(uint32_t c) 443 | { 444 | return lre_is_id_start(c) || 445 | lre_is_in_table(c, unicode_prop_ID_Continue1_table, 446 | unicode_prop_ID_Continue1_index, 447 | sizeof(unicode_prop_ID_Continue1_index) / 3); 448 | } 449 | 450 | #define UNICODE_DECOMP_LEN_MAX 18 451 | 452 | typedef enum { 453 | DECOMP_TYPE_C1, /* 16 bit char */ 454 | DECOMP_TYPE_L1, /* 16 bit char table */ 455 | DECOMP_TYPE_L2, 456 | DECOMP_TYPE_L3, 457 | DECOMP_TYPE_L4, 458 | DECOMP_TYPE_L5, /* XXX: not used */ 459 | DECOMP_TYPE_L6, /* XXX: could remove */ 460 | DECOMP_TYPE_L7, /* XXX: could remove */ 461 | DECOMP_TYPE_LL1, /* 18 bit char table */ 462 | DECOMP_TYPE_LL2, 463 | DECOMP_TYPE_S1, /* 8 bit char table */ 464 | DECOMP_TYPE_S2, 465 | DECOMP_TYPE_S3, 466 | DECOMP_TYPE_S4, 467 | DECOMP_TYPE_S5, 468 | DECOMP_TYPE_I1, /* increment 16 bit char value */ 469 | DECOMP_TYPE_I2_0, 470 | DECOMP_TYPE_I2_1, 471 | DECOMP_TYPE_I3_1, 472 | DECOMP_TYPE_I3_2, 473 | DECOMP_TYPE_I4_1, 474 | DECOMP_TYPE_I4_2, 475 | DECOMP_TYPE_B1, /* 16 bit base + 8 bit offset */ 476 | DECOMP_TYPE_B2, 477 | DECOMP_TYPE_B3, 478 | DECOMP_TYPE_B4, 479 | DECOMP_TYPE_B5, 480 | DECOMP_TYPE_B6, 481 | DECOMP_TYPE_B7, 482 | DECOMP_TYPE_B8, 483 | DECOMP_TYPE_B18, 484 | DECOMP_TYPE_LS2, 485 | DECOMP_TYPE_PAT3, 486 | DECOMP_TYPE_S2_UL, 487 | DECOMP_TYPE_LS2_UL, 488 | } DecompTypeEnum; 489 | 490 | static uint32_t unicode_get_short_code(uint32_t c) 491 | { 492 | static const uint16_t unicode_short_table[2] = { 0x2044, 0x2215 }; 493 | 494 | if (c < 0x80) 495 | return c; 496 | else if (c < 0x80 + 0x50) 497 | return c - 0x80 + 0x300; 498 | else 499 | return unicode_short_table[c - 0x80 - 0x50]; 500 | } 501 | 502 | static uint32_t unicode_get_lower_simple(uint32_t c) 503 | { 504 | if (c < 0x100 || (c >= 0x410 && c <= 0x42f)) 505 | c += 0x20; 506 | else 507 | c++; 508 | return c; 509 | } 510 | 511 | static uint16_t unicode_get16(const uint8_t *p) 512 | { 513 | return p[0] | (p[1] << 8); 514 | } 515 | 516 | static int unicode_decomp_entry(uint32_t *res, uint32_t c, 517 | int idx, uint32_t code, uint32_t len, 518 | uint32_t type) 519 | { 520 | uint32_t c1; 521 | int l, i, p; 522 | const uint8_t *d; 523 | 524 | if (type == DECOMP_TYPE_C1) { 525 | res[0] = unicode_decomp_table2[idx]; 526 | return 1; 527 | } else { 528 | d = unicode_decomp_data + unicode_decomp_table2[idx]; 529 | switch(type) { 530 | case DECOMP_TYPE_L1 ... DECOMP_TYPE_L7: 531 | l = type - DECOMP_TYPE_L1 + 1; 532 | d += (c - code) * l * 2; 533 | for(i = 0; i < l; i++) { 534 | if ((res[i] = unicode_get16(d + 2 * i)) == 0) 535 | return 0; 536 | } 537 | return l; 538 | case DECOMP_TYPE_LL1 ... DECOMP_TYPE_LL2: 539 | { 540 | uint32_t k, p; 541 | l = type - DECOMP_TYPE_LL1 + 1; 542 | k = (c - code) * l; 543 | p = len * l * 2; 544 | for(i = 0; i < l; i++) { 545 | c1 = unicode_get16(d + 2 * k) | 546 | (((d[p + (k / 4)] >> ((k % 4) * 2)) & 3) << 16); 547 | if (!c1) 548 | return 0; 549 | res[i] = c1; 550 | k++; 551 | } 552 | } 553 | return l; 554 | case DECOMP_TYPE_S1 ... DECOMP_TYPE_S5: 555 | l = type - DECOMP_TYPE_S1 + 1; 556 | d += (c - code) * l; 557 | for(i = 0; i < l; i++) { 558 | if ((res[i] = unicode_get_short_code(d[i])) == 0) 559 | return 0; 560 | } 561 | return l; 562 | case DECOMP_TYPE_I1: 563 | l = 1; 564 | p = 0; 565 | goto decomp_type_i; 566 | case DECOMP_TYPE_I2_0: 567 | case DECOMP_TYPE_I2_1: 568 | case DECOMP_TYPE_I3_1: 569 | case DECOMP_TYPE_I3_2: 570 | case DECOMP_TYPE_I4_1: 571 | case DECOMP_TYPE_I4_2: 572 | l = 2 + ((type - DECOMP_TYPE_I2_0) >> 1); 573 | p = ((type - DECOMP_TYPE_I2_0) & 1) + (l > 2); 574 | decomp_type_i: 575 | for(i = 0; i < l; i++) { 576 | c1 = unicode_get16(d + 2 * i); 577 | if (i == p) 578 | c1 += c - code; 579 | res[i] = c1; 580 | } 581 | return l; 582 | case DECOMP_TYPE_B18: 583 | l = 18; 584 | goto decomp_type_b; 585 | case DECOMP_TYPE_B1 ... DECOMP_TYPE_B8: 586 | l = type - DECOMP_TYPE_B1 + 1; 587 | decomp_type_b: 588 | { 589 | uint32_t c_min; 590 | c_min = unicode_get16(d); 591 | d += 2 + (c - code) * l; 592 | for(i = 0; i < l; i++) { 593 | c1 = d[i]; 594 | if (c1 == 0xff) 595 | c1 = 0x20; 596 | else 597 | c1 += c_min; 598 | res[i] = c1; 599 | } 600 | } 601 | return l; 602 | case DECOMP_TYPE_LS2: 603 | d += (c - code) * 3; 604 | if (!(res[0] = unicode_get16(d))) 605 | return 0; 606 | res[1] = unicode_get_short_code(d[2]); 607 | return 2; 608 | case DECOMP_TYPE_PAT3: 609 | res[0] = unicode_get16(d); 610 | res[2] = unicode_get16(d + 2); 611 | d += 4 + (c - code) * 2; 612 | res[1] = unicode_get16(d); 613 | return 3; 614 | case DECOMP_TYPE_S2_UL: 615 | case DECOMP_TYPE_LS2_UL: 616 | c1 = c - code; 617 | if (type == DECOMP_TYPE_S2_UL) { 618 | d += c1 & ~1; 619 | c = unicode_get_short_code(*d); 620 | d++; 621 | } else { 622 | d += (c1 >> 1) * 3; 623 | c = unicode_get16(d); 624 | d += 2; 625 | } 626 | if (c1 & 1) 627 | c = unicode_get_lower_simple(c); 628 | res[0] = c; 629 | res[1] = unicode_get_short_code(*d); 630 | return 2; 631 | } 632 | } 633 | return 0; 634 | } 635 | 636 | 637 | /* return the length of the decomposition (length <= 638 | UNICODE_DECOMP_LEN_MAX) or 0 if no decomposition */ 639 | static int unicode_decomp_char(uint32_t *res, uint32_t c, BOOL is_compat1) 640 | { 641 | uint32_t v, type, is_compat, code, len; 642 | int idx_min, idx_max, idx; 643 | 644 | idx_min = 0; 645 | idx_max = countof(unicode_decomp_table1) - 1; 646 | while (idx_min <= idx_max) { 647 | idx = (idx_max + idx_min) / 2; 648 | v = unicode_decomp_table1[idx]; 649 | code = v >> (32 - 18); 650 | len = (v >> (32 - 18 - 7)) & 0x7f; 651 | // printf("idx=%d code=%05x len=%d\n", idx, code, len); 652 | if (c < code) { 653 | idx_max = idx - 1; 654 | } else if (c >= code + len) { 655 | idx_min = idx + 1; 656 | } else { 657 | is_compat = v & 1; 658 | if (is_compat1 < is_compat) 659 | break; 660 | type = (v >> (32 - 18 - 7 - 6)) & 0x3f; 661 | return unicode_decomp_entry(res, c, idx, code, len, type); 662 | } 663 | } 664 | return 0; 665 | } 666 | 667 | /* return 0 if no pair found */ 668 | static int unicode_compose_pair(uint32_t c0, uint32_t c1) 669 | { 670 | uint32_t code, len, type, v, idx1, d_idx, d_offset, ch; 671 | int idx_min, idx_max, idx, d; 672 | uint32_t pair[2]; 673 | 674 | idx_min = 0; 675 | idx_max = countof(unicode_comp_table) - 1; 676 | while (idx_min <= idx_max) { 677 | idx = (idx_max + idx_min) / 2; 678 | idx1 = unicode_comp_table[idx]; 679 | 680 | /* idx1 represent an entry of the decomposition table */ 681 | d_idx = idx1 >> 6; 682 | d_offset = idx1 & 0x3f; 683 | v = unicode_decomp_table1[d_idx]; 684 | code = v >> (32 - 18); 685 | len = (v >> (32 - 18 - 7)) & 0x7f; 686 | type = (v >> (32 - 18 - 7 - 6)) & 0x3f; 687 | ch = code + d_offset; 688 | unicode_decomp_entry(pair, ch, d_idx, code, len, type); 689 | d = c0 - pair[0]; 690 | if (d == 0) 691 | d = c1 - pair[1]; 692 | if (d < 0) { 693 | idx_max = idx - 1; 694 | } else if (d > 0) { 695 | idx_min = idx + 1; 696 | } else { 697 | return ch; 698 | } 699 | } 700 | return 0; 701 | } 702 | 703 | /* return the combining class of character c (between 0 and 255) */ 704 | static int unicode_get_cc(uint32_t c) 705 | { 706 | uint32_t code, n, type, cc, c1, b; 707 | int pos; 708 | const uint8_t *p; 709 | 710 | pos = get_index_pos(&code, c, 711 | unicode_cc_index, sizeof(unicode_cc_index) / 3); 712 | if (pos < 0) 713 | return 0; 714 | p = unicode_cc_table + pos; 715 | for(;;) { 716 | b = *p++; 717 | type = b >> 6; 718 | n = b & 0x3f; 719 | if (n < 48) { 720 | } else if (n < 56) { 721 | n = (n - 48) << 8; 722 | n |= *p++; 723 | n += 48; 724 | } else { 725 | n = (n - 56) << 8; 726 | n |= *p++ << 8; 727 | n |= *p++; 728 | n += 48 + (1 << 11); 729 | } 730 | if (type <= 1) 731 | p++; 732 | c1 = code + n + 1; 733 | if (c < c1) { 734 | switch(type) { 735 | case 0: 736 | cc = p[-1]; 737 | break; 738 | case 1: 739 | cc = p[-1] + c - code; 740 | break; 741 | case 2: 742 | cc = 0; 743 | break; 744 | default: 745 | case 3: 746 | cc = 230; 747 | break; 748 | } 749 | return cc; 750 | } 751 | code = c1; 752 | } 753 | } 754 | 755 | static void sort_cc(int *buf, int len) 756 | { 757 | int i, j, k, cc, cc1, start, ch1; 758 | 759 | for(i = 0; i < len; i++) { 760 | cc = unicode_get_cc(buf[i]); 761 | if (cc != 0) { 762 | start = i; 763 | j = i + 1; 764 | while (j < len) { 765 | ch1 = buf[j]; 766 | cc1 = unicode_get_cc(ch1); 767 | if (cc1 == 0) 768 | break; 769 | k = j - 1; 770 | while (k >= start) { 771 | if (unicode_get_cc(buf[k]) <= cc1) 772 | break; 773 | buf[k + 1] = buf[k]; 774 | k--; 775 | } 776 | buf[k + 1] = ch1; 777 | j++; 778 | } 779 | #if 0 780 | printf("cc:"); 781 | for(k = start; k < j; k++) { 782 | printf(" %3d", unicode_get_cc(buf[k])); 783 | } 784 | printf("\n"); 785 | #endif 786 | i = j; 787 | } 788 | } 789 | } 790 | 791 | static void to_nfd_rec(DynBuf *dbuf, 792 | const int *src, int src_len, int is_compat) 793 | { 794 | uint32_t c, v; 795 | int i, l; 796 | uint32_t res[UNICODE_DECOMP_LEN_MAX]; 797 | 798 | for(i = 0; i < src_len; i++) { 799 | c = src[i]; 800 | if (c >= 0xac00 && c < 0xd7a4) { 801 | /* Hangul decomposition */ 802 | c -= 0xac00; 803 | dbuf_put_u32(dbuf, 0x1100 + c / 588); 804 | dbuf_put_u32(dbuf, 0x1161 + (c % 588) / 28); 805 | v = c % 28; 806 | if (v != 0) 807 | dbuf_put_u32(dbuf, 0x11a7 + v); 808 | } else { 809 | l = unicode_decomp_char(res, c, is_compat); 810 | if (l) { 811 | to_nfd_rec(dbuf, (int *)res, l, is_compat); 812 | } else { 813 | dbuf_put_u32(dbuf, c); 814 | } 815 | } 816 | } 817 | } 818 | 819 | /* return 0 if not found */ 820 | static int compose_pair(uint32_t c0, uint32_t c1) 821 | { 822 | /* Hangul composition */ 823 | if (c0 >= 0x1100 && c0 < 0x1100 + 19 && 824 | c1 >= 0x1161 && c1 < 0x1161 + 21) { 825 | return 0xac00 + (c0 - 0x1100) * 588 + (c1 - 0x1161) * 28; 826 | } else if (c0 >= 0xac00 && c0 < 0xac00 + 11172 && 827 | (c0 - 0xac00) % 28 == 0 && 828 | c1 >= 0x11a7 && c1 < 0x11a7 + 28) { 829 | return c0 + c1 - 0x11a7; 830 | } else { 831 | return unicode_compose_pair(c0, c1); 832 | } 833 | } 834 | 835 | int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len, 836 | UnicodeNormalizationEnum n_type, 837 | void *opaque, DynBufReallocFunc *realloc_func) 838 | { 839 | int *buf, buf_len, i, p, starter_pos, cc, last_cc, out_len; 840 | BOOL is_compat; 841 | DynBuf dbuf_s, *dbuf = &dbuf_s; 842 | 843 | is_compat = n_type >> 1; 844 | 845 | dbuf_init2(dbuf, opaque, realloc_func); 846 | if (dbuf_realloc(dbuf, sizeof(int) * src_len)) 847 | goto fail; 848 | 849 | /* common case: latin1 is unaffected by NFC */ 850 | if (n_type == UNICODE_NFC) { 851 | for(i = 0; i < src_len; i++) { 852 | if (src[i] >= 0x100) 853 | goto not_latin1; 854 | } 855 | buf = (int *)dbuf->buf; 856 | memcpy(buf, src, src_len * sizeof(int)); 857 | *pdst = (uint32_t *)buf; 858 | return src_len; 859 | not_latin1: ; 860 | } 861 | 862 | to_nfd_rec(dbuf, (const int *)src, src_len, is_compat); 863 | if (dbuf_error(dbuf)) { 864 | fail: 865 | *pdst = NULL; 866 | return -1; 867 | } 868 | buf = (int *)dbuf->buf; 869 | buf_len = dbuf->size / sizeof(int); 870 | 871 | sort_cc(buf, buf_len); 872 | 873 | if (buf_len <= 1 || (n_type & 1) != 0) { 874 | /* NFD / NFKD */ 875 | *pdst = (uint32_t *)buf; 876 | return buf_len; 877 | } 878 | 879 | i = 1; 880 | out_len = 1; 881 | while (i < buf_len) { 882 | /* find the starter character and test if it is blocked from 883 | the character at 'i' */ 884 | last_cc = unicode_get_cc(buf[i]); 885 | starter_pos = out_len - 1; 886 | while (starter_pos >= 0) { 887 | cc = unicode_get_cc(buf[starter_pos]); 888 | if (cc == 0) 889 | break; 890 | if (cc >= last_cc) 891 | goto next; 892 | last_cc = 256; 893 | starter_pos--; 894 | } 895 | if (starter_pos >= 0 && 896 | (p = compose_pair(buf[starter_pos], buf[i])) != 0) { 897 | buf[starter_pos] = p; 898 | i++; 899 | } else { 900 | next: 901 | buf[out_len++] = buf[i++]; 902 | } 903 | } 904 | *pdst = (uint32_t *)buf; 905 | return out_len; 906 | } 907 | 908 | /* char ranges for various unicode properties */ 909 | 910 | static int unicode_find_name(const char *name_table, const char *name) 911 | { 912 | const char *p, *r; 913 | int pos; 914 | size_t name_len, len; 915 | 916 | p = name_table; 917 | pos = 0; 918 | name_len = strlen(name); 919 | while (*p) { 920 | for(;;) { 921 | r = strchr(p, ','); 922 | if (!r) 923 | len = strlen(p); 924 | else 925 | len = r - p; 926 | if (len == name_len && !memcmp(p, name, name_len)) 927 | return pos; 928 | p += len + 1; 929 | if (!r) 930 | break; 931 | } 932 | pos++; 933 | } 934 | return -1; 935 | } 936 | 937 | /* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2 938 | if not found */ 939 | int unicode_script(CharRange *cr, 940 | const char *script_name, BOOL is_ext) 941 | { 942 | int script_idx; 943 | const uint8_t *p, *p_end; 944 | uint32_t c, c1, b, n, v, v_len, i, type; 945 | CharRange cr1_s, *cr1; 946 | CharRange cr2_s, *cr2 = &cr2_s; 947 | BOOL is_common; 948 | 949 | script_idx = unicode_find_name(unicode_script_name_table, script_name); 950 | if (script_idx < 0) 951 | return -2; 952 | /* Note: we remove the "Unknown" Script */ 953 | script_idx += UNICODE_SCRIPT_Unknown + 1; 954 | 955 | is_common = (script_idx == UNICODE_SCRIPT_Common || 956 | script_idx == UNICODE_SCRIPT_Inherited); 957 | if (is_ext) { 958 | cr1 = &cr1_s; 959 | cr_init(cr1, cr->mem_opaque, cr->realloc_func); 960 | cr_init(cr2, cr->mem_opaque, cr->realloc_func); 961 | } else { 962 | cr1 = cr; 963 | } 964 | 965 | p = unicode_script_table; 966 | p_end = unicode_script_table + countof(unicode_script_table); 967 | c = 0; 968 | while (p < p_end) { 969 | b = *p++; 970 | type = b >> 7; 971 | n = b & 0x7f; 972 | if (n < 96) { 973 | } else if (n < 112) { 974 | n = (n - 96) << 8; 975 | n |= *p++; 976 | n += 96; 977 | } else { 978 | n = (n - 112) << 16; 979 | n |= *p++ << 8; 980 | n |= *p++; 981 | n += 96 + (1 << 12); 982 | } 983 | if (type == 0) 984 | v = 0; 985 | else 986 | v = *p++; 987 | c1 = c + n + 1; 988 | if (v == script_idx) { 989 | if (cr_add_interval(cr1, c, c1)) 990 | goto fail; 991 | } 992 | c = c1; 993 | } 994 | 995 | if (is_ext) { 996 | /* add the script extensions */ 997 | p = unicode_script_ext_table; 998 | p_end = unicode_script_ext_table + countof(unicode_script_ext_table); 999 | c = 0; 1000 | while (p < p_end) { 1001 | b = *p++; 1002 | if (b < 128) { 1003 | n = b; 1004 | } else if (b < 128 + 64) { 1005 | n = (b - 128) << 8; 1006 | n |= *p++; 1007 | n += 128; 1008 | } else { 1009 | n = (b - 128 - 64) << 16; 1010 | n |= *p++ << 8; 1011 | n |= *p++; 1012 | n += 128 + (1 << 14); 1013 | } 1014 | c1 = c + n + 1; 1015 | v_len = *p++; 1016 | if (is_common) { 1017 | if (v_len != 0) { 1018 | if (cr_add_interval(cr2, c, c1)) 1019 | goto fail; 1020 | } 1021 | } else { 1022 | for(i = 0; i < v_len; i++) { 1023 | if (p[i] == script_idx) { 1024 | if (cr_add_interval(cr2, c, c1)) 1025 | goto fail; 1026 | break; 1027 | } 1028 | } 1029 | } 1030 | p += v_len; 1031 | c = c1; 1032 | } 1033 | if (is_common) { 1034 | /* remove all the characters with script extensions */ 1035 | if (cr_invert(cr2)) 1036 | goto fail; 1037 | if (cr_op(cr, cr1->points, cr1->len, cr2->points, cr2->len, 1038 | CR_OP_INTER)) 1039 | goto fail; 1040 | } else { 1041 | if (cr_op(cr, cr1->points, cr1->len, cr2->points, cr2->len, 1042 | CR_OP_UNION)) 1043 | goto fail; 1044 | } 1045 | cr_free(cr1); 1046 | cr_free(cr2); 1047 | } 1048 | return 0; 1049 | fail: 1050 | if (is_ext) { 1051 | cr_free(cr1); 1052 | cr_free(cr2); 1053 | } 1054 | goto fail; 1055 | } 1056 | 1057 | #define M(id) (1U << UNICODE_GC_ ## id) 1058 | 1059 | static int unicode_general_category1(CharRange *cr, uint32_t gc_mask) 1060 | { 1061 | const uint8_t *p, *p_end; 1062 | uint32_t c, c0, b, n, v; 1063 | 1064 | p = unicode_gc_table; 1065 | p_end = unicode_gc_table + countof(unicode_gc_table); 1066 | c = 0; 1067 | while (p < p_end) { 1068 | b = *p++; 1069 | n = b >> 5; 1070 | v = b & 0x1f; 1071 | if (n == 7) { 1072 | n = *p++; 1073 | if (n < 128) { 1074 | n += 7; 1075 | } else if (n < 128 + 64) { 1076 | n = (n - 128) << 8; 1077 | n |= *p++; 1078 | n += 7 + 128; 1079 | } else { 1080 | n = (n - 128 - 64) << 16; 1081 | n |= *p++ << 8; 1082 | n |= *p++; 1083 | n += 7 + 128 + (1 << 14); 1084 | } 1085 | } 1086 | c0 = c; 1087 | c += n + 1; 1088 | if (v == 31) { 1089 | /* run of Lu / Ll */ 1090 | b = gc_mask & (M(Lu) | M(Ll)); 1091 | if (b != 0) { 1092 | if (b == (M(Lu) | M(Ll))) { 1093 | goto add_range; 1094 | } else { 1095 | c0 += ((gc_mask & M(Ll)) != 0); 1096 | for(; c0 < c; c0 += 2) { 1097 | if (cr_add_interval(cr, c0, c0 + 1)) 1098 | return -1; 1099 | } 1100 | } 1101 | } 1102 | } else if ((gc_mask >> v) & 1) { 1103 | add_range: 1104 | if (cr_add_interval(cr, c0, c)) 1105 | return -1; 1106 | } 1107 | } 1108 | return 0; 1109 | } 1110 | 1111 | static int unicode_prop1(CharRange *cr, int prop_idx) 1112 | { 1113 | const uint8_t *p, *p_end; 1114 | uint32_t c, c0, b, bit; 1115 | 1116 | p = unicode_prop_table[prop_idx]; 1117 | p_end = p + unicode_prop_len_table[prop_idx]; 1118 | c = 0; 1119 | bit = 0; 1120 | while (p < p_end) { 1121 | c0 = c; 1122 | b = *p++; 1123 | if (b < 64) { 1124 | c += (b >> 3) + 1; 1125 | if (bit) { 1126 | if (cr_add_interval(cr, c0, c)) 1127 | return -1; 1128 | } 1129 | bit ^= 1; 1130 | c0 = c; 1131 | c += (b & 7) + 1; 1132 | } else if (b >= 0x80) { 1133 | c += b - 0x80 + 1; 1134 | } else if (b < 0x60) { 1135 | c += (((b - 0x40) << 8) | p[0]) + 1; 1136 | p++; 1137 | } else { 1138 | c += (((b - 0x60) << 16) | (p[0] << 8) | p[1]) + 1; 1139 | p += 2; 1140 | } 1141 | if (bit) { 1142 | if (cr_add_interval(cr, c0, c)) 1143 | return -1; 1144 | } 1145 | bit ^= 1; 1146 | } 1147 | return 0; 1148 | } 1149 | 1150 | #define CASE_U (1 << 0) 1151 | #define CASE_L (1 << 1) 1152 | #define CASE_F (1 << 2) 1153 | 1154 | /* use the case conversion table to generate range of characters. 1155 | CASE_U: set char if modified by uppercasing, 1156 | CASE_L: set char if modified by lowercasing, 1157 | CASE_F: set char if modified by case folding, 1158 | */ 1159 | static int unicode_case1(CharRange *cr, int case_mask) 1160 | { 1161 | #define MR(x) (1 << RUN_TYPE_ ## x) 1162 | const uint32_t tab_run_mask[3] = { 1163 | MR(U) | MR(UF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(UF_D20) | 1164 | MR(UF_D1_EXT) | MR(U_EXT) | MR(U_EXT2) | MR(U_EXT3), 1165 | 1166 | MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(L_EXT2), 1167 | 1168 | MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT), 1169 | }; 1170 | #undef MR 1171 | uint32_t mask, v, code, type, len, i, idx; 1172 | 1173 | if (case_mask == 0) 1174 | return 0; 1175 | mask = 0; 1176 | for(i = 0; i < 3; i++) { 1177 | if ((case_mask >> i) & 1) 1178 | mask |= tab_run_mask[i]; 1179 | } 1180 | for(idx = 0; idx < countof(case_conv_table1); idx++) { 1181 | v = case_conv_table1[idx]; 1182 | type = (v >> (32 - 17 - 7 - 4)) & 0xf; 1183 | code = v >> (32 - 17); 1184 | len = (v >> (32 - 17 - 7)) & 0x7f; 1185 | if ((mask >> type) & 1) { 1186 | // printf("%d: type=%d %04x %04x\n", idx, type, code, code + len - 1); 1187 | switch(type) { 1188 | case RUN_TYPE_UL: 1189 | if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F))) 1190 | goto def_case; 1191 | code += ((case_mask & CASE_U) != 0); 1192 | for(i = 0; i < len; i += 2) { 1193 | if (cr_add_interval(cr, code + i, code + i + 1)) 1194 | return -1; 1195 | } 1196 | break; 1197 | case RUN_TYPE_LSU: 1198 | if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F))) 1199 | goto def_case; 1200 | if (!(case_mask & CASE_U)) { 1201 | if (cr_add_interval(cr, code, code + 1)) 1202 | return -1; 1203 | } 1204 | if (cr_add_interval(cr, code + 1, code + 2)) 1205 | return -1; 1206 | if (case_mask & CASE_U) { 1207 | if (cr_add_interval(cr, code + 2, code + 3)) 1208 | return -1; 1209 | } 1210 | break; 1211 | default: 1212 | def_case: 1213 | if (cr_add_interval(cr, code, code + len)) 1214 | return -1; 1215 | break; 1216 | } 1217 | } 1218 | } 1219 | return 0; 1220 | } 1221 | 1222 | typedef enum { 1223 | POP_GC, 1224 | POP_PROP, 1225 | POP_CASE, 1226 | POP_UNION, 1227 | POP_INTER, 1228 | POP_XOR, 1229 | POP_INVERT, 1230 | POP_END, 1231 | } PropOPEnum; 1232 | 1233 | #define POP_STACK_LEN_MAX 4 1234 | 1235 | static int unicode_prop_ops(CharRange *cr, ...) 1236 | { 1237 | va_list ap; 1238 | CharRange stack[POP_STACK_LEN_MAX]; 1239 | int stack_len, op, ret, i; 1240 | uint32_t a; 1241 | 1242 | va_start(ap, cr); 1243 | stack_len = 0; 1244 | for(;;) { 1245 | op = va_arg(ap, int); 1246 | switch(op) { 1247 | case POP_GC: 1248 | assert(stack_len < POP_STACK_LEN_MAX); 1249 | a = va_arg(ap, int); 1250 | cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func); 1251 | if (unicode_general_category1(&stack[stack_len - 1], a)) 1252 | goto fail; 1253 | break; 1254 | case POP_PROP: 1255 | assert(stack_len < POP_STACK_LEN_MAX); 1256 | a = va_arg(ap, int); 1257 | cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func); 1258 | if (unicode_prop1(&stack[stack_len - 1], a)) 1259 | goto fail; 1260 | break; 1261 | case POP_CASE: 1262 | assert(stack_len < POP_STACK_LEN_MAX); 1263 | a = va_arg(ap, int); 1264 | cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func); 1265 | if (unicode_case1(&stack[stack_len - 1], a)) 1266 | goto fail; 1267 | break; 1268 | case POP_UNION: 1269 | case POP_INTER: 1270 | case POP_XOR: 1271 | { 1272 | CharRange *cr1, *cr2, *cr3; 1273 | assert(stack_len >= 2); 1274 | assert(stack_len < POP_STACK_LEN_MAX); 1275 | cr1 = &stack[stack_len - 2]; 1276 | cr2 = &stack[stack_len - 1]; 1277 | cr3 = &stack[stack_len++]; 1278 | cr_init(cr3, cr->mem_opaque, cr->realloc_func); 1279 | if (cr_op(cr3, cr1->points, cr1->len, 1280 | cr2->points, cr2->len, op - POP_UNION + CR_OP_UNION)) 1281 | goto fail; 1282 | cr_free(cr1); 1283 | cr_free(cr2); 1284 | *cr1 = *cr3; 1285 | stack_len -= 2; 1286 | } 1287 | break; 1288 | case POP_INVERT: 1289 | assert(stack_len >= 1); 1290 | if (cr_invert(&stack[stack_len - 1])) 1291 | goto fail; 1292 | break; 1293 | case POP_END: 1294 | goto done; 1295 | default: 1296 | abort(); 1297 | } 1298 | } 1299 | done: 1300 | assert(stack_len == 1); 1301 | ret = cr_copy(cr, &stack[0]); 1302 | cr_free(&stack[0]); 1303 | return ret; 1304 | fail: 1305 | for(i = 0; i < stack_len; i++) 1306 | cr_free(&stack[i]); 1307 | return -1; 1308 | } 1309 | 1310 | static const uint32_t unicode_gc_mask_table[] = { 1311 | M(Lu) | M(Ll) | M(Lt), /* LC */ 1312 | M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo), /* L */ 1313 | M(Mn) | M(Mc) | M(Me), /* M */ 1314 | M(Nd) | M(Nl) | M(No), /* N */ 1315 | M(Sm) | M(Sc) | M(Sk) | M(So), /* S */ 1316 | M(Pc) | M(Pd) | M(Ps) | M(Pe) | M(Pi) | M(Pf) | M(Po), /* P */ 1317 | M(Zs) | M(Zl) | M(Zp), /* Z */ 1318 | M(Cc) | M(Cf) | M(Cs) | M(Co) | M(Cn), /* C */ 1319 | }; 1320 | 1321 | /* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2 1322 | if not found */ 1323 | int unicode_general_category(CharRange *cr, const char *gc_name) 1324 | { 1325 | int gc_idx; 1326 | uint32_t gc_mask; 1327 | 1328 | gc_idx = unicode_find_name(unicode_gc_name_table, gc_name); 1329 | if (gc_idx < 0) 1330 | return -2; 1331 | if (gc_idx <= UNICODE_GC_Co) { 1332 | gc_mask = (uint64_t)1 << gc_idx; 1333 | } else { 1334 | gc_mask = unicode_gc_mask_table[gc_idx - UNICODE_GC_LC]; 1335 | } 1336 | return unicode_general_category1(cr, gc_mask); 1337 | } 1338 | 1339 | 1340 | /* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2 1341 | if not found */ 1342 | int unicode_prop(CharRange *cr, const char *prop_name) 1343 | { 1344 | int prop_idx, ret; 1345 | 1346 | prop_idx = unicode_find_name(unicode_prop_name_table, prop_name); 1347 | if (prop_idx < 0) 1348 | return -2; 1349 | prop_idx += UNICODE_PROP_ASCII_Hex_Digit; 1350 | 1351 | ret = 0; 1352 | switch(prop_idx) { 1353 | case UNICODE_PROP_ASCII: 1354 | if (cr_add_interval(cr, 0x00, 0x7f + 1)) 1355 | return -1; 1356 | break; 1357 | case UNICODE_PROP_Any: 1358 | if (cr_add_interval(cr, 0x00000, 0x10ffff + 1)) 1359 | return -1; 1360 | break; 1361 | case UNICODE_PROP_Assigned: 1362 | ret = unicode_prop_ops(cr, 1363 | POP_GC, M(Cn), 1364 | POP_INVERT, 1365 | POP_END); 1366 | break; 1367 | case UNICODE_PROP_Math: 1368 | ret = unicode_prop_ops(cr, 1369 | POP_GC, M(Sm), 1370 | POP_PROP, UNICODE_PROP_Other_Math, 1371 | POP_UNION, 1372 | POP_END); 1373 | break; 1374 | case UNICODE_PROP_Lowercase: 1375 | ret = unicode_prop_ops(cr, 1376 | POP_GC, M(Ll), 1377 | POP_PROP, UNICODE_PROP_Other_Lowercase, 1378 | POP_UNION, 1379 | POP_END); 1380 | break; 1381 | case UNICODE_PROP_Uppercase: 1382 | ret = unicode_prop_ops(cr, 1383 | POP_GC, M(Lu), 1384 | POP_PROP, UNICODE_PROP_Other_Uppercase, 1385 | POP_UNION, 1386 | POP_END); 1387 | break; 1388 | case UNICODE_PROP_Cased: 1389 | ret = unicode_prop_ops(cr, 1390 | POP_GC, M(Lu) | M(Ll) | M(Lt), 1391 | POP_PROP, UNICODE_PROP_Other_Uppercase, 1392 | POP_UNION, 1393 | POP_PROP, UNICODE_PROP_Other_Lowercase, 1394 | POP_UNION, 1395 | POP_END); 1396 | break; 1397 | case UNICODE_PROP_Alphabetic: 1398 | ret = unicode_prop_ops(cr, 1399 | POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl), 1400 | POP_PROP, UNICODE_PROP_Other_Uppercase, 1401 | POP_UNION, 1402 | POP_PROP, UNICODE_PROP_Other_Lowercase, 1403 | POP_UNION, 1404 | POP_PROP, UNICODE_PROP_Other_Alphabetic, 1405 | POP_UNION, 1406 | POP_END); 1407 | break; 1408 | case UNICODE_PROP_Grapheme_Base: 1409 | ret = unicode_prop_ops(cr, 1410 | POP_GC, M(Cc) | M(Cf) | M(Cs) | M(Co) | M(Cn) | M(Zl) | M(Zp) | M(Me) | M(Mn), 1411 | POP_PROP, UNICODE_PROP_Other_Grapheme_Extend, 1412 | POP_UNION, 1413 | POP_INVERT, 1414 | POP_END); 1415 | break; 1416 | case UNICODE_PROP_Grapheme_Extend: 1417 | ret = unicode_prop_ops(cr, 1418 | POP_GC, M(Me) | M(Mn), 1419 | POP_PROP, UNICODE_PROP_Other_Grapheme_Extend, 1420 | POP_UNION, 1421 | POP_END); 1422 | break; 1423 | case UNICODE_PROP_XID_Start: 1424 | ret = unicode_prop_ops(cr, 1425 | POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl), 1426 | POP_PROP, UNICODE_PROP_Other_ID_Start, 1427 | POP_UNION, 1428 | POP_PROP, UNICODE_PROP_Pattern_Syntax, 1429 | POP_PROP, UNICODE_PROP_Pattern_White_Space, 1430 | POP_UNION, 1431 | POP_PROP, UNICODE_PROP_XID_Start1, 1432 | POP_UNION, 1433 | POP_INVERT, 1434 | POP_INTER, 1435 | POP_END); 1436 | break; 1437 | case UNICODE_PROP_XID_Continue: 1438 | ret = unicode_prop_ops(cr, 1439 | POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl) | 1440 | M(Mn) | M(Mc) | M(Nd) | M(Pc), 1441 | POP_PROP, UNICODE_PROP_Other_ID_Start, 1442 | POP_UNION, 1443 | POP_PROP, UNICODE_PROP_Other_ID_Continue, 1444 | POP_UNION, 1445 | POP_PROP, UNICODE_PROP_Pattern_Syntax, 1446 | POP_PROP, UNICODE_PROP_Pattern_White_Space, 1447 | POP_UNION, 1448 | POP_PROP, UNICODE_PROP_XID_Continue1, 1449 | POP_UNION, 1450 | POP_INVERT, 1451 | POP_INTER, 1452 | POP_END); 1453 | break; 1454 | case UNICODE_PROP_Changes_When_Uppercased: 1455 | ret = unicode_case1(cr, CASE_U); 1456 | break; 1457 | case UNICODE_PROP_Changes_When_Lowercased: 1458 | ret = unicode_case1(cr, CASE_L); 1459 | break; 1460 | case UNICODE_PROP_Changes_When_Casemapped: 1461 | ret = unicode_case1(cr, CASE_U | CASE_L | CASE_F); 1462 | break; 1463 | case UNICODE_PROP_Changes_When_Titlecased: 1464 | ret = unicode_prop_ops(cr, 1465 | POP_CASE, CASE_U, 1466 | POP_PROP, UNICODE_PROP_Changes_When_Titlecased1, 1467 | POP_XOR, 1468 | POP_END); 1469 | break; 1470 | case UNICODE_PROP_Changes_When_Casefolded: 1471 | ret = unicode_prop_ops(cr, 1472 | POP_CASE, CASE_F, 1473 | POP_PROP, UNICODE_PROP_Changes_When_Casefolded1, 1474 | POP_XOR, 1475 | POP_END); 1476 | break; 1477 | case UNICODE_PROP_Changes_When_NFKC_Casefolded: 1478 | ret = unicode_prop_ops(cr, 1479 | POP_CASE, CASE_F, 1480 | POP_PROP, UNICODE_PROP_Changes_When_NFKC_Casefolded1, 1481 | POP_XOR, 1482 | POP_END); 1483 | break; 1484 | #if 0 1485 | case UNICODE_PROP_ID_Start: 1486 | ret = unicode_prop_ops(cr, 1487 | POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl), 1488 | POP_PROP, UNICODE_PROP_Other_ID_Start, 1489 | POP_UNION, 1490 | POP_PROP, UNICODE_PROP_Pattern_Syntax, 1491 | POP_PROP, UNICODE_PROP_Pattern_White_Space, 1492 | POP_UNION, 1493 | POP_INVERT, 1494 | POP_INTER, 1495 | POP_END); 1496 | break; 1497 | case UNICODE_PROP_ID_Continue: 1498 | ret = unicode_prop_ops(cr, 1499 | POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl) | 1500 | M(Mn) | M(Mc) | M(Nd) | M(Pc), 1501 | POP_PROP, UNICODE_PROP_Other_ID_Start, 1502 | POP_UNION, 1503 | POP_PROP, UNICODE_PROP_Other_ID_Continue, 1504 | POP_UNION, 1505 | POP_PROP, UNICODE_PROP_Pattern_Syntax, 1506 | POP_PROP, UNICODE_PROP_Pattern_White_Space, 1507 | POP_UNION, 1508 | POP_INVERT, 1509 | POP_INTER, 1510 | POP_END); 1511 | break; 1512 | case UNICODE_PROP_Case_Ignorable: 1513 | ret = unicode_prop_ops(cr, 1514 | POP_GC, M(Mn) | M(Cf) | M(Lm) | M(Sk), 1515 | POP_PROP, UNICODE_PROP_Case_Ignorable1, 1516 | POP_XOR, 1517 | POP_END); 1518 | break; 1519 | #else 1520 | /* we use the existing tables */ 1521 | case UNICODE_PROP_ID_Continue: 1522 | ret = unicode_prop_ops(cr, 1523 | POP_PROP, UNICODE_PROP_ID_Start, 1524 | POP_PROP, UNICODE_PROP_ID_Continue1, 1525 | POP_XOR, 1526 | POP_END); 1527 | break; 1528 | #endif 1529 | default: 1530 | if (prop_idx >= countof(unicode_prop_table)) 1531 | return -2; 1532 | ret = unicode_prop1(cr, prop_idx); 1533 | break; 1534 | } 1535 | return ret; 1536 | } 1537 | 1538 | #endif /* CONFIG_ALL_UNICODE */ 1539 | --------------------------------------------------------------------------------