#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <stdint.h>
#include <stdlib.h>
#define MATH_INT64_NATIVE_IF_AVAILABLE
#include "perl_math_int64.h"
#include "qstruct/utils.h"
#include "qstruct/compiler.h"
#include "qstruct/loader.h"
#include "qstruct/builder.h"
typedef
struct
qstruct_definition * Qstruct_Definitions;
typedef
struct
qstruct_item * Qstruct_Item;
typedef
struct
qstruct_builder * Qstruct_Builder;
MODULE = Qstruct PACKAGE = Qstruct
PROTOTYPES: ENABLE
BOOT:
PERL_MATH_INT64_LOAD_OR_CROAK;
Qstruct_Definitions
parse_schema(schema_sv)
SV *schema_sv
CODE:
char
*schema;
size_t
schema_size;
struct
qstruct_definition *def;
char
err_buf[1024];
if
(!SvPOK(schema_sv)) croak(
"schema must be a string"
);
schema_size = SvCUR(schema_sv);
schema = SvPV(schema_sv, schema_size);
def = parse_qstructs(schema, schema_size, err_buf,
sizeof
(err_buf));
if
(!def) croak(
"Qstruct::parse error: %s"
, err_buf);
RETVAL = def;
OUTPUT:
RETVAL
MODULE = Qstruct PACKAGE = Qstruct::Definitions
PROTOTYPES: ENABLE
void
iterate(def, callback)
Qstruct_Definitions def
SV *callback
CODE:
HV *def_info, *items_iterator;
for
(; def; def = def->next) {
ENTER;
SAVETMPS;
PUSHMARK(SP);
def_info = (HV *) sv_2mortal ((SV *) newHV ());
hv_store(def_info,
"def_addr"
, 8, newSViv((
size_t
)def), 0);
hv_store(def_info,
"name"
, 4, newSVpvn(def->name, def->name_len), 0);
hv_store(def_info,
"body_size"
, 9, newSVnv(def->body_size), 0);
hv_store(def_info,
"num_items"
, 9, newSVnv(def->num_items), 0);
XPUSHs(newRV((SV*)def_info));
PUTBACK;
call_sv(callback, G_SCALAR);
FREETMPS;
LEAVE;
}
SV *
get_item(def_addr, item_index)
unsigned
long
def_addr
unsigned
long
item_index
CODE:
Qstruct_Definitions def = (Qstruct_Definitions) def_addr;
HV * rh;
struct
qstruct_item *item = def->items + item_index;
rh = (HV *) sv_2mortal ((SV *) newHV ());
hv_store(rh,
"name"
, 4, newSVpvn(item->name, item->name_len), 0);
hv_store(rh,
"type"
, 4, newSVnv(item->type), 0);
hv_store(rh,
"fixed_array_size"
, 16, newSVnv(item->fixed_array_size), 0);
hv_store(rh,
"byte_offset"
, 11, newSVnv(item->byte_offset), 0);
hv_store(rh,
"bit_offset"
, 10, newSVnv(item->bit_offset), 0);
hv_store(rh,
"nested_type"
, 11, newSVpvn(item->nested_name, item->nested_name_len), 0);
hv_store(rh,
"order"
, 5, newSVnv(item->item_order), 0);
RETVAL = newRV((SV *)rh);
OUTPUT:
RETVAL
void
DESTROY(def)
Qstruct_Definitions def
CODE:
free_qstruct_definitions(def);
MODULE = Qstruct PACKAGE = Qstruct::Runtime
PROTOTYPES: ENABLE
int
sanity_check(buf_sv)
SV *buf_sv
CODE:
char
*buf;
size_t
buf_size;
if
(!SvPOK(buf_sv)) croak(
"buf is not a string"
);
buf_size = SvCUR(buf_sv);
buf = SvPV(buf_sv, buf_size);
RETVAL = qstruct_sanity_check(buf, buf_size);
OUTPUT:
RETVAL
AV *
unpack_header(buf_sv)
SV *buf_sv
CODE:
char
*buf;
size_t
buf_size;
AV *rv;
uint64_t magic_id;
uint32_t body_size, body_count;
int
ret;
if
(!SvPOK(buf_sv)) croak(
"buf is not a string"
);
buf_size = SvCUR(buf_sv);
buf = SvPV(buf_sv, buf_size);
if
(buf_size > 0) {
ret = qstruct_unpack_header(buf, buf_size, &magic_id, &body_size, &body_count);
if
(ret) croak(
"unable to unpack header"
);
}
else
{
magic_id = body_size = body_count;
}
rv = newAV();
sv_2mortal((SV*)rv);
av_push(rv, newSViv(0));
av_push(rv, newSViv(body_size));
av_push(rv, newSViv(body_count));
RETVAL = rv;
OUTPUT:
RETVAL
INCLUDE_COMMAND: $^X gen_getters.pl
int
get_bool(buf_sv, body_index, byte_offset, bit_offset)
SV *buf_sv
uint32_t body_index
uint32_t byte_offset
int
bit_offset
CODE:
char
*buf;
size_t
buf_size;
int
output;
int
ret;
if
(!SvPOK(buf_sv)) croak(
"buf is not a string"
);
buf_size = SvCUR(buf_sv);
buf = SvPV(buf_sv, buf_size);
ret = qstruct_get_bool(buf, buf_size, body_index, byte_offset, bit_offset, &output);
if
(ret) croak(
"malformed qstruct"
);
RETVAL = output;
OUTPUT:
RETVAL
void
get_string(buf_sv, body_index, byte_offset, output_sv)
SV *buf_sv
uint32_t body_index
uint32_t byte_offset
SV *output_sv
CODE:
char
*buf, *output;
size_t
buf_size, output_size;
int
ret;
if
(!SvPOK(buf_sv)) croak(
"buf is not a string"
);
buf_size = SvCUR(buf_sv);
buf = SvPV(buf_sv, buf_size);
ret = qstruct_get_pointer(buf, buf_size, body_index, byte_offset, &output, &output_size, 1);
if
(ret) croak(
"malformed qstruct (%d)"
, ret);
SvUPGRADE(output_sv, SVt_PV);
sv_magicext(output_sv, buf_sv, PERL_MAGIC_ext, NULL, NULL, 0);
SvCUR_set(output_sv, output_size);
SvPV_set(output_sv, output);
SvPOK_only(output_sv);
SvLEN_set(output_sv, 0);
SvREADONLY_on(output_sv);
SvREADONLY_on(buf_sv);
void
get_raw_bytes(buf_sv, body_index, byte_offset, length, output_sv)
SV *buf_sv
uint32_t body_index
uint32_t byte_offset
size_t
length
SV *output_sv
CODE:
char
*buf, *output;
size_t
buf_size, output_size;
int
ret;
if
(!SvPOK(buf_sv)) croak(
"buf is not a string"
);
buf_size = SvCUR(buf_sv);
buf = SvPV(buf_sv, buf_size);
ret = qstruct_get_raw_bytes(buf, buf_size, body_index, byte_offset, length, &output, &output_size);
if
(ret) croak(
"malformed qstruct"
);
SvUPGRADE(output_sv, SVt_PV);
sv_magicext(output_sv, buf_sv, PERL_MAGIC_ext, NULL, NULL, 0);
SvCUR_set(output_sv, output_size);
SvPV_set(output_sv, output);
SvPOK_only(output_sv);
SvLEN_set(output_sv, 0);
SvREADONLY_on(output_sv);
SvREADONLY_on(buf_sv);
MODULE = Qstruct PACKAGE = Qstruct::Builder
PROTOTYPES: ENABLE
Qstruct_Builder
new
(package, magic_id, body_size, body_count)
char
*package
uint64_t magic_id
uint32_t body_size
uint32_t body_count
CODE:
RETVAL = qstruct_builder_new(magic_id, body_size, body_count);
OUTPUT:
RETVAL
INCLUDE_COMMAND: $^X gen_setters.pl
void
set_bool(self, body_index, byte_offset, bit_offset, value)
Qstruct_Builder self
uint32_t body_index
uint32_t byte_offset
int
bit_offset
int
value
CODE:
if
(qstruct_builder_set_bool(self, body_index, byte_offset, bit_offset, value)) croak(
"out of memory"
);
void
set_string(self, body_index, byte_offset, value_sv,
int
alignment)
Qstruct_Builder self
uint32_t body_index
uint32_t byte_offset
SV *value_sv
CODE:
char
*value;
size_t
value_size;
int
ret;
if
(!SvPOK(value_sv)) croak(
"value is not a string"
);
value_size = SvCUR(value_sv);
value = SvPV(value_sv, value_size);
if
(ret = qstruct_builder_set_pointer(self, body_index, byte_offset, value, value_size, alignment, NULL)) croak(
"out of memory (%d)"
, ret);
void
set_raw_bytes(self, body_index, byte_offset, bytes)
Qstruct_Builder self
uint32_t body_index
uint32_t byte_offset
SV *bytes
CODE:
size_t
bytes_size;
char
*bytesp;
if
(!SvPOK(bytes)) croak(
"bytes is not a string"
);
bytes_size = SvCUR(bytes);
bytesp = SvPV(bytes, bytes_size);
if
(qstruct_builder_set_raw_bytes(self, body_index, byte_offset, bytesp, bytes_size)) croak(
"out of memory"
);
SV *
render(builder)
Qstruct_Builder builder
CODE:
char
*msg;
size_t
msg_size;
msg_size = qstruct_builder_get_msg_size(builder);
msg = qstruct_builder_get_buf(builder);
RETVAL = newSVpvn(msg, msg_size);
OUTPUT:
RETVAL
void
DESTROY(builder)
Qstruct_Builder builder
CODE:
qstruct_builder_free(builder);