File-Raw-JSON
view release on metacpan or search on metacpan
}
/* ============================================================
* Plugin phase functions
* ============================================================ */
/* Per-plugin state pointers (so the plugin descriptor can carry mode). */
static json_mode_t MODE_DOCUMENT_TAG = JSON_MODE_DOCUMENT;
static json_mode_t MODE_LINES_TAG = JSON_MODE_LINES;
static SV *
json_read(pTHX_ FilePluginContext *ctx)
{
json_options_t o;
const char *boolean_class;
HV *bool_stash;
STRLEN len;
const char *pv;
json_options_defaults(&o);
if (ctx->plugin_state)
o.mode = *(const json_mode_t *)ctx->plugin_state;
boolean_class = decode_opts(aTHX_ ctx->options, &o);
bool_stash = resolve_boolean_stash(aTHX_ boolean_class);
if (!ctx->data) return &PL_sv_undef;
pv = SvPV(ctx->data, len);
if (o.mode == JSON_MODE_LINES) {
AV *av = json_decode_lines(aTHX_ pv, len, &o, bool_stash);
return newRV_noinc((SV *)av);
}
return json_decode_document(aTHX_ pv, len, &o, bool_stash);
}
static SV *
json_write(pTHX_ FilePluginContext *ctx)
{
json_options_t o;
json_options_defaults(&o);
if (ctx->plugin_state)
o.mode = *(const json_mode_t *)ctx->plugin_state;
(void)decode_opts(aTHX_ ctx->options, &o);
if (o.mode == JSON_MODE_LINES) {
return json_encode_lines(aTHX_ ctx->data, &o);
}
return json_encode_document(aTHX_ ctx->data, &o);
}
/* The 'json' plugin rejects STREAM with a helpful redirect. */
static int
json_stream_reject(pTHX_ FilePluginContext *ctx,
const char *chunk, size_t len, int eof)
{
PERL_UNUSED_ARG(chunk);
PERL_UNUSED_ARG(len);
PERL_UNUSED_ARG(eof);
ctx->cancel = 1;
croak("File::Raw::JSON: the 'json' plugin does not support streaming; "
"use 'jsonl' for concatenated JSON values, or slurp the whole "
"document via File::Raw::slurp(...)");
return 1;
}
/* ============================================================
* jsonl streaming
*
* Buffers bytes across chunks; brace-balancer slices off complete
* top-level values; each is parsed by yyjson and emitted via
* call_sv(ctx->callback, ...). Mirrors File::Raw::Separated's
* sep_stream pattern. State lives in ctx->call_state. */
typedef struct {
char *acc_buf;
STRLEN acc_len;
STRLEN acc_cap;
json_options_t opts;
HV *bool_stash;
SV *die_msg; /* propagation slot */
} jsonl_stream_state_t;
static void
jsonl_stream_state_free(pTHX_ jsonl_stream_state_t *s)
{
if (!s) return;
if (s->acc_buf) Safefree(s->acc_buf);
if (s->die_msg) SvREFCNT_dec(s->die_msg);
Safefree(s);
}
static void
jsonl_acc_append(pTHX_ jsonl_stream_state_t *s, const char *p, STRLEN n)
{
if (s->acc_len + n > s->acc_cap) {
STRLEN newcap = s->acc_cap ? s->acc_cap : 8192;
while (newcap < s->acc_len + n) newcap *= 2;
Renew(s->acc_buf, newcap, char);
s->acc_cap = newcap;
}
if (n) memcpy(s->acc_buf + s->acc_len, p, n);
s->acc_len += n;
}
static int
jsonl_emit_one(pTHX_ FilePluginContext *ctx, jsonl_stream_state_t *s,
const char *vp, STRLEN vlen)
{
yyjson_read_err err;
yyjson_doc *doc;
SV *value;
int count, rc = 0;
SV *errsv;
doc = yyjson_read_opts((char *)vp, (size_t)vlen,
0, NULL, &err);
if (!doc) {
char ctx_buf[64];
STRLEN copy_len = vlen < sizeof(ctx_buf) - 1
? vlen : sizeof(ctx_buf) - 1;
memcpy(ctx_buf, vp, copy_len);
ctx_buf[copy_len] = '\0';
ctx->cancel = 1;
croak("File::Raw::JSON: stream parse error: %s near \"%s\"",
err.msg ? err.msg : "unknown", ctx_buf);
}
value = json_sv_from_yyjson(aTHX_ yyjson_doc_get_root(doc),
( run in 1.063 second using v1.01-cache-2.11-cpan-140bd7fdf52 )