#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include #include #include #include #include #include #define NEED_newRV_noinc #define NEED_sv_2pv_flags #include "ppport.h" typedef yajl_handle JSON__YAJL__Parser; int DEBUG = 0; void callback_call(SV* hashref, unsigned int index) { HV* hash; SV** array_p; SV* arrayref; AV* array; SV** callback_p; SV* callbackref; SV* callback; dSP; if (!SvOK((SV*) hashref)) { Perl_croak(aTHX_ "YAJL: hashref is not defined"); } else { DEBUG && printf(" hashref is defined\n"); } if (!SvROK((SV*) hashref)) { Perl_croak(aTHX_ "YAJL: hashref is not a reference"); } else { DEBUG && printf(" hashref is a reference\n"); } hash = (HV*) SvRV((SV*) hashref); if (SvTYPE(hash) != SVt_PVHV) { Perl_croak(aTHX_ "YAJL: hash is not a PVHV"); } else { DEBUG && printf(" hash is a PVHV\n"); } array_p = hv_fetchs(hash, "array", 0); if (array_p == NULL) { Perl_croak(aTHX_ "YAJL: array_p is NULL"); } else { DEBUG && printf(" array_p is not NULL\n"); } arrayref = (SV*) *array_p; if (!SvROK(arrayref)) { printf("type is %i\n", SvTYPE(arrayref)); Perl_croak(aTHX_ "YAJL: arrayref is not a reference"); } else { DEBUG && printf(" arrayref is a reference\n"); } array = (AV*) SvRV(arrayref); if (SvTYPE(array) != SVt_PVAV) { printf("type is %i\n", SvTYPE(array)); Perl_croak(aTHX_ "YAJL: array is not a PVAV"); } else { DEBUG && printf(" array is a PVAV\n"); } callback_p = av_fetch(array, index, 0); if (callback_p == NULL) { DEBUG && printf(" nothing in array slot\n"); return; } else { DEBUG && printf(" something in array slot\n"); } callbackref = (SV*) *callback_p; if (!SvROK((SV*) callbackref)) { Perl_croak(aTHX_ "YAJL: callbackref is not a reference"); } else { DEBUG && printf(" callbackref is a reference\n"); } callback = (SV*) SvRV((SV*) callbackref); if (SvTYPE(callback) != SVt_PVCV) { Perl_croak(aTHX_ "YAJL: callback is not a PVCV"); } else { DEBUG && printf(" callback is a PVCV\n"); } DEBUG && printf(" about to call callback\n"); call_sv(callback, G_DISCARD); FREETMPS; LEAVE; } static int callback_null(void * hashref) { DEBUG && printf("null\n"); dSP; ENTER; SAVETMPS; PUSHMARK(SP); PUTBACK; callback_call((SV*) hashref, 0); return 1; } static int callback_boolean(void * hashref, int boolean) { DEBUG && printf("boolean %i\n", boolean); dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSViv(boolean))); PUTBACK; callback_call((SV*) hashref, 1); return 1; } static int callback_number(void * hashref, const char * s, size_t l) { DEBUG && printf("number %.*s\n", (int)l, s); dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(s, l))); PUTBACK; callback_call((SV*) hashref, 4); return 1; } static int callback_string(void * hashref, const unsigned char * s, size_t l) { DEBUG && printf("string %.*s\n", (int)l, s); dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv((char *)s, l))); PUTBACK; callback_call((SV*) hashref, 5); return 1; } static int callback_map_open(void * hashref) { DEBUG && printf("map_open\n"); dSP; ENTER; SAVETMPS; PUSHMARK(SP); PUTBACK; callback_call((SV*) hashref, 6); return 1; } static int callback_map_key(void * hashref, const unsigned char * s, size_t l) { DEBUG && printf("map_key %.*s\n", (int)l, s); dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv((char *)s, l))); PUTBACK; callback_call((SV*) hashref, 7); return 1; } static int callback_map_close(void * hashref) { DEBUG && printf("map_close\n"); dSP; ENTER; SAVETMPS; PUSHMARK(SP); PUTBACK; callback_call((SV*) hashref, 8); return 1; } static int callback_array_open(void * hashref) { DEBUG && printf("array_open\n"); dSP; ENTER; SAVETMPS; PUSHMARK(SP); PUTBACK; callback_call((SV*) hashref, 9); return 1; } static int callback_array_close(void * hashref) { DEBUG && printf("array_close\n"); dSP; ENTER; SAVETMPS; PUSHMARK(SP); PUTBACK; callback_call((SV*) hashref, 10); return 1; } static yajl_callbacks callbacks = { callback_null, callback_boolean, NULL, NULL, callback_number, callback_string, callback_map_open, callback_map_key, callback_map_close, callback_array_open, callback_array_close, }; MODULE = JSON::YAJL::Parser PACKAGE = JSON::YAJL::Parser JSON::YAJL::Parser new(package, unsigned int allowComments = 0, unsigned int checkUTF8 = 0, SV* arrayref) CODE: yajl_handle parser; AV* array; HV *hash = newHV(); (void)hv_stores(hash, "data", newSVpv("", 0)); SvREFCNT_inc_void(arrayref); if (!SvROK(arrayref)) { printf("type is %i\n", SvTYPE(arrayref)); Perl_croak(aTHX_ "YAJL: arrayref is not a reference"); } else { DEBUG && printf("arrayref is a reference\n"); } array = (AV*) SvRV(arrayref); if (SvTYPE(array) != SVt_PVAV) { printf("type is %i\n", SvTYPE(array)); Perl_croak(aTHX_ "YAJL: array is not a PVAV"); } else { DEBUG && printf("array is an PVAV\n"); } (void)hv_stores(hash, "array", arrayref); SV *hashref = newRV_noinc((SV*)hash); parser = yajl_alloc(&callbacks, NULL, (void *) hashref); yajl_config(parser, yajl_allow_comments, allowComments); yajl_config(parser, yajl_dont_validate_strings, !checkUTF8); RETVAL = parser; OUTPUT: RETVAL void parse(JSON::YAJL::Parser parser, SV* data) CODE: const char * jsonText; unsigned int jsonTextLength; yajl_status status; unsigned char * error; SV* hashref; HV* hash; SV** dataref; jsonText = SvPV_nolen(data); jsonTextLength = SvCUR(data); status = yajl_parse(parser, (unsigned char*)jsonText, jsonTextLength); if (status != yajl_status_ok) { error = yajl_get_error(parser, 1, (unsigned char*)jsonText, jsonTextLength); Perl_croak(aTHX_ "%s", error); yajl_free_error(parser, error); } else { hashref = (SV*) parser->ctx; hash = (HV*) SvRV(hashref); (void)hv_stores(hash, "data", data); } void parse_complete(JSON::YAJL::Parser parser) CODE: yajl_status status; unsigned char * error; const char * jsonText; unsigned int jsonTextLength; SV* hashref; HV* hash; SV** dataref; SV* data; status = yajl_complete_parse(parser); if (status != yajl_status_ok) { hashref = (SV*) parser->ctx; hash = (HV*) SvRV(hashref); dataref = hv_fetchs(hash, "data", 0); data = (SV*) *dataref; jsonText = SvPV_nolen(data); jsonTextLength = SvCUR(data); error = yajl_get_error(parser, 1, (unsigned char*)jsonText, jsonTextLength); Perl_croak(aTHX_ "%s", error); yajl_free_error(parser, error); } void DESTROY(JSON::YAJL::Parser parser) CODE: SV* hashref; HV* hash; SV** array_p; SV* arrayref; hashref = (SV*) parser->ctx; hash = (HV*) SvRV(hashref); array_p = hv_fetchs(hash, "array", 0); if (array_p == NULL) { Perl_croak(aTHX_ "YAJL: DESTROY array_p is NULL"); } else { DEBUG && printf("destroy array_p is not NULL\n"); } arrayref = (SV*) *array_p; if (!SvROK(arrayref)) { printf("type is %i\n", SvTYPE(arrayref)); Perl_croak(aTHX_ "YAJL: DESTROY arrayref is not a reference"); } else { DEBUG && printf("destroy arrayref is a reference\n"); } SvREFCNT_dec(arrayref); DEBUG && printf("decreased refcount of arrayref\n"); yajl_free(parser);