Beispiel #1
0
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);
}
Beispiel #2
0
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;
  }
}
Beispiel #3
0
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;
  }
}
Beispiel #4
0
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);
}