ClickHouse-Encoder
view release on metacpan or search on metacpan
RETVAL = (UV)(av_len(s->buffer) + 1);
}
OUTPUT:
RETVAL
bool
is_empty(self)
SV *self
CODE:
{
Streamer *s;
if (!sv_isobject(self)) croak("Not an object");
s = INT2PTR(Streamer *, SvIV(SvRV(self)));
RETVAL = (av_len(s->buffer) < 0);
}
OUTPUT:
RETVAL
void
DESTROY(self)
SV *self
CODE:
{
Streamer *s;
if (!sv_isobject(self)) return;
s = INT2PTR(Streamer *, SvIV(SvRV(self)));
free_streamer(aTHX_ s);
}
MODULE = ClickHouse::Encoder PACKAGE = ClickHouse::Encoder::TCP
# Pack an unsigned varint (LEB128 / CH varuint form). Used by the
# protocol-packet builders in ClickHouse::Encoder::TCP. Equivalent
# to the buf_varint() internal helper but exposed as a Perl callable
# so the pure-Perl module can produce wire-format bytes via XS rather
# than a per-byte chr/shift loop.
SV *
pack_varint(v)
UV v
CODE:
{
char buf[10];
int i = 0;
while (v >= 0x80) {
buf[i++] = (char)((v & 0x7f) | 0x80);
v >>= 7;
}
buf[i++] = (char)v;
RETVAL = newSVpvn(buf, i);
}
OUTPUT:
RETVAL
# Unpack one varint from a byte string starting at the given offset.
# Returns (value, new_offset). Croaks on truncated input or a varint
# wider than 64 bits.
void
unpack_varint(bytes, offset)
SV *bytes
UV offset
PPCODE:
{
STRLEN len;
const unsigned char *p = (const unsigned char *)SvPVbyte(bytes, len);
UV v = tcp_read_varint(aTHX_ p, (UV)len, &offset);
EXTEND(SP, 2);
PUSHs(sv_2mortal(newSVuv(v)));
PUSHs(sv_2mortal(newSVuv(offset)));
}
# Pack a length-prefixed string (varint length + UTF-8 bytes). The
# caller should pass Perl strings; we encode to UTF-8 explicitly so
# non-ASCII chars get the right byte length on the wire.
SV *
pack_string(s)
SV *s
CODE:
{
STRLEN len;
const char *p;
if (!SvOK(s)) {
p = ""; len = 0;
} else {
/* SvPVutf8 returns the UTF-8 byte form */
p = SvPVutf8(s, len);
}
/* Build prefix + bytes. */
char prefix[10];
int pi = 0;
UV vv = (UV)len;
while (vv >= 0x80) {
prefix[pi++] = (char)((vv & 0x7f) | 0x80);
vv >>= 7;
}
prefix[pi++] = (char)vv;
RETVAL = newSVpvn(prefix, pi);
sv_catpvn(RETVAL, p, len);
}
OUTPUT:
RETVAL
# Unpack a length-prefixed string at the given offset. Returns (string,
# new_offset). String bytes are returned without decoding (caller
# decides UTF-8 vs binary).
void
unpack_string(bytes, offset)
SV *bytes
UV offset
PPCODE:
{
STRLEN buf_len;
const unsigned char *p = (const unsigned char *)SvPVbyte(bytes, buf_len);
UV slen = tcp_read_varint(aTHX_ p, (UV)buf_len, &offset);
/* Subtraction form: addition (offset + slen) can wrap UV_MAX when
* slen is attacker-controlled via a crafted varint. tcp_read_varint
* guarantees offset <= buf_len on return, so buf_len - offset is
* safe. */
if (slen > (UV)buf_len - offset)
croak("string: truncated at offset %lu (need %lu)",
(unsigned long)offset, (unsigned long)slen);
SV *out = newSVpvn((const char *)(p + offset), (STRLEN)slen);
EXTEND(SP, 2);
PUSHs(sv_2mortal(out));
PUSHs(sv_2mortal(newSVuv(offset + slen)));
}
( run in 2.415 seconds using v1.01-cache-2.11-cpan-71847e10f99 )