SRL_STATIC_INLINE void srl_set_input_buffer(pTHX_ srl_merger_t *mrg, SV *src) { STRLEN len; UV header_len; U8 encoding_flags; U8 protocol_version; srl_buffer_char *tmp; IV proto_version_and_encoding_flags_int; SRL_RDR_CLEAR(&mrg->ibuf); tmp = (srl_buffer_char*) SvPV(src, len); mrg->ibuf.start = mrg->ibuf.pos = tmp; mrg->ibuf.end = mrg->ibuf.start + len; proto_version_and_encoding_flags_int = srl_validate_header_version(aTHX_ (srl_reader_char_ptr) mrg->ibuf.start, len); if (proto_version_and_encoding_flags_int < 1) { if (proto_version_and_encoding_flags_int == 0) SRL_RDR_ERROR(mrg->pibuf, "Bad Sereal header: It seems your document was accidentally UTF-8 encoded"); else SRL_RDR_ERROR(mrg->pibuf, "Bad Sereal header: Not a valid Sereal document."); } mrg->ibuf.pos += 5; encoding_flags = (U8) (proto_version_and_encoding_flags_int & SRL_PROTOCOL_ENCODING_MASK); protocol_version = (U8) (proto_version_and_encoding_flags_int & SRL_PROTOCOL_VERSION_MASK); if (expect_false(protocol_version > 3 || protocol_version < 1)) { SRL_RDR_ERRORf1(mrg->pibuf, "Unsupported Sereal protocol version %u", (unsigned int) protocol_version); } // skip header in any case header_len = srl_read_varint_uv_length(aTHX_ mrg->pibuf, " while reading header"); mrg->ibuf.pos += header_len; if (encoding_flags == SRL_PROTOCOL_ENCODING_RAW) { /* no op */ } else if ( encoding_flags == SRL_PROTOCOL_ENCODING_SNAPPY || encoding_flags == SRL_PROTOCOL_ENCODING_SNAPPY_INCREMENTAL) { srl_decompress_body_snappy(aTHX_ mrg->pibuf, encoding_flags, NULL); } else if (encoding_flags == SRL_PROTOCOL_ENCODING_ZLIB) { srl_decompress_body_zlib(aTHX_ mrg->pibuf, NULL); } else { SRL_RDR_ERROR(mrg->pibuf, "Sereal document encoded in an unknown format"); } /* this functions *MUST* be called after srl_decompress_body* */ SRL_RDR_UPDATE_BODY_POS(mrg->pibuf, protocol_version); DEBUG_ASSERT_RDR_SANE(mrg->pibuf); }
int bck_read( void* handle, char* buf, int len ){ char *eot = ((CHILD*)handle)->cph_eot; int eot_len = strlen(eot); if( len ){ if( !strncmp( buf, eot, len ) ){ _dbg(F,L,3, "logical end of stdin from %s", ((CHILD*)handle)->cph_cmd ); return NPOLL_RET_IDLE; } else if (!strncmp(eot, buf+len-eot_len, eot_len)) { len -= eot_len; _dbg(F,L,3, "unterminated end of stdin from %s", ((CHILD*)handle)->cph_cmd ); _dbg(F,L,2, "<<-- %.*s", len, buf); Perl_av_push( aTHX_ ((CHILD*)handle)->cph_out_array , Perl_newSVpv( aTHX_ buf, len ) ); return NPOLL_RET_IDLE; } else { _dbg(F,L,2, "<<-- %.*s", len, buf); Perl_av_push( aTHX_ ((CHILD*)handle)->cph_out_array , Perl_newSVpv( aTHX_ buf, len ) ); return NPOLL_CONTINUE; } } else { _dbg(F,L,3, "eof on stdin from %s", ((CHILD*)handle)->cph_cmd ); return NPOLL_RET_IDLE; } }
int err_read( void* handle, char* buf, int len ){ if( len ){ /* * Interrupt handling doesn't work quite right. As yet undiagnosed * but this code is left in because it's no worse than not having it. */ if( !strncmp( buf, "Interrupt", 9 ) ){ _dbg(F,L,3, "interrupted end of cmd from %s", ((CHILD*)handle)->cph_cmd ); return NPOLL_RET_IDLE; } else { _dbg(F,L,2, "<<== '%.*s'", len, buf); Perl_av_push( aTHX_ ((CHILD*)handle)->cph_err_array , Perl_newSVpv( aTHX_ buf, len ) ); return NPOLL_CONTINUE; } } else { return NPOLL_RET_IDLE; } }
SV * srl_merger_finish(pTHX_ srl_merger_t *mrg, SV *user_header_src) { UV end_offset; UV body_offset; UV srl_start_offset = 0; DEBUG_ASSERT_BUF_SANE(&mrg->obuf); if (mrg->obuf_last_successfull_offset) { SRL_MERGER_TRACE("last merge operation has failed, reset to offset %"UVuf"", mrg->obuf_last_successfull_offset); mrg->obuf.pos = mrg->obuf.body_pos + mrg->obuf_last_successfull_offset; DEBUG_ASSERT_BUF_SANE(&mrg->obuf); } /* store offset to the end of the document */ end_offset = BODY_POS_OFS(&mrg->obuf); body_offset = mrg->obuf.body_pos - mrg->obuf.start; if (!SRL_MRG_HAVE_OPTION(mrg, SRL_F_TOPLEVEL_KEY_SCALAR)) { mrg->obuf.pos = mrg->obuf.start + mrg->obuf_padding_bytes_offset; DEBUG_ASSERT_BUF_SANE(&mrg->obuf); srl_buf_cat_varint_nocheck(aTHX_ &mrg->obuf, 0, mrg->cnt_of_merged_elements); DEBUG_ASSERT_BUF_SANE(&mrg->obuf); mrg->obuf.pos = mrg->obuf.body_pos + end_offset; DEBUG_ASSERT_BUF_SANE(&mrg->obuf); } if (user_header_src) { char *user_header; STRLEN user_header_len; U8 encoding_flags, protocol_version; IV proto_version_and_encoding_flags_int; UV need_space_for_sereal_and_user_headers = 0; if (mrg->protocol_version < 2) croak("Sereal version does not support headers"); user_header = (char*) SvPV(user_header_src, user_header_len); proto_version_and_encoding_flags_int = srl_validate_header_version(aTHX_ (srl_reader_char_ptr) user_header, user_header_len); if (expect_false(proto_version_and_encoding_flags_int < 1)) croak("Bad Sereal header: Not a valid Sereal document."); protocol_version = (U8) (proto_version_and_encoding_flags_int & SRL_PROTOCOL_VERSION_MASK); if (expect_false(protocol_version != mrg->protocol_version)) croak("The versions of body and header do not match"); encoding_flags = (U8) (proto_version_and_encoding_flags_int & SRL_PROTOCOL_ENCODING_MASK); if (expect_false(encoding_flags != SRL_PROTOCOL_ENCODING_RAW)) croak("The header has unsupported format."); if (expect_false(user_header_len < SRL_MINIMALISTIC_HEADER_SIZE)) croak("Provided user header is too short"); /* here some byte magic goes. The main idea is to fix user_header * inside preallocated space. However, due to varint it becomes quite * tricky */ user_header += SRL_MINIMALISTIC_HEADER_SIZE; user_header_len -= SRL_MINIMALISTIC_HEADER_SIZE; // =srl + 1 byte for version + 1 byte for header need_space_for_sereal_and_user_headers = 4 /* srl magic */ + 1 /* byte for version */ + 1 /* user_header bit field */ + srl_varint_length(aTHX_ user_header_len + 1) /* user_header_len in varint representation, add one because of bit field */ + user_header_len; if (SRL_PREALLOCATE_FOR_USER_HEADER < need_space_for_sereal_and_user_headers) { croak("User header excided SRL_PREALLOCATE_FOR_USER_HEADER. Need to reallocate memory but too lazy to implement this"); // TODO } // move position to where Sereal and user headers should start with */ srl_start_offset = SRL_PREALLOCATE_FOR_USER_HEADER - need_space_for_sereal_and_user_headers; mrg->obuf.pos = mrg->obuf.start + srl_start_offset; srl_fill_header(aTHX_ mrg, user_header, user_header_len); DEBUG_ASSERT_BUF_SANE(&mrg->obuf); if (expect_false(body_offset != (UV) (mrg->obuf.pos - mrg->obuf.start - 1))) { croak("Bizare! Body pointer has different offset after writing Sereal header! Current offset=%"UVuf", expected=%"UVuf, (UV) (mrg->obuf.pos - mrg->obuf.start), body_offset); } mrg->obuf.pos += end_offset; } else if (mrg->protocol_version > 1) { assert(SRL_PREALLOCATE_FOR_USER_HEADER > SRL_MINIMALISTIC_HEADER_SIZE); // move position to where Sereal and user headers should start with */ srl_start_offset = SRL_PREALLOCATE_FOR_USER_HEADER - SRL_MINIMALISTIC_HEADER_SIZE; mrg->obuf.pos = mrg->obuf.start + srl_start_offset; srl_fill_header(aTHX_ mrg, NULL, 0); DEBUG_ASSERT_BUF_SANE(&mrg->obuf); if (expect_false(body_offset != (UV) (mrg->obuf.pos - mrg->obuf.start - 1))) { croak("Bizare! Body pointer has different offset after writing Sereal header!"); } mrg->obuf.pos += end_offset; } DEBUG_ASSERT_BUF_SANE(&mrg->obuf); if (SRL_MRG_HAVE_OPTION(mrg, SRL_F_COMPRESS_SNAPPY_INCREMENTAL)) { srl_compress_body(aTHX_ &mrg->obuf, body_offset, mrg->flags, 0, &mrg->snappy_workmem); SRL_UPDATE_BODY_POS(&mrg->obuf, mrg->protocol_version); } assert(srl_start_offset <= (UV) BUF_POS_OFS(&mrg->obuf)); DEBUG_ASSERT_BUF_SANE(&mrg->obuf); return newSVpvn((char *) mrg->obuf.start + srl_start_offset, BUF_POS_OFS(&mrg->obuf) - srl_start_offset - 1); }