mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-03 07:29:23 +00:00
Add raw parameter to redbean lua compress
This commit is contained in:
parent
f37524ef4f
commit
3d99ebb68c
4 changed files with 92 additions and 50 deletions
|
@ -30,14 +30,14 @@ char testlib_enable_tmp_setup_teardown;
|
|||
|
||||
TEST(getcwd, test) {
|
||||
char buf[PATH_MAX];
|
||||
EXPECT_NE(-1, mkdir("subdir", 0755));
|
||||
EXPECT_NE(-1, chdir("subdir"));
|
||||
EXPECT_SYS(0, 0, mkdir("subdir", 0755));
|
||||
EXPECT_SYS(0, 0, chdir("subdir"));
|
||||
EXPECT_STREQ("subdir", basename(getcwd(buf, ARRAYLEN(buf))));
|
||||
}
|
||||
|
||||
TEST(getcwd, testNullBuf_allocatesResult) {
|
||||
EXPECT_NE(-1, mkdir("subdir", 0755));
|
||||
EXPECT_NE(-1, chdir("subdir"));
|
||||
EXPECT_SYS(0, 0, mkdir("subdir", 0755));
|
||||
EXPECT_SYS(0, 0, chdir("subdir"));
|
||||
EXPECT_STREQ("subdir", basename(gc(getcwd(0, 0))));
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
@ -34,6 +35,7 @@ struct sigaction oldsa;
|
|||
volatile bool gotsigint;
|
||||
|
||||
void OnSigInt(int sig) {
|
||||
_checkstackalign();
|
||||
gotsigint = true;
|
||||
}
|
||||
|
||||
|
@ -46,11 +48,11 @@ void SetUp(void) {
|
|||
|
||||
TEST(sigaction, raise) {
|
||||
struct sigaction saint = {.sa_handler = OnSigInt};
|
||||
EXPECT_NE(-1, sigaction(SIGINT, &saint, &oldsa));
|
||||
EXPECT_SYS(0, 0, sigaction(SIGINT, &saint, &oldsa));
|
||||
ASSERT_FALSE(gotsigint);
|
||||
EXPECT_NE(-1, raise(SIGINT));
|
||||
ASSERT_TRUE(gotsigint);
|
||||
EXPECT_NE(-1, sigaction(SIGINT, &oldsa, NULL));
|
||||
EXPECT_SYS(0, 0, sigaction(SIGINT, &oldsa, NULL));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -68,37 +70,36 @@ TEST(sigaction, testPingPongParentChildWithSigint) {
|
|||
// kind of runner. todo(fixme!)
|
||||
return;
|
||||
}
|
||||
EXPECT_NE(-1, sigemptyset(&blockint));
|
||||
EXPECT_NE(-1, sigaddset(&blockint, SIGINT));
|
||||
EXPECT_NE(-1, sigprocmask(SIG_BLOCK, &blockint, &oldmask));
|
||||
EXPECT_NE(-1, sigaction(SIGINT, &catchint, &oldint));
|
||||
EXPECT_SYS(0, 0, sigemptyset(&blockint));
|
||||
EXPECT_SYS(0, 0, sigaddset(&blockint, SIGINT));
|
||||
EXPECT_SYS(0, 0, sigprocmask(SIG_BLOCK, &blockint, &oldmask));
|
||||
EXPECT_SYS(0, 0, sigaction(SIGINT, &catchint, &oldint));
|
||||
ASSERT_NE(-1, (pid = fork()));
|
||||
if (!pid) {
|
||||
// ping
|
||||
EXPECT_NE(-1, kill(getppid(), SIGINT));
|
||||
EXPECT_SYS(0, 0, kill(getppid(), SIGINT));
|
||||
EXPECT_FALSE(gotsigint);
|
||||
// pong
|
||||
EXPECT_NE(-1, sigaction(SIGINT, &catchint, 0));
|
||||
EXPECT_EQ(-1, sigsuspend(0));
|
||||
EXPECT_EQ(EINTR, errno);
|
||||
EXPECT_SYS(0, 0, sigaction(SIGINT, &catchint, 0));
|
||||
EXPECT_SYS(EINTR, -1, sigsuspend(0));
|
||||
EXPECT_TRUE(gotsigint);
|
||||
_exit(0);
|
||||
}
|
||||
// pong
|
||||
EXPECT_FALSE(gotsigint);
|
||||
EXPECT_NE(-1, sigaction(SIGINT, &catchint, 0));
|
||||
EXPECT_EQ(-1, sigsuspend(0));
|
||||
EXPECT_SYS(0, 0, sigaction(SIGINT, &catchint, 0));
|
||||
EXPECT_SYS(EINTR, -1, sigsuspend(0));
|
||||
EXPECT_TRUE(gotsigint);
|
||||
// ping
|
||||
EXPECT_NE(-1, sigaction(SIGINT, &ignoreint, 0));
|
||||
EXPECT_NE(-1, kill(pid, SIGINT));
|
||||
EXPECT_SYS(0, 0, sigaction(SIGINT, &ignoreint, 0));
|
||||
EXPECT_SYS(0, 0, kill(pid, SIGINT));
|
||||
// cleanup
|
||||
EXPECT_NE(-1, wait4(pid, &status, 0, 0));
|
||||
EXPECT_EQ(1, WIFEXITED(status));
|
||||
EXPECT_EQ(0, WEXITSTATUS(status));
|
||||
EXPECT_EQ(0, WTERMSIG(status));
|
||||
EXPECT_NE(-1, sigaction(SIGINT, &oldint, 0));
|
||||
EXPECT_NE(-1, sigprocmask(SIG_BLOCK, &oldmask, 0));
|
||||
EXPECT_SYS(0, 0, sigaction(SIGINT, &oldint, 0));
|
||||
EXPECT_SYS(0, 0, sigprocmask(SIG_BLOCK, &oldmask, 0));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -108,6 +109,7 @@ TEST(sigaction, testPingPongParentChildWithSigint) {
|
|||
volatile int trapeax;
|
||||
|
||||
void OnTrap(int sig, struct siginfo *si, struct ucontext *ctx) {
|
||||
_checkstackalign();
|
||||
trapeax = ctx->uc_mcontext.rax;
|
||||
}
|
||||
|
||||
|
@ -116,7 +118,7 @@ TEST(sigaction, debugBreak_handlerCanReadCpuState) {
|
|||
EXPECT_NE(-1, sigaction(SIGTRAP, &saint, &oldsa));
|
||||
asm("int3" : /* no outputs */ : "a"(0x31337));
|
||||
EXPECT_EQ(0x31337, trapeax);
|
||||
EXPECT_NE(-1, sigaction(SIGTRAP, &oldsa, NULL));
|
||||
EXPECT_SYS(0, 0, sigaction(SIGTRAP, &oldsa, NULL));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -124,6 +126,7 @@ TEST(sigaction, debugBreak_handlerCanReadCpuState) {
|
|||
// test signal handler can modify cpu registers (now it's recoverable!)
|
||||
|
||||
void SkipOverFaultingInstruction(struct ucontext *ctx) {
|
||||
_checkstackalign();
|
||||
struct XedDecodedInst xedd;
|
||||
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64);
|
||||
xed_instruction_length_decode(&xedd, (void *)ctx->uc_mcontext.rip, 15);
|
||||
|
@ -131,6 +134,7 @@ void SkipOverFaultingInstruction(struct ucontext *ctx) {
|
|||
}
|
||||
|
||||
void OnFpe(int sig, struct siginfo *si, struct ucontext *ctx) {
|
||||
_checkstackalign();
|
||||
SkipOverFaultingInstruction(ctx);
|
||||
ctx->uc_mcontext.rax = 42;
|
||||
ctx->uc_mcontext.rdx = 0;
|
||||
|
@ -138,10 +142,10 @@ void OnFpe(int sig, struct siginfo *si, struct ucontext *ctx) {
|
|||
|
||||
noubsan void ubsanTrumpsSystemsEngineering(void) {
|
||||
struct sigaction saint = {.sa_sigaction = OnFpe, .sa_flags = SA_SIGINFO};
|
||||
EXPECT_NE(-1, sigaction(SIGFPE, &saint, &oldsa));
|
||||
EXPECT_SYS(0, 0, sigaction(SIGFPE, &saint, &oldsa));
|
||||
volatile long x = 0;
|
||||
EXPECT_EQ(42, 666 / x); /* systems engineering trumps math */
|
||||
EXPECT_NE(-1, sigaction(SIGFPE, &oldsa, NULL));
|
||||
EXPECT_SYS(0, 0, sigaction(SIGFPE, &oldsa, NULL));
|
||||
}
|
||||
|
||||
TEST(sigaction, sigFpe_handlerCanEditProcessStateAndRecoverExecution) {
|
||||
|
|
|
@ -1308,7 +1308,7 @@ FUNCTIONS
|
|||
the density of information. Cryptographic random should be in
|
||||
the ballpark of 7.9 whereas plaintext will be more like 4.5.
|
||||
|
||||
Compress(uncompdata:str[, level:int]) → compdata:str
|
||||
Compress(uncompdata:str[, level:int[, raw:bool]]) → compdata:str
|
||||
|
||||
Compresses data using DEFLATE algorithm. The compression
|
||||
format here is defined to be quick and handy for things like
|
||||
|
@ -1319,18 +1319,27 @@ FUNCTIONS
|
|||
>: Uncompress(Compress('hello'))
|
||||
"hello"
|
||||
|
||||
`level` is the compression level, which defaults to 7. The max
|
||||
is 10. Lower numbers go faster. Higher numbers go slower, but
|
||||
have better compression ratios.
|
||||
|
||||
[implementation details]
|
||||
The binary wire format is defined as follows:
|
||||
|
||||
1. uleb64 uncompressed byte size (1 to 10 bytes)
|
||||
2. uint32_t crc32 (4 bytes; zlib polynomial)
|
||||
3. data (created by zlib compress function)
|
||||
|
||||
Uncompress(compdata:str) → uncompdata:str
|
||||
`level` is the compression level, which defaults to 7. The max
|
||||
is 10. Lower numbers go faster. Higher numbers go slower, but
|
||||
have better compression ratios.
|
||||
|
||||
`raw` may be set to true if you only want `data` (3) to be
|
||||
returned. In this case, it's assumed the caller will take
|
||||
responsibility for storing the length (and optionall crc)
|
||||
separately. See the redbean Crc32() API.
|
||||
|
||||
>: a = 'hello'
|
||||
>: b = Compress(a, 9, true)
|
||||
>: Uncompress(b, #a)
|
||||
"hello"
|
||||
|
||||
Uncompress(compdata:str[, uncomplen:int]) → uncompdata:str
|
||||
|
||||
Uncompresses data using DEFLATE algorithm. This applies the
|
||||
inverse transform of the Compress() function. See its docs for
|
||||
|
@ -1341,6 +1350,15 @@ FUNCTIONS
|
|||
of validity iron-clad. It's implemented using Intel CLMUL so
|
||||
it has ludicrous speed performance as well.
|
||||
|
||||
If you used the `raw` parameter when calling Compress() i.e.
|
||||
`compdata` doesn't have the redbean header described above,
|
||||
then the `uncomplen` parameter may be supplied. IN that case
|
||||
your data is handed over directly to zlib `uncompress()`. In
|
||||
this case an exception will be raised if the value couldn't be
|
||||
decoded, or if the resulting length differed from the supplied
|
||||
length. It's recommended that Crc32() check still be performed
|
||||
manually after using this method.
|
||||
|
||||
Benchmark(func[, count[, maxattempts]])
|
||||
└─→ nanos:real, ticks:int, overhead-ticks:int, tries:int
|
||||
|
||||
|
|
|
@ -683,6 +683,7 @@ int LuaBenchmark(lua_State *L) {
|
|||
}
|
||||
|
||||
int LuaCompress(lua_State *L) {
|
||||
bool raw;
|
||||
size_t n, m;
|
||||
char *q, *e;
|
||||
uint32_t crc;
|
||||
|
@ -691,14 +692,23 @@ int LuaCompress(lua_State *L) {
|
|||
p = luaL_checklstring(L, 1, &n);
|
||||
level = luaL_optinteger(L, 2, Z_DEFAULT_COMPRESSION);
|
||||
m = compressBound(n);
|
||||
CHECK_NOTNULL((q = LuaAlloc(L, 10 + 4 + m)));
|
||||
crc = crc32_z(0, p, n);
|
||||
e = uleb64(q, n);
|
||||
e = WRITE32LE(e, crc);
|
||||
hdrlen = e - q;
|
||||
CHECK_EQ(Z_OK, compress2((unsigned char *)(q + hdrlen), &m,
|
||||
(unsigned char *)p, n, level));
|
||||
lua_pushlstring(L, q, hdrlen + m);
|
||||
if (lua_toboolean(L, 3)) {
|
||||
// raw mode
|
||||
CHECK_NOTNULL((q = LuaAlloc(L, m)));
|
||||
CHECK_EQ(Z_OK,
|
||||
compress2((unsigned char *)q, &m, (unsigned char *)p, n, level));
|
||||
lua_pushlstring(L, q, m);
|
||||
} else {
|
||||
// easy mode
|
||||
CHECK_NOTNULL((q = LuaAlloc(L, 10 + 4 + m)));
|
||||
crc = crc32_z(0, p, n);
|
||||
e = uleb64(q, n);
|
||||
e = WRITE32LE(e, crc);
|
||||
hdrlen = e - q;
|
||||
CHECK_EQ(Z_OK, compress2((unsigned char *)(q + hdrlen), &m,
|
||||
(unsigned char *)p, n, level));
|
||||
lua_pushlstring(L, q, hdrlen + m);
|
||||
}
|
||||
free(q);
|
||||
return 1;
|
||||
}
|
||||
|
@ -710,18 +720,28 @@ int LuaUncompress(lua_State *L) {
|
|||
const char *p;
|
||||
size_t n, m, len;
|
||||
p = luaL_checklstring(L, 1, &n);
|
||||
if ((rc = unuleb64(p, n, &m)) == -1 || n < rc + 4) {
|
||||
luaL_error(L, "compressed value too short to be valid");
|
||||
unreachable;
|
||||
}
|
||||
len = m;
|
||||
crc = READ32LE(p + rc);
|
||||
CHECK_NOTNULL((q = LuaAlloc(L, m)));
|
||||
if (uncompress((void *)q, &m, (unsigned char *)p + rc + 4, n) != Z_OK ||
|
||||
m != len || crc32_z(0, q, m) != crc) {
|
||||
free(q);
|
||||
luaL_error(L, "compressed value is corrupted");
|
||||
unreachable;
|
||||
if (lua_isnoneornil(L, 2)) {
|
||||
if ((rc = unuleb64(p, n, &m)) == -1 || n < rc + 4) {
|
||||
luaL_error(L, "compressed value too short to be valid");
|
||||
unreachable;
|
||||
}
|
||||
len = m;
|
||||
crc = READ32LE(p + rc);
|
||||
CHECK_NOTNULL((q = LuaAlloc(L, m)));
|
||||
if (uncompress((void *)q, &m, (unsigned char *)p + rc + 4, n) != Z_OK ||
|
||||
m != len || crc32_z(0, q, m) != crc) {
|
||||
free(q);
|
||||
luaL_error(L, "compressed value is corrupted");
|
||||
unreachable;
|
||||
}
|
||||
} else {
|
||||
len = m = luaL_checkinteger(L, 2);
|
||||
CHECK_NOTNULL((q = LuaAlloc(L, m)));
|
||||
if (uncompress((void *)q, &m, (void *)p, n) != Z_OK || m != len) {
|
||||
free(q);
|
||||
luaL_error(L, "compressed value is corrupted");
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
lua_pushlstring(L, q, m);
|
||||
free(q);
|
||||
|
|
Loading…
Add table
Reference in a new issue